Merge pull request #114075 from akien-mga/vulkan-sdk-1.4.335.0

Vulkan: Update all components to Vulkan SDK 1.4.335.0
This commit is contained in:
Thaddeus Crews 2026-02-04 11:04:21 -06:00
commit cb04441dad
No known key found for this signature in database
GPG key ID: 8C6E5FEB5FC03CCC
174 changed files with 227554 additions and 110637 deletions

View file

@ -579,6 +579,11 @@ Comment: SPIRV-Cross
Copyright: 2015-2021, Arm Limited
License: Apache-2.0 or Expat
Files: thirdparty/spirv-headers/*
Comment: SPIRV-Headers
Copyright: 2015-2024, The Khronos Group Inc.
License: Expat
Files: thirdparty/spirv-reflect/*
Comment: SPIRV-Reflect
Copyright: 2017-2022, Google Inc.
@ -613,19 +618,19 @@ License: BSD-3-clause
Files: thirdparty/volk/*
Comment: volk
Copyright: 2018-2024, Arseny Kapoulkine
Copyright: 2018-2025, Arseny Kapoulkine
License: Expat
Files: thirdparty/vulkan/*
Comment: Vulkan Headers
Copyright: 2014-2024, The Khronos Group Inc.
2014-2024, Valve Corporation
2014-2024, LunarG, Inc.
Copyright: 2015-2025, The Khronos Group Inc.
2015-2025, Valve Corporation
2015-2025, LunarG, Inc.
License: Apache-2.0
Files: thirdparty/vulkan/vk_mem_alloc.h
Comment: Vulkan Memory Allocator
Copyright: 2017-2024, Advanced Micro Devices, Inc.
Copyright: 2017-2025, Advanced Micro Devices, Inc.
License: Expat
Files: thirdparty/wayland/*

View file

@ -19,6 +19,7 @@ thirdparty_sources = [
"spirv_reflect.cpp",
"spirv_glsl.cpp",
"spirv_cross_parsed_ir.cpp",
"spirv_cross_util.cpp",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]

View file

@ -31,6 +31,10 @@ elif env["platform"] == "windows":
env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_WIN32_KHR"])
# Build Vulkan memory allocator and volk
# We don't use it for now, and it depends on Windows APIs.
env.AppendUnique(CPPDEFINES=["VMA_EXTERNAL_MEMORY_WIN32=0"])
env_thirdparty_vma = env.Clone()
env_thirdparty_vma.disable_warnings()
thirdparty_sources_vma = [thirdparty_dir + "/vk_mem_alloc.cpp"]

View file

@ -52,7 +52,6 @@ if env["builtin_glslang"]:
"SPIRV/Logger.cpp",
"SPIRV/SpvBuilder.cpp",
"SPIRV/SpvPostProcess.cpp",
"SPIRV/SPVRemapper.cpp",
"SPIRV/SpvTools.cpp",
]

View file

@ -1249,7 +1249,6 @@ void CopyEffects::octmap_filter(RID p_source_octmap, const Vector<RID> &p_dest_o
OctmapFilterPushConstant push_constant;
push_constant.border_size[0] = p_border_size;
push_constant.border_size[1] = 1.0f - p_border_size * 2.0f;
push_constant.size = 320;
Vector<RD::Uniform> uniforms;
for (int i = 0; i < p_dest_octmap.size(); i++) {

View file

@ -237,7 +237,7 @@ private:
struct CopyToOctmapPushConstant {
float border_size;
float pad[3];
uint32_t pad[3];
};
struct CopyToOctmap {
@ -282,8 +282,8 @@ private:
struct OctmapFilterPushConstant {
float border_size[2];
uint32_t size;
uint32_t pad;
uint32_t pad1;
uint32_t pad2;
};
struct OctmapFilterRasterPushConstant {

View file

@ -71,7 +71,7 @@ private:
float reprojection_matrix[16];
float resolution[2];
uint32_t force_derive_from_depth;
float pad;
uint32_t pad;
};
struct {

View file

@ -65,7 +65,7 @@ private:
float upscaled_height;
float sharpness;
int pass;
int _unused0, _unused1;
int pad[2];
};
FsrUpscaleShaderRD fsr_shader;

View file

@ -27,6 +27,9 @@ layout(set = 0, binding = 0) uniform samplerCube source_cube;
layout(push_constant, std430) uniform Params {
float border_size;
uint pad1;
uint pad2;
uint pad3;
}
params;

View file

@ -60,6 +60,8 @@ layout(push_constant, std430) uniform Params {
float upscaled_height;
float sharpness;
int pass;
int pad1;
int pad2;
}
params;

View file

@ -30,7 +30,8 @@ layout(location = 0) out vec4 frag_color;
layout(push_constant, std430) uniform Params {
highp mat4 reprojection_matrix;
vec2 resolution;
bool force_derive_from_depth;
uint force_derive_from_depth;
uint pad;
}
params;
@ -55,7 +56,7 @@ void main() {
vec2 cell_pos_pixel = floor(pos_pixel / cell_size) * cell_size + (cell_size * 0.5f);
vec2 cell_pos_uv = cell_pos_pixel / params.resolution;
vec2 cell_pos_velocity = textureLod(source_velocity, cell_pos_uv, 0.0f).xy;
bool derive_velocity = params.force_derive_from_depth || all(lessThanEqual(cell_pos_velocity, vec2(-1.0f, -1.0f)));
bool derive_velocity = bool(params.force_derive_from_depth) || all(lessThanEqual(cell_pos_velocity, vec2(-1.0f, -1.0f)));
if (derive_velocity) {
float depth = textureLod(source_depth, cell_pos_uv, 0.0f).x;
cell_pos_velocity = derive_motion_vector(cell_pos_uv, depth, params.reprojection_matrix);

View file

@ -37,7 +37,7 @@ layout(OCTMAP_FORMAT, set = 1, binding = 0) uniform restrict writeonly image2D d
layout(push_constant, std430) uniform Params {
float border_size;
uint size;
uint pad;
uint pad1;
uint pad2;
}
params;

View file

@ -28,7 +28,10 @@
#include "../oct_inc.glsl"
layout(push_constant, std430) uniform Params {
float border_size;
uint size;
uint pad1;
uint pad2;
}
params;
@ -64,7 +67,10 @@ void main() {
#include "../oct_inc.glsl"
layout(push_constant, std430) uniform Params {
float border_size;
uint size;
uint pad1;
uint pad2;
}
params;

View file

@ -29,6 +29,9 @@ layout(push_constant, std430) uniform Params {
float depth_tolerance;
bool orthogonal;
int view_index;
int pad1;
int pad2;
int pad3;
}
params;

View file

@ -13,6 +13,7 @@ layout(rgba8, set = 0, binding = 3) uniform restrict writeonly image2D dest_norm
layout(push_constant, std430) uniform Params {
ivec2 screen_size;
ivec2 pad;
}
params;

View file

@ -12,6 +12,7 @@ layout(set = 0, binding = 1) uniform restrict writeonly image2D dest;
layout(push_constant, std430) uniform Params {
ivec2 screen_size;
uint mip_level;
int pad;
}
params;

View file

@ -11,6 +11,7 @@ layout(r32f, set = 0, binding = 1) uniform restrict writeonly image2D dest;
layout(push_constant, std430) uniform Params {
ivec2 screen_size;
ivec2 pad;
}
params;

View file

@ -16,6 +16,7 @@ layout(rgba16f, set = 0, binding = 6) uniform restrict writeonly image2D output_
layout(push_constant, std430) uniform Params {
ivec2 screen_size;
ivec2 pad;
}
params;

View file

@ -492,22 +492,31 @@ Error RenderingShaderContainer::reflect_spirv(const String &p_shader_name, Span<
SpvReflectSpecializationConstant *spc = spec_constants[j];
sconst.set_spv_reflect(stage, spc);
if (spc->default_value_size != 4) {
ERR_FAIL_V_MSG(FAILED, vformat("Reflection of SPIR-V shader stage '%s' failed because the specialization constant #%d's default value is not 4 bytes long (%d) and is currently not supported.", RDC::SHADER_STAGE_NAMES[p_spirv[i].shader_stage], spc->constant_id, spc->default_value_size));
}
sconst.constant_id = spc->constant_id;
sconst.int_value = 0; // Clear previous value JIC.
switch (spc->constant_type) {
case SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL: {
switch (spc->type_description->op) {
case SpvOpTypeBool:
sconst.type = RDC::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
sconst.bool_value = spc->default_value.int_bool_value != 0;
} break;
case SPV_REFLECT_SPECIALIZATION_CONSTANT_INT: {
sconst.bool_value = *(uint32_t *)(spc->default_value);
break;
case SpvOpTypeInt:
sconst.type = RDC::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
sconst.int_value = spc->default_value.int_bool_value;
} break;
case SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT: {
sconst.int_value = *(uint32_t *)(spc->default_value);
break;
case SpvOpTypeFloat:
sconst.type = RDC::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT;
sconst.float_value = spc->default_value.float_value;
} break;
sconst.float_value = *(float *)(spc->default_value);
break;
default:
ERR_FAIL_V_MSG(FAILED, vformat("Reflection of SPIR-V shader stage '%s' failed because the specialization constant #%d does not use a known operation (%d).", RDC::SHADER_STAGE_NAMES[p_spirv[i].shader_stage], spc->constant_id, spc->type_description->op));
break;
}
sconst.stages.set_flag(stage_flag);
for (uint32_t k = 0; k < reflection.specialization_constants.size(); k++) {

33
thirdparty/README.md vendored
View file

@ -413,7 +413,7 @@ Patches:
## glslang
- Upstream: https://github.com/KhronosGroup/glslang
- Version: vulkan-sdk-1.3.283.0 (e8dd0b6903b34f1879520b444634c75ea2deedf5, 2024)
- Version: vulkan-sdk-1.4.335.0 (b5782e52ee2f7b3e40bb9c80d15b47016e008bc9, 2025)
- License: glslang
Version should be kept in sync with the one of the used Vulkan SDK (see `vulkan`
@ -424,6 +424,8 @@ Files extracted from upstream source:
- `glslang/` folder (except the `glslang/HLSL` and `glslang/ExtensionHeaders`
subfolders), `SPIRV/` folder
* Remove C interface code: `CInterface/` folders, files matching `"*_c[_\.]*"`
* Remove `glslang/stub.cpp`
* Remove `SPIRV/spirv.hpp11` (should use copy from `thirdparty/spirv-headers`)
- Run `cmake . && make` and copy generated `include/glslang/build_info.h`
to `glslang/build_info.h`
- `LICENSE.txt`
@ -432,7 +434,6 @@ Files extracted from upstream source:
Patches:
- `0001-apple-disable-absolute-paths.patch` ([GH-92010](https://github.com/godotengine/godot/pull/92010))
- `0002-gcc15-include-fix.patch` ([GH-102022](https://github.com/godotengine/godot/pull/102022))
## graphite
@ -998,12 +999,12 @@ Patches:
## spirv-cross
- Upstream: https://github.com/KhronosGroup/SPIRV-Cross
- Version: git (d7440cbc6c50332600fdf21c45e6a5df0b07e54c, 2025)
- Version: git (fb0c1a307cca4b4a9d891837bf4c44d17fe2d324, 2025)
- License: Apache 2.0
Files extracted from upstream source:
- All `.cpp`, `.hpp` and `.h` files, minus `main.cpp`, `spirv_cross_c.*`, `spirv_hlsl.*`, `spirv_cpp.*`
- All `.cpp`, `.hpp` and `.h` files, minus `main.cpp`, `spirv.h*`, `spirv_cross_c.*`, `spirv_hlsl.*`, `spirv_cpp.*`
- `include/` folder
- `LICENSE` and `LICENSES/` folder, minus `CC-BY-4.0.txt`
@ -1014,17 +1015,19 @@ to generate Metal source from Vulkan SPIR-V.
## spirv-headers
- Upstream: https://github.com/KhronosGroup/SPIRV-Headers
- Version: vulkan-sdk-1.4.328.1 (01e0577914a75a2569c846778c2f93aa8e6feddd, 2025)
- Version: vulkan-sdk-1.4.335.0 (b824a462d4256d720bebb40e78b9eb8f78bbb305, 2025)
- License: MIT
Files extracted from upstream source:
- `include/spirv/unified1` folder with only `spirv.h` and `spirv.hpp`
- `LICENSE`
- `include/spirv/unified1/spirv.{h,hpp,hpp11}` with the same folder structure
- `LICENSE` (edited to keep only relevant license)
## spirv-reflect
- Upstream: https://github.com/KhronosGroup/SPIRV-Reflect
- Version: vulkan-sdk-1.3.283.0 (ee5b57fba6a986381f998567761bbc064428e645, 2024)
- Version: vulkan-sdk-1.4.335.0 (ef913b3ab3da1becca3cf46b15a10667c67bebe5, 2025)
- License: Apache 2.0
Version should be kept in sync with the one of the used Vulkan SDK (see `vulkan`
@ -1033,14 +1036,12 @@ section).
Files extracted from upstream source:
- `spirv_reflect.h`, `spirv_reflect.c`
- `include/` folder
- `LICENSE`
Patches:
- `0001-specialization-constants.patch` ([GH-50325](https://github.com/godotengine/godot/pull/50325))
- `0002-zero-size-for-sc-sized-arrays.patch` ([GH-94985](https://github.com/godotengine/godot/pull/94985))
- `0003-spirv-headers.patch` ([GH-111452](https://github.com/godotengine/godot/pull/111452))
- `0001-zero-size-for-sc-sized-arrays.patch` ([GH-94985](https://github.com/godotengine/godot/pull/94985))
- `0002-spirv-headers.patch` ([GH-111452](https://github.com/godotengine/godot/pull/111452))
## swappy-frame-pacing
@ -1125,7 +1126,7 @@ Patches:
## volk
- Upstream: https://github.com/zeux/volk
- Version: vulkan-sdk-1.3.283.0 (3a8068a57417940cf2bf9d837a7bb60d015ca2f1, 2024)
- Version: vulkan-sdk-1.4.335.0 (4f3bcee79618a9abe79f4c717c50379197c77512, 2025)
- License: MIT
Version should be kept in sync with the one of the used Vulkan SDK (see `vulkan`
@ -1140,7 +1141,7 @@ Files extracted from upstream source:
## vulkan
- Upstream: https://github.com/KhronosGroup/Vulkan-Headers
- Version: vulkan-sdk-1.3.283.0 (eaa319dade959cb61ed2229c8ea42e307cc8f8b3, 2024)
- Version: vulkan-sdk-1.4.335.0 (2fa203425eb4af9dfc6b03f97ef72b0b5bcb8350, 2025)
- License: Apache 2.0
Unless there is a specific reason to package a more recent version, please stick
@ -1149,6 +1150,8 @@ to tagged SDK releases. All Vulkan libraries and headers should be kept in sync
- Update Vulkan SDK components to the matching tag (see "vulkan")
- Update volk (see "volk")
- Update glslang (see "glslang")
- Update spirv-headers (see "spriv-headers")
- Update spirv-cross (see "spirv-cross")
- Update spirv-reflect (see "spirv-reflect")
Files extracted from upstream source:
@ -1160,7 +1163,7 @@ Files extracted from upstream source:
SDK release: https://github.com/KhronosGroup/Vulkan-Utility-Libraries/blob/main/include/vulkan/vk_enum_string_helper.h
`vk_mem_alloc.h` is taken from https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
Version: 3.1.0 (009ecd192c1289c7529bff248a16cfe896254816, 2024)
Version: 3.3.0 (1d8f600fd424278486eade7ed3e877c99f0846b1, 2025)
`vk_mem_alloc.cpp` is a Godot file and should be preserved on updates.
Patches:

View file

@ -13,9 +13,6 @@ Other parts, outside of glslang proper, include:
- update_glslang_sources.py, which is not part of the project proper and does
not need to be used.
- the SPIR-V "remapper", which is optional, but has the same license as
glslang proper
- Google tests and SPIR-V tools, and anything in the external subdirectory
are external and optional; see them for their respective licenses.

View file

@ -1,5 +1,5 @@
/*
** Copyright (c) 2022 ARM Limited
** Copyright (c) 2022, 2025 ARM Limited
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and/or associated documentation files (the "Materials"),
@ -28,8 +28,10 @@
#define GLSLextARM_H
static const int GLSLextARMVersion = 100;
static const int GLSLextARMRevision = 1;
static const int GLSLextARMRevision = 2;
static const char * const E_SPV_ARM_core_builtins = "SPV_ARM_core_builtins";
static const char* const E_SPV_ARM_core_builtins = "SPV_ARM_core_builtins";
static const char* const E_SPV_ARM_cooperative_matrix_layouts = "SPV_ARM_cooperative_matrix_layouts";
static const char* const E_SPV_ARM_tensors = "SPV_ARM_tensors";
#endif // #ifndef GLSLextARM_H

View file

@ -41,5 +41,8 @@ static const char* const E_SPV_EXT_shader_atomic_float_min_max = "SPV_EXT_shader
static const char* const E_SPV_EXT_shader_image_int64 = "SPV_EXT_shader_image_int64";
static const char* const E_SPV_EXT_shader_tile_image = "SPV_EXT_shader_tile_image";
static const char* const E_SPV_EXT_mesh_shader = "SPV_EXT_mesh_shader";
static const char* const E_SPV_EXT_float8 = "SPV_EXT_float8";
static const char* const E_SPV_EXT_shader_64bit_indexing = "SPV_EXT_shader_64bit_indexing";
static const char* const E_SPV_EXT_shader_invocation_reorder = "SPV_EXT_shader_invocation_reorder";
#endif // #ifndef GLSLextEXT_H

View file

@ -61,5 +61,10 @@ static const char* const E_SPV_KHR_cooperative_matrix = "SPV_KHR_coope
static const char* const E_SPV_KHR_maximal_reconvergence = "SPV_KHR_maximal_reconvergence";
static const char* const E_SPV_KHR_subgroup_rotate = "SPV_KHR_subgroup_rotate";
static const char* const E_SPV_KHR_expect_assume = "SPV_KHR_expect_assume";
static const char* const E_SPV_EXT_replicated_composites = "SPV_EXT_replicated_composites";
static const char* const E_SPV_KHR_relaxed_extended_instruction = "SPV_KHR_relaxed_extended_instruction";
static const char* const E_SPV_KHR_integer_dot_product = "SPV_KHR_integer_dot_product";
static const char* const E_SPV_NV_cooperative_vector = "SPV_NV_cooperative_vector";
static const char* const E_SPV_KHR_bfloat16 = "SPV_KHR_bfloat16";
#endif // #ifndef GLSLextKHR_H

View file

@ -27,10 +27,10 @@
#ifndef GLSLextNV_H
#define GLSLextNV_H
enum BuiltIn;
enum Decoration;
enum Op;
enum Capability;
enum class BuiltIn : unsigned;
enum class Decoration : unsigned;
enum class Op : unsigned;
enum class Capability : unsigned;
static const int GLSLextNVVersion = 100;
static const int GLSLextNVRevision = 11;
@ -90,4 +90,15 @@ const char* const E_SPV_NV_displacement_micromap = "SPV_NV_displacement_micromap
//SPV_NV_shader_atomic_fp16_vector
const char* const E_SPV_NV_shader_atomic_fp16_vector = "SPV_NV_shader_atomic_fp16_vector";
//SPV_NV_tensor_addressing
const char* const E_SPV_NV_tensor_addressing = "SPV_NV_tensor_addressing";
//SPV_NV_cooperative_matrix2
const char* const E_SPV_NV_cooperative_matrix2 = "SPV_NV_cooperative_matrix2";
//SPV_NV_cluster_acceleration_structure
const char* const E_SPV_NV_cluster_acceleration_structure = "SPV_NV_cluster_acceleration_structure";
//SPV_NV_linear_swept_spheres
const char* const E_SPV_NV_linear_swept_spheres = "SPV_NV_linear_swept_spheres";
#endif // #ifndef GLSLextNV_H

View file

@ -27,10 +27,10 @@
#ifndef GLSLextQCOM_H
#define GLSLextQCOM_H
enum BuiltIn;
enum Decoration;
enum Op;
enum Capability;
enum class BuiltIn : unsigned;
enum class Decoration : unsigned;
enum class Op : unsigned;
enum class Capability : unsigned;
static const int GLSLextQCOMVersion = 100;
static const int GLSLextQCOMRevision = 1;
@ -39,5 +39,10 @@ static const int GLSLextQCOMRevision = 1;
const char* const E_SPV_QCOM_image_processing = "SPV_QCOM_image_processing";
//SPV_QCOM_image_processing2
const char* const E_SPV_QCOM_image_processing2 = "SPV_QCOM_image_processing2";
//SPV_QCOM_cooperative_matrix_conversion
const char* const E_SPV_QCOM_cooperative_matrix_conversion = "SPV_QCOM_cooperative_matrix_conversion";
//SPV_QCOM_tile_shading
const char* const E_SPV_QCOM_tile_shading = "SPV_QCOM_tile_shading";
#endif // #ifndef GLSLextQCOM_H

File diff suppressed because it is too large Load diff

View file

@ -39,6 +39,7 @@
#include <vector>
#include "Logger.h"
#include "glslang/Include/visibility.h"
namespace glslang {
class TIntermediate;
@ -53,15 +54,16 @@ struct SpvOptions {
bool emitNonSemanticShaderDebugInfo {false};
bool emitNonSemanticShaderDebugSource{ false };
bool compileOnly{false};
bool optimizerAllowExpandedIDBound{false};
};
void GetSpirvVersion(std::string&);
int GetSpirvGeneratorVersion();
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
SpvOptions* options = nullptr);
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
spv::SpvBuildLogger* logger, SpvOptions* options = nullptr);
bool OutputSpvBin(const std::vector<unsigned int>& spirv, const char* baseName);
bool OutputSpvHex(const std::vector<unsigned int>& spirv, const char* baseName, const char* varName);
GLSLANG_EXPORT void GetSpirvVersion(std::string&);
GLSLANG_EXPORT int GetSpirvGeneratorVersion();
GLSLANG_EXPORT void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
SpvOptions* options = nullptr);
GLSLANG_EXPORT void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
spv::SpvBuildLogger* logger, SpvOptions* options = nullptr);
GLSLANG_EXPORT bool OutputSpvBin(const std::vector<unsigned int>& spirv, const char* baseName);
GLSLANG_EXPORT bool OutputSpvHex(const std::vector<unsigned int>& spirv, const char* baseName, const char* varName);
}

View file

@ -85,7 +85,7 @@ public:
Id mergeId = mergeInst->getIdOperand(0);
mergeBlock = block->getParent().getParent().getInstruction(mergeId)->getBlock();
delayed_.insert(mergeBlock);
if (mergeInst->getOpCode() == spv::OpLoopMerge) {
if (mergeInst->getOpCode() == spv::Op::OpLoopMerge) {
Id continueId = mergeInst->getIdOperand(1);
continueBlock =
block->getParent().getParent().getInstruction(continueId)->getBlock();

View file

@ -37,12 +37,13 @@
#include <string>
#include <vector>
#include "glslang/Include/visibility.h"
namespace spv {
// A class for holding all SPIR-V build status messages, including
// missing/TBD functionalities, warnings, and errors.
class SpvBuildLogger {
class GLSLANG_EXPORT SpvBuildLogger {
public:
SpvBuildLogger() {}

File diff suppressed because it is too large Load diff

View file

@ -1,284 +0,0 @@
//
// Copyright (C) 2015 LunarG, Inc.
//
// 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.
//
#ifndef SPIRVREMAPPER_H
#define SPIRVREMAPPER_H
#include <string>
#include <vector>
#include <cstdlib>
#include <exception>
namespace spv {
class spirvbin_base_t
{
public:
enum Options {
NONE = 0,
STRIP = (1<<0),
MAP_TYPES = (1<<1),
MAP_NAMES = (1<<2),
MAP_FUNCS = (1<<3),
DCE_FUNCS = (1<<4),
DCE_VARS = (1<<5),
DCE_TYPES = (1<<6),
OPT_LOADSTORE = (1<<7),
OPT_FWD_LS = (1<<8), // EXPERIMENTAL: PRODUCES INVALID SCHEMA-0 SPIRV
MAP_ALL = (MAP_TYPES | MAP_NAMES | MAP_FUNCS),
DCE_ALL = (DCE_FUNCS | DCE_VARS | DCE_TYPES),
OPT_ALL = (OPT_LOADSTORE),
ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL),
DO_EVERYTHING = (STRIP | ALL_BUT_STRIP)
};
};
} // namespace SPV
#include <functional>
#include <cstdint>
#include <unordered_map>
#include <unordered_set>
#include <map>
#include <set>
#include <cassert>
#include "spirv.hpp"
namespace spv {
const Id NoResult = 0;
// class to hold SPIR-V binary data for remapping, DCE, and debug stripping
class spirvbin_t : public spirvbin_base_t
{
public:
spirvbin_t(int verbose = 0) : entryPoint(spv::NoResult), largestNewId(0), verbose(verbose), errorLatch(false)
{ }
virtual ~spirvbin_t() { }
// remap on an existing binary in memory
void remap(std::vector<std::uint32_t>& spv, const std::vector<std::string>& whiteListStrings,
std::uint32_t opts = DO_EVERYTHING);
// remap on an existing binary in memory - legacy interface without white list
void remap(std::vector<std::uint32_t>& spv, std::uint32_t opts = DO_EVERYTHING);
// Type for error/log handler functions
typedef std::function<void(const std::string&)> errorfn_t;
typedef std::function<void(const std::string&)> logfn_t;
// Register error/log handling functions (can be lambda fn / functor / etc)
static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; }
static void registerLogHandler(logfn_t handler) { logHandler = handler; }
protected:
// This can be overridden to provide other message behavior if needed
virtual void msg(int minVerbosity, int indent, const std::string& txt) const;
private:
// Local to global, or global to local ID map
typedef std::unordered_map<spv::Id, spv::Id> idmap_t;
typedef std::unordered_set<spv::Id> idset_t;
typedef std::unordered_map<spv::Id, int> blockmap_t;
void remap(std::uint32_t opts = DO_EVERYTHING);
// Map of names to IDs
typedef std::unordered_map<std::string, spv::Id> namemap_t;
typedef std::uint32_t spirword_t;
typedef std::pair<unsigned, unsigned> range_t;
typedef std::function<void(spv::Id&)> idfn_t;
typedef std::function<bool(spv::Op, unsigned start)> instfn_t;
// Special Values for ID map:
static const spv::Id unmapped; // unchanged from default value
static const spv::Id unused; // unused ID
static const int header_size; // SPIR header = 5 words
class id_iterator_t;
// For mapping type entries between different shaders
typedef std::vector<spirword_t> typeentry_t;
typedef std::map<spv::Id, typeentry_t> globaltypes_t;
// A set that preserves position order, and a reverse map
typedef std::set<int> posmap_t;
typedef std::unordered_map<spv::Id, int> posmap_rev_t;
// Maps and ID to the size of its base type, if known.
typedef std::unordered_map<spv::Id, unsigned> typesize_map_t;
// handle error
void error(const std::string& txt) const { errorLatch = true; errorHandler(txt); }
bool isConstOp(spv::Op opCode) const;
bool isTypeOp(spv::Op opCode) const;
bool isStripOp(spv::Op opCode) const;
bool isFlowCtrl(spv::Op opCode) const;
range_t literalRange(spv::Op opCode) const;
range_t typeRange(spv::Op opCode) const;
range_t constRange(spv::Op opCode) const;
unsigned typeSizeInWords(spv::Id id) const;
unsigned idTypeSizeInWords(spv::Id id) const;
bool isStripOp(spv::Op opCode, unsigned start) const;
spv::Id& asId(unsigned word) { return spv[word]; }
const spv::Id& asId(unsigned word) const { return spv[word]; }
spv::Op asOpCode(unsigned word) const { return opOpCode(spv[word]); }
std::uint32_t asOpCodeHash(unsigned word);
spv::Decoration asDecoration(unsigned word) const { return spv::Decoration(spv[word]); }
unsigned asWordCount(unsigned word) const { return opWordCount(spv[word]); }
spv::Id asTypeConstId(unsigned word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }
unsigned idPos(spv::Id id) const;
static unsigned opWordCount(spirword_t data) { return data >> spv::WordCountShift; }
static spv::Op opOpCode(spirword_t data) { return spv::Op(data & spv::OpCodeMask); }
// Header access & set methods
spirword_t magic() const { return spv[0]; } // return magic number
spirword_t bound() const { return spv[3]; } // return Id bound from header
spirword_t bound(spirword_t b) { return spv[3] = b; }
spirword_t genmagic() const { return spv[2]; } // generator magic
spirword_t genmagic(spirword_t m) { return spv[2] = m; }
spirword_t schemaNum() const { return spv[4]; } // schema number from header
// Mapping fns: get
spv::Id localId(spv::Id id) const { return idMapL[id]; }
// Mapping fns: set
inline spv::Id localId(spv::Id id, spv::Id newId);
void countIds(spv::Id id);
// Return next unused new local ID.
// NOTE: boost::dynamic_bitset would be more efficient due to find_next(),
// which std::vector<bool> doens't have.
inline spv::Id nextUnusedId(spv::Id id);
void buildLocalMaps();
std::string literalString(unsigned word) const; // Return literal as a std::string
int literalStringWords(const std::string& str) const { return (int(str.size())+4)/4; }
bool isNewIdMapped(spv::Id newId) const { return isMapped(newId); }
bool isOldIdUnmapped(spv::Id oldId) const { return localId(oldId) == unmapped; }
bool isOldIdUnused(spv::Id oldId) const { return localId(oldId) == unused; }
bool isOldIdMapped(spv::Id oldId) const { return !isOldIdUnused(oldId) && !isOldIdUnmapped(oldId); }
bool isFunction(spv::Id oldId) const { return fnPos.find(oldId) != fnPos.end(); }
// bool matchType(const globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const;
// spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const;
std::uint32_t hashType(unsigned typeStart) const;
spirvbin_t& process(instfn_t, idfn_t, unsigned begin = 0, unsigned end = 0);
int processInstruction(unsigned word, instfn_t, idfn_t);
void validate() const;
void mapTypeConst();
void mapFnBodies();
void optLoadStore();
void dceFuncs();
void dceVars();
void dceTypes();
void mapNames();
void foldIds(); // fold IDs to smallest space
void forwardLoadStores(); // load store forwarding (EXPERIMENTAL)
void offsetIds(); // create relative offset IDs
void applyMap(); // remap per local name map
void mapRemainder(); // map any IDs we haven't touched yet
void stripDebug(); // strip all debug info
void stripDeadRefs(); // strips debug info for now-dead references after DCE
void strip(); // remove debug symbols
std::vector<spirword_t> spv; // SPIR words
std::vector<std::string> stripWhiteList;
namemap_t nameMap; // ID names from OpName
// Since we want to also do binary ops, we can't use std::vector<bool>. we could use
// boost::dynamic_bitset, but we're trying to avoid a boost dependency.
typedef std::uint64_t bits_t;
std::vector<bits_t> mapped; // which new IDs have been mapped
static const int mBits = sizeof(bits_t) * 4;
bool isMapped(spv::Id id) const { return id < maxMappedId() && ((mapped[id/mBits] & (1LL<<(id%mBits))) != 0); }
void setMapped(spv::Id id) { resizeMapped(id); mapped[id/mBits] |= (1LL<<(id%mBits)); }
void resizeMapped(spv::Id id) { if (id >= maxMappedId()) mapped.resize(id/mBits+1, 0); }
size_t maxMappedId() const { return mapped.size() * mBits; }
// Add a strip range for a given instruction starting at 'start'
// Note: avoiding brace initializers to please older versions os MSVC.
void stripInst(unsigned start) { stripRange.push_back(range_t(start, start + asWordCount(start))); }
// Function start and end. use unordered_map because we'll have
// many fewer functions than IDs.
std::unordered_map<spv::Id, range_t> fnPos;
// Which functions are called, anywhere in the module, with a call count
std::unordered_map<spv::Id, int> fnCalls;
posmap_t typeConstPos; // word positions that define types & consts (ordered)
posmap_rev_t idPosR; // reverse map from IDs to positions
typesize_map_t idTypeSizeMap; // maps each ID to its type size, if known.
std::vector<spv::Id> idMapL; // ID {M}ap from {L}ocal to {G}lobal IDs
spv::Id entryPoint; // module entry point
spv::Id largestNewId; // biggest new ID we have mapped anything to
// Sections of the binary to strip, given as [begin,end)
std::vector<range_t> stripRange;
// processing options:
std::uint32_t options;
int verbose; // verbosity level
// Error latch: this is set if the error handler is ever executed. It would be better to
// use a try/catch block and throw, but that's not desired for certain environments, so
// this is the alternative.
mutable bool errorLatch;
static errorfn_t errorHandler;
static logfn_t logHandler;
};
} // namespace SPV
#endif // SPIRVREMAPPER_H

File diff suppressed because it is too large Load diff

View file

@ -48,10 +48,14 @@
#define SpvBuilder_H
#include "Logger.h"
#include "spirv.hpp"
#define SPV_ENABLE_UTILITY_CODE
#include "spirv.hpp11"
#include "spvIR.h"
#include "spvUtil.h"
namespace spv {
#include "GLSL.ext.KHR.h"
#include "GLSL.ext.EXT.h"
#include "NonSemanticShaderDebugInfo100.h"
}
@ -63,6 +67,7 @@ namespace spv {
#include <sstream>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <map>
namespace spv {
@ -74,8 +79,17 @@ typedef enum {
Spv_1_3 = (1 << 16) | (3 << 8),
Spv_1_4 = (1 << 16) | (4 << 8),
Spv_1_5 = (1 << 16) | (5 << 8),
Spv_1_6 = (1 << 16) | (6 << 8),
} SpvVersion;
struct StructMemberDebugInfo {
std::string name {};
int line {0};
int column {0};
// Set if the caller knows a better debug type than what is associated with the functional SPIR-V type.
spv::Id debugTypeOverride {0};
};
class Builder {
public:
Builder(unsigned int spvVersion, unsigned int userNumber, SpvBuildLogger* logger);
@ -96,7 +110,7 @@ public:
if (sItr != stringIds.end())
return sItr->second;
spv::Id strId = getUniqueId();
Instruction* fileString = new Instruction(strId, NoType, OpString);
Instruction* fileString = new Instruction(strId, NoType, Op::OpString);
const char* file_c_str = str.c_str();
fileString->addStringOperand(file_c_str);
strings.push_back(std::unique_ptr<Instruction>(fileString));
@ -108,7 +122,7 @@ public:
spv::Id getMainFileId() const { return mainFileId; }
// Initialize the main source file name
void setDebugSourceFile(const std::string& file)
void setDebugMainSourceFile(const std::string& file)
{
if (trackDebugInfo) {
dirtyLineTracker = true;
@ -124,7 +138,7 @@ public:
if (trackDebugInfo) {
dirtyLineTracker = true;
if (line != 0) {
// TODO: This is special handling of some AST nodes having (untracked) line 0.
// TODO: This is special handling of some AST nodes having (untracked) line 0.
// But they should have a valid line number.
currentLine = line;
if (filename) {
@ -192,6 +206,24 @@ public:
return id;
}
// Maps the given OpType Id to a Non-Semantic DebugType Id.
Id getDebugType(Id type) {
if (auto it = debugTypeIdLookup.find(type); it != debugTypeIdLookup.end()) {
return it->second;
}
return NoType;
}
// Maps the given OpFunction Id to a Non-Semantic DebugFunction Id.
Id getDebugFunction(Id func) {
if (auto it = debugFuncIdLookup.find(func); it != debugFuncIdLookup.end()) {
return it->second;
}
return NoResult;
}
// For creating new types (will return old type if the requested one was already made).
Id makeVoidType();
Id makeBoolType();
@ -202,28 +234,28 @@ public:
Id makeIntType(int width) { return makeIntegerType(width, true); }
Id makeUintType(int width) { return makeIntegerType(width, false); }
Id makeFloatType(int width);
Id makeStructType(const std::vector<Id>& members, const char* name, bool const compilerGenerated = true);
Id makeBFloat16Type();
Id makeFloatE5M2Type();
Id makeFloatE4M3Type();
Id makeStructType(const std::vector<Id>& members, const std::vector<spv::StructMemberDebugInfo>& memberDebugInfo,
const char* name, bool const compilerGenerated = true);
Id makeStructResultType(Id type0, Id type1);
Id makeVectorType(Id component, int size);
Id makeMatrixType(Id component, int cols, int rows);
Id makeArrayType(Id element, Id sizeId, int stride); // 0 stride means no stride decoration
Id makeRuntimeArray(Id element);
Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes);
Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
Id makeSamplerType();
Id makeSampledImageType(Id imageType);
Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format, const char* debugNames);
Id makeSamplerType(const char* debugName);
Id makeSampledImageType(Id imageType, const char* debugName);
Id makeCooperativeMatrixTypeKHR(Id component, Id scope, Id rows, Id cols, Id use);
Id makeCooperativeMatrixTypeNV(Id component, Id scope, Id rows, Id cols);
Id makeCooperativeMatrixTypeWithSameShape(Id component, Id otherType);
Id makeCooperativeVectorTypeNV(Id componentType, Id components);
Id makeTensorTypeARM(Id elementType, Id rank);
Id makeGenericType(spv::Op opcode, std::vector<spv::IdImmediate>& operands);
// SPIR-V NonSemantic Shader DebugInfo Instructions
struct DebugTypeLoc {
std::string name {};
int line {0};
int column {0};
};
std::unordered_map<Id, DebugTypeLoc> debugTypeLocs;
Id makeDebugInfoNone();
Id makeBoolDebugType(int const size);
Id makeIntegerDebugType(int const width, bool const hasSign);
@ -232,10 +264,12 @@ public:
Id makeArrayDebugType(Id const baseType, Id const componentCount);
Id makeVectorDebugType(Id const baseType, int const componentCount);
Id makeMatrixDebugType(Id const vectorType, int const vectorCount, bool columnMajor = true);
Id makeMemberDebugType(Id const memberType, DebugTypeLoc const& debugTypeLoc);
Id makeCompositeDebugType(std::vector<Id> const& memberTypes, char const*const name,
NonSemanticShaderDebugInfo100DebugCompositeType const tag, bool const isOpaqueType = false);
Id makeMemberDebugType(Id const memberType, StructMemberDebugInfo const& debugTypeLoc);
Id makeCompositeDebugType(std::vector<Id> const& memberTypes, std::vector<StructMemberDebugInfo> const& memberDebugInfo,
char const* const name, NonSemanticShaderDebugInfo100DebugCompositeType const tag);
Id makeOpaqueDebugType(char const* const name);
Id makePointerDebugType(StorageClass storageClass, Id const baseType);
Id makeForwardPointerDebugType(StorageClass storageClass);
Id makeDebugSource(const Id fileName);
Id makeDebugCompilationUnit();
Id createDebugGlobalVariable(Id const type, char const*const name, Id const variable);
@ -245,11 +279,14 @@ public:
Id makeDebugValue(Id const debugLocalVariable, Id const value);
Id makeDebugFunctionType(Id returnType, const std::vector<Id>& paramTypes);
Id makeDebugFunction(Function* function, Id nameId, Id funcTypeId);
Id makeDebugLexicalBlock(uint32_t line);
Id makeDebugLexicalBlock(uint32_t line, uint32_t column);
std::string unmangleFunctionName(std::string const& name) const;
void setupDebugFunctionEntry(Function* function, const char* name, int line,
const std::vector<Id>& paramTypes,
const std::vector<char const*>& paramNames);
// Initialize non-semantic debug information for a function, including those of:
// - The function definition
// - The function parameters
void setupFunctionDebugInfo(Function* function, const char* name, const std::vector<Id>& paramTypes,
const std::vector<char const*>& paramNames);
// accelerationStructureNV type
Id makeAccelerationStructureType();
@ -257,6 +294,8 @@ public:
Id makeRayQueryType();
// hitObjectNV type
Id makeHitObjectNVType();
// hitObjectEXT type
Id makeHitObjectEXTType();
// For querying about types.
Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
@ -264,9 +303,9 @@ public:
Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
Op getTypeClass(Id typeId) const { return getOpCode(typeId); }
Op getMostBasicTypeClass(Id typeId) const;
int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
int getNumTypeConstituents(Id typeId) const;
int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); }
unsigned int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
unsigned int getNumTypeConstituents(Id typeId) const;
unsigned int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); }
Id getScalarTypeId(Id typeId) const;
Id getContainedTypeId(Id typeId) const;
Id getContainedTypeId(Id typeId, int) const;
@ -275,54 +314,60 @@ public:
{ return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); }
Id getResultingAccessChainType() const;
Id getIdOperand(Id resultId, int idx) { return module.getInstruction(resultId)->getIdOperand(idx); }
Id getCooperativeVectorNumComponents(Id typeId) const { return module.getInstruction(typeId)->getIdOperand(1); }
bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); }
bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); }
bool isVector(Id resultId) const { return isVectorType(getTypeId(resultId)); }
bool isMatrix(Id resultId) const { return isMatrixType(getTypeId(resultId)); }
bool isCooperativeMatrix(Id resultId)const { return isCooperativeMatrixType(getTypeId(resultId)); }
bool isCooperativeVector(Id resultId)const { return isCooperativeVectorType(getTypeId(resultId)); }
bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); }
bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); }
bool isTensorView(Id resultId)const { return isTensorViewType(getTypeId(resultId)); }
bool isBoolType(Id typeId)
{ return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); }
{ return groupedTypes[enumCast(Op::OpTypeBool)].size() > 0 && typeId == groupedTypes[enumCast(Op::OpTypeBool)].back()->getResultId(); }
bool isIntType(Id typeId) const
{ return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) != 0; }
{ return getTypeClass(typeId) == Op::OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) != 0; }
bool isUintType(Id typeId) const
{ return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) == 0; }
bool isFloatType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat; }
bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; }
{ return getTypeClass(typeId) == Op::OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) == 0; }
bool isFloatType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeFloat; }
bool isPointerType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypePointer; }
bool isScalarType(Id typeId) const
{ return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt ||
getTypeClass(typeId) == OpTypeBool; }
bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; }
bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; }
bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; }
bool isArrayType(Id typeId) const { return getTypeClass(typeId) == OpTypeArray; }
{ return getTypeClass(typeId) == Op::OpTypeFloat || getTypeClass(typeId) == Op::OpTypeInt ||
getTypeClass(typeId) == Op::OpTypeBool; }
bool isVectorType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeVector; }
bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeMatrix; }
bool isStructType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeStruct; }
bool isArrayType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeArray; }
bool isCooperativeMatrixType(Id typeId)const
{
return getTypeClass(typeId) == OpTypeCooperativeMatrixKHR || getTypeClass(typeId) == OpTypeCooperativeMatrixNV;
return getTypeClass(typeId) == Op::OpTypeCooperativeMatrixKHR || getTypeClass(typeId) == Op::OpTypeCooperativeMatrixNV;
}
bool isTensorViewType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeTensorViewNV; }
bool isCooperativeVectorType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeCooperativeVectorNV; }
bool isTensorTypeARM(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeTensorARM; }
bool isAggregateType(Id typeId) const
{ return isArrayType(typeId) || isStructType(typeId) || isCooperativeMatrixType(typeId); }
bool isImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeImage; }
bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }
bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; }
bool isImageType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeImage; }
bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeSampler; }
bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeSampledImage; }
bool containsType(Id typeId, Op typeOp, unsigned int width) const;
bool containsPhysicalStorageBufferOrArray(Id typeId) const;
bool isConstantOpCode(Op opcode) const;
bool isSpecConstantOpCode(Op opcode) const;
bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }
bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == Op::OpConstant; }
bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); }
unsigned int getConstantScalar(Id resultId) const
{ return module.getInstruction(resultId)->getImmediateOperand(0); }
StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }
bool isVariableOpCode(Op opcode) const { return opcode == OpVariable; }
bool isVariableOpCode(Op opcode) const { return opcode == Op::OpVariable; }
bool isVariable(Id resultId) const { return isVariableOpCode(getOpCode(resultId)); }
bool isGlobalStorage(Id resultId) const { return getStorageClass(resultId) != StorageClassFunction; }
bool isGlobalStorage(Id resultId) const { return getStorageClass(resultId) != StorageClass::Function; }
bool isGlobalVariable(Id resultId) const { return isVariable(resultId) && isGlobalStorage(resultId); }
// See if a resultId is valid for use as an initializer.
bool isValidInitializer(Id resultId) const { return isConstant(resultId) || isGlobalVariable(resultId); }
@ -330,22 +375,22 @@ public:
int getScalarTypeWidth(Id typeId) const
{
Id scalarTypeId = getScalarTypeId(typeId);
assert(getTypeClass(scalarTypeId) == OpTypeInt || getTypeClass(scalarTypeId) == OpTypeFloat);
assert(getTypeClass(scalarTypeId) == Op::OpTypeInt || getTypeClass(scalarTypeId) == Op::OpTypeFloat);
return module.getInstruction(scalarTypeId)->getImmediateOperand(0);
}
int getTypeNumColumns(Id typeId) const
unsigned int getTypeNumColumns(Id typeId) const
{
assert(isMatrixType(typeId));
return getNumTypeConstituents(typeId);
}
int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
int getTypeNumRows(Id typeId) const
unsigned int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
unsigned int getTypeNumRows(Id typeId) const
{
assert(isMatrixType(typeId));
return getNumTypeComponents(getContainedTypeId(typeId));
}
int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
unsigned int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
Dim getTypeDimensionality(Id typeId) const
{
@ -367,6 +412,8 @@ public:
// For making new constants (will return old constant if the requested one was already made).
Id makeNullConstant(Id typeId);
Id makeBoolConstant(bool b, bool specConstant = false);
Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant);
Id makeInt8Constant(int i, bool specConstant = false)
{ return makeIntConstant(makeIntType(8), (unsigned)i, specConstant); }
Id makeUint8Constant(unsigned u, bool specConstant = false)
@ -379,6 +426,14 @@ public:
{ return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); }
Id makeUintConstant(unsigned u, bool specConstant = false)
{ return makeIntConstant(makeUintType(32), u, specConstant); }
Id makeUintConstant(Scope u, bool specConstant = false)
{ return makeUintConstant((unsigned)u, specConstant); }
Id makeUintConstant(StorageClass u, bool specConstant = false)
{ return makeUintConstant((unsigned)u, specConstant); }
Id makeUintConstant(MemorySemanticsMask u, bool specConstant = false)
{ return makeUintConstant((unsigned)u, specConstant); }
Id makeUintConstant(SourceLanguage u, bool specConstant = false)
{ return makeUintConstant((unsigned)u, specConstant); }
Id makeInt64Constant(long long i, bool specConstant = false)
{ return makeInt64Constant(makeIntType(64), (unsigned long long)i, specConstant); }
Id makeUint64Constant(unsigned long long u, bool specConstant = false)
@ -386,6 +441,9 @@ public:
Id makeFloatConstant(float f, bool specConstant = false);
Id makeDoubleConstant(double d, bool specConstant = false);
Id makeFloat16Constant(float f16, bool specConstant = false);
Id makeBFloat16Constant(float bf16, bool specConstant = false);
Id makeFloatE5M2Constant(float fe5m2, bool specConstant = false);
Id makeFloatE4M3Constant(float fe4m3, bool specConstant = false);
Id makeFpConstant(Id type, double d, bool specConstant = false);
Id importNonSemanticShaderDebugInfoInstructions();
@ -416,8 +474,7 @@ public:
// Also reset current last DebugScope and current source line to unknown
void setBuildPoint(Block* bp) {
buildPoint = bp;
// TODO: Technically, change of build point should set line tracker dirty. But we'll have bad line info for
// branch instructions. Commenting this for now because at least this matches the old behavior.
dirtyLineTracker = true;
dirtyScopeTracker = true;
}
Block* getBuildPoint() const { return buildPoint; }
@ -426,6 +483,11 @@ public:
// Optionally, additional debug info instructions may also be prepended.
void addInstruction(std::unique_ptr<Instruction> inst);
// Append an instruction to the end of the current build point without prepending any debug instructions.
// This is useful for insertion of some debug info instructions themselves or some control flow instructions
// that are attached to its predecessor instruction.
void addInstructionNoDebugInfo(std::unique_ptr<Instruction> inst);
// Make the entry-point function. The returned pointer is only valid
// for the lifetime of this builder.
Function* makeEntryPoint(const char*);
@ -442,7 +504,7 @@ public:
void makeReturn(bool implicit, Id retVal = 0);
// Initialize state and generate instructions for new lexical scope
void enterLexicalBlock(uint32_t line);
void enterLexicalBlock(uint32_t line, uint32_t column);
// Set state and generate instructions to exit current lexical scope
void leaveLexicalBlock();
@ -461,6 +523,10 @@ public:
// such as OpEmitMeshTasksEXT
void makeStatementTerminator(spv::Op opcode, const std::vector<Id>& operands, const char* name);
// Create a global/local constant. Because OpConstant is automatically emitted by getting the constant
// ids, this function only handles debug info.
void createConstVariable(Id type, const char* name, Id constant, bool isGlobal);
// Create a global or function local or IO variable.
Id createVariable(Decoration precision, StorageClass storageClass, Id type, const char* name = nullptr,
Id initializer = NoResult, bool const compilerGenerated = true);
@ -469,19 +535,19 @@ public:
Id createUndefined(Id type);
// Store into an Id and return the l-value
void createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone,
spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
void createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMask::MaskNone,
spv::Scope scope = spv::Scope::Max, unsigned int alignment = 0);
// Load from an Id and return it
Id createLoad(Id lValue, spv::Decoration precision,
spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone,
spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMask::MaskNone,
spv::Scope scope = spv::Scope::Max, unsigned int alignment = 0);
// Create an OpAccessChain instruction
Id createAccessChain(StorageClass, Id base, const std::vector<Id>& offsets);
// Create an OpArrayLength instruction
Id createArrayLength(Id base, unsigned int member);
Id createArrayLength(Id base, unsigned int member, unsigned int bits);
// Create an OpCooperativeMatrixLengthKHR instruction
Id createCooperativeMatrixLengthKHR(Id type);
@ -502,7 +568,7 @@ public:
void createNoResultOp(Op, const std::vector<Id>& operands);
void createNoResultOp(Op, const std::vector<IdImmediate>& operands);
void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);
void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
void createMemoryBarrier(Scope executionScope, MemorySemanticsMask memorySemantics);
Id createUnaryOp(Op, Id typeId, Id operand);
Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
@ -573,6 +639,7 @@ public:
Id coarse;
bool nonprivate;
bool volatil;
bool nontemporal;
};
// Select the correct texture operation based on all inputs, and emit the correct instruction
@ -600,10 +667,15 @@ public:
// matrix constructor
Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
// coopmat conversion
Id createCooperativeMatrixConversion(Id typeId, Id source);
Id createCooperativeMatrixReduce(Op opcode, Id typeId, Id source, unsigned int mask, Id func);
Id createCooperativeMatrixPerElementOp(Id typeId, const std::vector<Id>& operands);
// Helper to use for building nested control flow with if-then-else.
class If {
public:
If(Id condition, unsigned int ctrl, Builder& builder);
If(Id condition, SelectionControlMask ctrl, Builder& builder);
~If() {}
void makeBeginElse();
@ -615,7 +687,7 @@ public:
Builder& builder;
Id condition;
unsigned int control;
SelectionControlMask control;
Function* function;
Block* headerBlock;
Block* thenBlock;
@ -635,11 +707,11 @@ public:
// Returns the right set of basic blocks to start each code segment with, so that the caller's
// recursion stack can hold the memory for it.
//
void makeSwitch(Id condition, unsigned int control, int numSegments, const std::vector<int>& caseValues,
void makeSwitch(Id condition, SelectionControlMask control, int numSegments, const std::vector<int>& caseValues,
const std::vector<int>& valueToSegment, int defaultSegment, std::vector<Block*>& segmentBB);
// Add a branch to the innermost switch's merge block.
void addSwitchBreak();
void addSwitchBreak(bool implicit);
// Move to the next code segment, passing in the return argument in makeSwitch()
void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
@ -736,6 +808,7 @@ public:
unsigned shadercallcoherent : 1;
unsigned nonprivate : 1;
unsigned volatil : 1;
unsigned nontemporal : 1;
unsigned isImage : 1;
unsigned nonUniform : 1;
@ -748,6 +821,7 @@ public:
shadercallcoherent = 0;
nonprivate = 0;
volatil = 0;
nontemporal = 0;
isImage = 0;
nonUniform = 0;
}
@ -761,6 +835,7 @@ public:
shadercallcoherent |= other.shadercallcoherent;
nonprivate |= other.nonprivate;
volatil |= other.volatil;
nontemporal = other.nontemporal;
isImage |= other.isImage;
nonUniform |= other.nonUniform;
return *this;
@ -823,12 +898,12 @@ public:
// use accessChain and swizzle to store value
void accessChainStore(Id rvalue, Decoration nonUniform,
spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone,
spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMask::MaskNone,
spv::Scope scope = spv::Scope::Max, unsigned int alignment = 0);
// use accessChain and swizzle to load an r-value
Id accessChainLoad(Decoration precision, Decoration l_nonUniform, Decoration r_nonUniform, Id ResultType,
spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax,
spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMask::MaskNone, spv::Scope scope = spv::Scope::Max,
unsigned int alignment = 0);
// Return whether or not the access chain can be represented in SPIR-V
@ -856,12 +931,16 @@ public:
void postProcess(Instruction&);
// Hook to visit each non-32-bit sized float/int operation in a block.
void postProcessType(const Instruction&, spv::Id typeId);
// move OpSampledImage instructions to be next to their users.
void postProcessSamplers();
void dump(std::vector<unsigned int>&) const;
void createBranch(Block* block);
// Add a branch to the target block.
// If set implicit, the branch instruction shouldn't have debug source location.
void createBranch(bool implicit, Block* block);
void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control,
void createLoopMerge(Block* mergeBlock, Block* continueBlock, LoopControlMask control,
const std::vector<unsigned int>& operands);
// Sets to generate opcode for specialization constants.
@ -871,25 +950,32 @@ public:
// Check if the builder is generating code for spec constants.
bool isInSpecConstCodeGenMode() { return generatingOpCodeForSpecConst; }
protected:
Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant);
void setUseReplicatedComposites(bool use) { useReplicatedComposites = use; }
private:
// Helper to get size of a scalar (in bytes)
unsigned int postProcessGetLargestScalarSize(const Instruction& type);
protected:
Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value);
Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2);
Id findCompositeConstant(Op typeClass, Id typeId, const std::vector<Id>& comps);
Id findCompositeConstant(Op typeClass, Op opcode, Id typeId, const std::vector<Id>& comps, size_t numMembers);
Id findStructConstant(Id typeId, const std::vector<Id>& comps);
Id collapseAccessChain();
void remapDynamicSwizzle();
void transferAccessChainSwizzle(bool dynamic);
void simplifyAccessChainSwizzle();
void createAndSetNoPredecessorBlock(const char*);
void createSelectionMerge(Block* mergeBlock, unsigned int control);
void createSelectionMerge(Block* mergeBlock, SelectionControlMask control);
void dumpSourceInstructions(std::vector<unsigned int>&) const;
void dumpSourceInstructions(const spv::Id fileId, const std::string& text, std::vector<unsigned int>&) const;
void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const;
template <class Range> void dumpInstructions(std::vector<unsigned int>& out, const Range& instructions) const;
void dumpModuleProcesses(std::vector<unsigned int>&) const;
spv::MemoryAccessMask sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc)
const;
struct DecorationInstructionLessThan {
bool operator()(const std::unique_ptr<Instruction>& lhs, const std::unique_ptr<Instruction>& rhs) const;
};
unsigned int spvVersion; // the version of SPIR-V to emit in the header
SourceLanguage sourceLang;
@ -936,7 +1022,10 @@ public:
Block* buildPoint;
Id uniqueId;
Function* entryPointFunction;
// This tracks the current function being built, or nullptr if not in a function.
Function const* currentFunction { nullptr };
bool generatingOpCodeForSpecConst;
bool useReplicatedComposites { false };
AccessChain accessChain;
// special blocks of instructions for output
@ -945,15 +1034,65 @@ public:
std::vector<std::unique_ptr<Instruction> > entryPoints;
std::vector<std::unique_ptr<Instruction> > executionModes;
std::vector<std::unique_ptr<Instruction> > names;
std::vector<std::unique_ptr<Instruction> > decorations;
std::set<std::unique_ptr<Instruction>, DecorationInstructionLessThan> decorations;
std::vector<std::unique_ptr<Instruction> > constantsTypesGlobals;
std::vector<std::unique_ptr<Instruction> > externals;
std::vector<std::unique_ptr<Function> > functions;
// not output, internally used for quick & dirty canonical (unique) creation
// Key for scalar constants (handles both 32-bit and 64-bit)
struct ScalarConstantKey {
unsigned int typeClass; // OpTypeInt, OpTypeFloat, OpTypeBool
unsigned int opcode; // OpConstant, OpSpecConstant, OpConstantTrue, etc.
Id typeId; // The specific type
unsigned value1; // First operand (or only operand)
unsigned value2; // Second operand (0 for single-operand constants)
bool operator==(const ScalarConstantKey& other) const {
return typeClass == other.typeClass &&
opcode == other.opcode &&
typeId == other.typeId &&
value1 == other.value1 &&
value2 == other.value2;
}
};
struct ScalarConstantKeyHash {
// 64/32 bit mix function from MurmurHash3
inline std::size_t hash_mix(std::size_t h) const {
if constexpr (sizeof(std::size_t) == 8) {
h ^= h >> 33;
h *= UINT64_C(0xff51afd7ed558ccd);
h ^= h >> 33;
h *= UINT64_C(0xc4ceb9fe1a85ec53);
h ^= h >> 33;
return h;
} else {
h ^= h >> 16;
h *= UINT32_C(0x85ebca6b);
h ^= h >> 13;
h *= UINT32_C(0xc2b2ae35);
h ^= h >> 16;
return h;
}
}
// Hash combine from boost
inline std::size_t hash_combine(std::size_t seed, std::size_t v) const {
return hash_mix(seed + 0x9e3779b9 + v);
}
std::size_t operator()(const ScalarConstantKey& k) const {
size_t hash1 = hash_combine(std::hash<unsigned>{}(k.typeClass), std::hash<unsigned>{}(k.opcode));
size_t hash2 = hash_combine(std::hash<Id>{}(k.value1), std::hash<unsigned>{}(k.value2));
size_t hash3 = hash_combine(hash1, hash2);
return hash_combine(hash3, std::hash<unsigned>{}(k.typeId));
}
};
// map type opcodes to constant inst.
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedConstants;
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedCompositeConstants;
// map struct-id to constant instructions
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedStructConstants;
// map type opcodes to type instructions
@ -962,6 +1101,12 @@ public:
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedDebugTypes;
// list of OpConstantNull instructions
std::vector<Instruction*> nullConstants;
// map scalar constants to result IDs
std::unordered_map<ScalarConstantKey, Id, ScalarConstantKeyHash> groupedScalarConstantResultIDs;
// Track which types have explicit layouts, to avoid reusing in storage classes without layout.
// Currently only tracks array types.
std::unordered_set<unsigned int> explicitlyLaidOut;
// stack of switches
std::stack<Block*> switchMerges;
@ -975,8 +1120,11 @@ public:
// map from include file name ids to their contents
std::map<spv::Id, const std::string*> includeFiles;
// map from core id to debug id
std::map <spv::Id, spv::Id> debugId;
// maps from OpTypeXXX id to DebugTypeXXX id
std::unordered_map<spv::Id, spv::Id> debugTypeIdLookup;
// maps from OpFunction id to DebugFunction id
std::unordered_map<spv::Id, spv::Id> debugFuncIdLookup;
// map from file name string id to DebugSource id
std::unordered_map<spv::Id, spv::Id> debugSourceId;
@ -985,6 +1133,6 @@ public:
SpvBuildLogger* logger;
}; // end Builder class
}; // end spv namespace
} // end spv namespace
#endif // SpvBuilder_H

View file

@ -43,8 +43,10 @@
#include <unordered_set>
#include <algorithm>
#include "SPIRV/spvIR.h"
#include "SpvBuilder.h"
#include "spirv.hpp"
#include "spirv.hpp11"
#include "spvUtil.h"
namespace spv {
#include "GLSL.std.450.h"
@ -64,182 +66,213 @@ namespace spv {
void Builder::postProcessType(const Instruction& inst, Id typeId)
{
// Characterize the type being questioned
Id basicTypeOp = getMostBasicTypeClass(typeId);
Op basicTypeOp = getMostBasicTypeClass(typeId);
int width = 0;
if (basicTypeOp == OpTypeFloat || basicTypeOp == OpTypeInt)
if (basicTypeOp == Op::OpTypeFloat || basicTypeOp == Op::OpTypeInt)
width = getScalarTypeWidth(typeId);
// Do opcode-specific checks
switch (inst.getOpCode()) {
case OpLoad:
case OpStore:
if (basicTypeOp == OpTypeStruct) {
if (containsType(typeId, OpTypeInt, 8))
addCapability(CapabilityInt8);
if (containsType(typeId, OpTypeInt, 16))
addCapability(CapabilityInt16);
if (containsType(typeId, OpTypeFloat, 16))
addCapability(CapabilityFloat16);
case Op::OpLoad:
case Op::OpStore:
if (basicTypeOp == Op::OpTypeStruct) {
if (containsType(typeId, Op::OpTypeInt, 8))
addCapability(Capability::Int8);
if (containsType(typeId, Op::OpTypeInt, 16))
addCapability(Capability::Int16);
if (containsType(typeId, Op::OpTypeFloat, 16))
addCapability(Capability::Float16);
} else {
StorageClass storageClass = getStorageClass(inst.getIdOperand(0));
if (width == 8) {
switch (storageClass) {
case StorageClassPhysicalStorageBufferEXT:
case StorageClassUniform:
case StorageClassStorageBuffer:
case StorageClassPushConstant:
case StorageClass::PhysicalStorageBufferEXT:
case StorageClass::Uniform:
case StorageClass::StorageBuffer:
case StorageClass::PushConstant:
break;
default:
addCapability(CapabilityInt8);
addCapability(Capability::Int8);
break;
}
} else if (width == 16) {
switch (storageClass) {
case StorageClassPhysicalStorageBufferEXT:
case StorageClassUniform:
case StorageClassStorageBuffer:
case StorageClassPushConstant:
case StorageClassInput:
case StorageClassOutput:
case StorageClass::PhysicalStorageBufferEXT:
case StorageClass::Uniform:
case StorageClass::StorageBuffer:
case StorageClass::PushConstant:
case StorageClass::Input:
case StorageClass::Output:
break;
default:
if (basicTypeOp == OpTypeInt)
addCapability(CapabilityInt16);
if (basicTypeOp == OpTypeFloat)
addCapability(CapabilityFloat16);
if (basicTypeOp == Op::OpTypeInt)
addCapability(Capability::Int16);
if (basicTypeOp == Op::OpTypeFloat)
addCapability(Capability::Float16);
break;
}
}
}
break;
case OpCopyObject:
case Op::OpCopyObject:
break;
case OpFConvert:
case OpSConvert:
case OpUConvert:
case Op::OpFConvert:
case Op::OpSConvert:
case Op::OpUConvert:
// Look for any 8/16-bit storage capabilities. If there are none, assume that
// the convert instruction requires the Float16/Int8/16 capability.
if (containsType(typeId, OpTypeFloat, 16) || containsType(typeId, OpTypeInt, 16)) {
if (containsType(typeId, Op::OpTypeFloat, 16) || containsType(typeId, Op::OpTypeInt, 16)) {
bool foundStorage = false;
for (auto it = capabilities.begin(); it != capabilities.end(); ++it) {
spv::Capability cap = *it;
if (cap == spv::CapabilityStorageInputOutput16 ||
cap == spv::CapabilityStoragePushConstant16 ||
cap == spv::CapabilityStorageUniformBufferBlock16 ||
cap == spv::CapabilityStorageUniform16) {
if (cap == spv::Capability::StorageInputOutput16 ||
cap == spv::Capability::StoragePushConstant16 ||
cap == spv::Capability::StorageUniformBufferBlock16 ||
cap == spv::Capability::StorageUniform16) {
foundStorage = true;
break;
}
}
if (!foundStorage) {
if (containsType(typeId, OpTypeFloat, 16))
addCapability(CapabilityFloat16);
if (containsType(typeId, OpTypeInt, 16))
addCapability(CapabilityInt16);
if (containsType(typeId, Op::OpTypeFloat, 16))
addCapability(Capability::Float16);
if (containsType(typeId, Op::OpTypeInt, 16))
addCapability(Capability::Int16);
}
}
if (containsType(typeId, OpTypeInt, 8)) {
if (containsType(typeId, Op::OpTypeInt, 8)) {
bool foundStorage = false;
for (auto it = capabilities.begin(); it != capabilities.end(); ++it) {
spv::Capability cap = *it;
if (cap == spv::CapabilityStoragePushConstant8 ||
cap == spv::CapabilityUniformAndStorageBuffer8BitAccess ||
cap == spv::CapabilityStorageBuffer8BitAccess) {
if (cap == spv::Capability::StoragePushConstant8 ||
cap == spv::Capability::UniformAndStorageBuffer8BitAccess ||
cap == spv::Capability::StorageBuffer8BitAccess) {
foundStorage = true;
break;
}
}
if (!foundStorage) {
addCapability(CapabilityInt8);
addCapability(Capability::Int8);
}
}
break;
case OpExtInst:
case Op::OpExtInst:
switch (inst.getImmediateOperand(1)) {
case GLSLstd450Frexp:
case GLSLstd450FrexpStruct:
if (getSpvVersion() < spv::Spv_1_3 && containsType(typeId, OpTypeInt, 16))
if (getSpvVersion() < spv::Spv_1_3 && containsType(typeId, Op::OpTypeInt, 16))
addExtension(spv::E_SPV_AMD_gpu_shader_int16);
break;
case GLSLstd450InterpolateAtCentroid:
case GLSLstd450InterpolateAtSample:
case GLSLstd450InterpolateAtOffset:
if (getSpvVersion() < spv::Spv_1_3 && containsType(typeId, OpTypeFloat, 16))
if (getSpvVersion() < spv::Spv_1_3 && containsType(typeId, Op::OpTypeFloat, 16))
addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
break;
default:
break;
}
break;
case OpAccessChain:
case OpPtrAccessChain:
case Op::OpAccessChain:
case Op::OpPtrAccessChain:
if (isPointerType(typeId))
break;
if (basicTypeOp == OpTypeInt) {
if (basicTypeOp == Op::OpTypeInt) {
if (width == 16)
addCapability(CapabilityInt16);
addCapability(Capability::Int16);
else if (width == 8)
addCapability(CapabilityInt8);
addCapability(Capability::Int8);
}
break;
default:
if (basicTypeOp == OpTypeInt) {
if (basicTypeOp == Op::OpTypeInt) {
if (width == 16)
addCapability(CapabilityInt16);
addCapability(Capability::Int16);
else if (width == 8)
addCapability(CapabilityInt8);
addCapability(Capability::Int8);
else if (width == 64)
addCapability(CapabilityInt64);
} else if (basicTypeOp == OpTypeFloat) {
addCapability(Capability::Int64);
} else if (basicTypeOp == Op::OpTypeFloat) {
if (width == 16)
addCapability(CapabilityFloat16);
addCapability(Capability::Float16);
else if (width == 64)
addCapability(CapabilityFloat64);
addCapability(Capability::Float64);
}
break;
}
}
unsigned int Builder::postProcessGetLargestScalarSize(const Instruction& type)
{
switch (type.getOpCode()) {
case Op::OpTypeBool:
return 1;
case Op::OpTypeInt:
case Op::OpTypeFloat:
return type.getImmediateOperand(0) / 8;
case Op::OpTypePointer:
return 8;
case Op::OpTypeVector:
case Op::OpTypeMatrix:
case Op::OpTypeArray:
case Op::OpTypeRuntimeArray: {
const Instruction* elem_type = module.getInstruction(type.getIdOperand(0));
return postProcessGetLargestScalarSize(*elem_type);
}
case Op::OpTypeStruct: {
unsigned int largest = 0;
for (int i = 0; i < type.getNumOperands(); ++i) {
const Instruction* elem_type = module.getInstruction(type.getIdOperand(i));
unsigned int elem_size = postProcessGetLargestScalarSize(*elem_type);
largest = std::max(largest, elem_size);
}
return largest;
}
default:
return 0;
}
}
// Called for each instruction that resides in a block.
void Builder::postProcess(Instruction& inst)
{
// Add capabilities based simply on the opcode.
switch (inst.getOpCode()) {
case OpExtInst:
case Op::OpExtInst:
switch (inst.getImmediateOperand(1)) {
case GLSLstd450InterpolateAtCentroid:
case GLSLstd450InterpolateAtSample:
case GLSLstd450InterpolateAtOffset:
addCapability(CapabilityInterpolationFunction);
addCapability(Capability::InterpolationFunction);
break;
default:
break;
}
break;
case OpDPdxFine:
case OpDPdyFine:
case OpFwidthFine:
case OpDPdxCoarse:
case OpDPdyCoarse:
case OpFwidthCoarse:
addCapability(CapabilityDerivativeControl);
case Op::OpDPdxFine:
case Op::OpDPdyFine:
case Op::OpFwidthFine:
case Op::OpDPdxCoarse:
case Op::OpDPdyCoarse:
case Op::OpFwidthCoarse:
addCapability(Capability::DerivativeControl);
break;
case OpImageQueryLod:
case OpImageQuerySize:
case OpImageQuerySizeLod:
case OpImageQuerySamples:
case OpImageQueryLevels:
addCapability(CapabilityImageQuery);
case Op::OpImageQueryLod:
case Op::OpImageQuerySize:
case Op::OpImageQuerySizeLod:
case Op::OpImageQuerySamples:
case Op::OpImageQueryLevels:
addCapability(Capability::ImageQuery);
break;
case OpGroupNonUniformPartitionNV:
case Op::OpGroupNonUniformPartitionNV:
addExtension(E_SPV_NV_shader_subgroup_partitioned);
addCapability(CapabilityGroupNonUniformPartitionedNV);
addCapability(Capability::GroupNonUniformPartitionedNV);
break;
case OpLoad:
case OpStore:
case Op::OpLoad:
case Op::OpStore:
{
// For any load/store to a PhysicalStorageBufferEXT, walk the accesschain
// index list to compute the misalignment. The pre-existing alignment value
@ -247,13 +280,13 @@ void Builder::postProcess(Instruction& inst)
// the reference type and any scalar component selection in the accesschain,
// and this function computes the rest from the SPIR-V Offset decorations.
Instruction *accessChain = module.getInstruction(inst.getIdOperand(0));
if (accessChain->getOpCode() == OpAccessChain) {
Instruction *base = module.getInstruction(accessChain->getIdOperand(0));
if (accessChain->getOpCode() == Op::OpAccessChain) {
const Instruction* base = module.getInstruction(accessChain->getIdOperand(0));
// Get the type of the base of the access chain. It must be a pointer type.
Id typeId = base->getTypeId();
Instruction *type = module.getInstruction(typeId);
assert(type->getOpCode() == OpTypePointer);
if (type->getImmediateOperand(0) != StorageClassPhysicalStorageBufferEXT) {
assert(type->getOpCode() == Op::OpTypePointer);
if (type->getImmediateOperand(0) != StorageClass::PhysicalStorageBuffer) {
break;
}
// Get the pointee type.
@ -264,31 +297,37 @@ void Builder::postProcess(Instruction& inst)
// Offset/ArrayStride/MatrixStride decorations, and bitwise OR them all
// together.
int alignment = 0;
bool first_struct_elem = false;
for (int i = 1; i < accessChain->getNumOperands(); ++i) {
Instruction *idx = module.getInstruction(accessChain->getIdOperand(i));
if (type->getOpCode() == OpTypeStruct) {
assert(idx->getOpCode() == OpConstant);
if (type->getOpCode() == Op::OpTypeStruct) {
assert(idx->getOpCode() == Op::OpConstant);
unsigned int c = idx->getImmediateOperand(0);
const auto function = [&](const std::unique_ptr<Instruction>& decoration) {
if (decoration.get()->getOpCode() == OpMemberDecorate &&
if (decoration.get()->getOpCode() == Op::OpMemberDecorate &&
decoration.get()->getIdOperand(0) == typeId &&
decoration.get()->getImmediateOperand(1) == c &&
(decoration.get()->getImmediateOperand(2) == DecorationOffset ||
decoration.get()->getImmediateOperand(2) == DecorationMatrixStride)) {
alignment |= decoration.get()->getImmediateOperand(3);
(decoration.get()->getImmediateOperand(2) == Decoration::Offset ||
decoration.get()->getImmediateOperand(2) == Decoration::MatrixStride)) {
unsigned int opernad_value = decoration.get()->getImmediateOperand(3);
alignment |= opernad_value;
if (opernad_value == 0 &&
decoration.get()->getImmediateOperand(2) == Decoration::Offset) {
first_struct_elem = true;
}
}
};
std::for_each(decorations.begin(), decorations.end(), function);
// get the next member type
typeId = type->getIdOperand(c);
type = module.getInstruction(typeId);
} else if (type->getOpCode() == OpTypeArray ||
type->getOpCode() == OpTypeRuntimeArray) {
} else if (type->getOpCode() == Op::OpTypeArray ||
type->getOpCode() == Op::OpTypeRuntimeArray) {
const auto function = [&](const std::unique_ptr<Instruction>& decoration) {
if (decoration.get()->getOpCode() == OpDecorate &&
if (decoration.get()->getOpCode() == Op::OpDecorate &&
decoration.get()->getIdOperand(0) == typeId &&
decoration.get()->getImmediateOperand(1) == DecorationArrayStride) {
decoration.get()->getImmediateOperand(1) == Decoration::ArrayStride) {
alignment |= decoration.get()->getImmediateOperand(2);
}
};
@ -302,18 +341,51 @@ void Builder::postProcess(Instruction& inst)
}
}
assert(inst.getNumOperands() >= 3);
unsigned int memoryAccess = inst.getImmediateOperand((inst.getOpCode() == OpStore) ? 2 : 1);
assert(memoryAccess & MemoryAccessAlignedMask);
const bool is_store = inst.getOpCode() == Op::OpStore;
auto const memoryAccess = (MemoryAccessMask)inst.getImmediateOperand(is_store ? 2 : 1);
assert(anySet(memoryAccess, MemoryAccessMask::Aligned));
static_cast<void>(memoryAccess);
// Compute the index of the alignment operand.
int alignmentIdx = 2;
if (inst.getOpCode() == OpStore)
if (is_store)
alignmentIdx++;
// Merge new and old (mis)alignment
alignment |= inst.getImmediateOperand(alignmentIdx);
if (!is_store) {
Instruction* inst_type = module.getInstruction(inst.getTypeId());
if (inst_type->getOpCode() == Op::OpTypePointer &&
inst_type->getImmediateOperand(0) == StorageClass::PhysicalStorageBuffer) {
// This means we are loading a pointer which means need to ensure it is at least 8-byte aligned
// See https://github.com/KhronosGroup/glslang/issues/4084
// In case the alignment is currently 4, need to ensure it is 8 before grabbing the LSB
alignment |= 8;
alignment &= 8;
}
}
// Pick the LSB
alignment = alignment & ~(alignment & (alignment-1));
// The edge case we find is when copying a struct to another struct, we never find the alignment anywhere,
// so in this case, fallback to doing a full size lookup on the type
if (alignment == 0 && first_struct_elem) {
// Quick get the struct type back
const Instruction* pointer_type = module.getInstruction(base->getTypeId());
const Instruction* struct_type = module.getInstruction(pointer_type->getIdOperand(1));
assert(struct_type->getOpCode() == Op::OpTypeStruct);
const Instruction* elem_type = module.getInstruction(struct_type->getIdOperand(0));
unsigned int largest_scalar = postProcessGetLargestScalarSize(*elem_type);
if (largest_scalar != 0) {
alignment = largest_scalar;
} else {
alignment = 16; // fallback if can't determine a godo alignment
}
}
// update the Aligned operand
assert(alignment != 0);
inst.setImmediateOperand(alignmentIdx, alignment);
}
break;
@ -387,12 +459,14 @@ void Builder::postProcessCFG()
}
// Remove unneeded decorations, for unreachable instructions
decorations.erase(std::remove_if(decorations.begin(), decorations.end(),
[&unreachableDefinitions](std::unique_ptr<Instruction>& I) -> bool {
Id decoration_id = I.get()->getIdOperand(0);
return unreachableDefinitions.count(decoration_id) != 0;
}),
decorations.end());
for (auto decorationIter = decorations.begin(); decorationIter != decorations.end();) {
Id decorationId = (*decorationIter)->getIdOperand(0);
if (unreachableDefinitions.count(decorationId) != 0) {
decorationIter = decorations.erase(decorationIter);
} else {
++decorationIter;
}
}
}
// comment in header
@ -402,17 +476,17 @@ void Builder::postProcessFeatures() {
// Look for any 8/16 bit type in physical storage buffer class, and set the
// appropriate capability. This happens in createSpvVariable for other storage
// classes, but there isn't always a variable for physical storage buffer.
for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
Instruction* type = groupedTypes[OpTypePointer][t];
if (type->getImmediateOperand(0) == (unsigned)StorageClassPhysicalStorageBufferEXT) {
if (containsType(type->getIdOperand(1), OpTypeInt, 8)) {
for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypePointer)].size(); ++t) {
Instruction* type = groupedTypes[enumCast(Op::OpTypePointer)][t];
if (type->getImmediateOperand(0) == (unsigned)StorageClass::PhysicalStorageBufferEXT) {
if (containsType(type->getIdOperand(1), Op::OpTypeInt, 8)) {
addIncorporatedExtension(spv::E_SPV_KHR_8bit_storage, spv::Spv_1_5);
addCapability(spv::CapabilityStorageBuffer8BitAccess);
addCapability(spv::Capability::StorageBuffer8BitAccess);
}
if (containsType(type->getIdOperand(1), OpTypeInt, 16) ||
containsType(type->getIdOperand(1), OpTypeFloat, 16)) {
if (containsType(type->getIdOperand(1), Op::OpTypeInt, 16) ||
containsType(type->getIdOperand(1), Op::OpTypeFloat, 16)) {
addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3);
addCapability(spv::CapabilityStorageBuffer16BitAccess);
addCapability(spv::Capability::StorageBuffer16BitAccess);
}
}
}
@ -435,15 +509,15 @@ void Builder::postProcessFeatures() {
bool foundDecoration = false;
const auto function = [&](const std::unique_ptr<Instruction>& decoration) {
if (decoration.get()->getIdOperand(0) == resultId &&
decoration.get()->getOpCode() == OpDecorate &&
(decoration.get()->getImmediateOperand(1) == spv::DecorationAliasedPointerEXT ||
decoration.get()->getImmediateOperand(1) == spv::DecorationRestrictPointerEXT)) {
decoration.get()->getOpCode() == Op::OpDecorate &&
(decoration.get()->getImmediateOperand(1) == spv::Decoration::AliasedPointerEXT ||
decoration.get()->getImmediateOperand(1) == spv::Decoration::RestrictPointerEXT)) {
foundDecoration = true;
}
};
std::for_each(decorations.begin(), decorations.end(), function);
if (!foundDecoration) {
addDecoration(resultId, spv::DecorationAliasedPointerEXT);
addDecoration(resultId, spv::Decoration::AliasedPointerEXT);
}
}
}
@ -452,13 +526,13 @@ void Builder::postProcessFeatures() {
// If any Vulkan memory model-specific functionality is used, update the
// OpMemoryModel to match.
if (capabilities.find(spv::CapabilityVulkanMemoryModelKHR) != capabilities.end()) {
memoryModel = spv::MemoryModelVulkanKHR;
if (capabilities.find(spv::Capability::VulkanMemoryModelKHR) != capabilities.end()) {
memoryModel = spv::MemoryModel::VulkanKHR;
addIncorporatedExtension(spv::E_SPV_KHR_vulkan_memory_model, spv::Spv_1_5);
}
// Add Aliased decoration if there's more than one Workgroup Block variable.
if (capabilities.find(spv::CapabilityWorkgroupMemoryExplicitLayoutKHR) != capabilities.end()) {
if (capabilities.find(spv::Capability::WorkgroupMemoryExplicitLayoutKHR) != capabilities.end()) {
assert(entryPoints.size() == 1);
auto &ep = entryPoints[0];
@ -469,20 +543,72 @@ void Builder::postProcessFeatures() {
const Id id = ep->getIdOperand(i);
const Instruction *instr = module.getInstruction(id);
if (instr->getOpCode() != spv::OpVariable)
if (instr->getOpCode() != spv::Op::OpVariable)
continue;
if (instr->getImmediateOperand(0) == spv::StorageClassWorkgroup)
if (instr->getImmediateOperand(0) == spv::StorageClass::Workgroup)
workgroup_variables.push_back(id);
}
if (workgroup_variables.size() > 1) {
for (size_t i = 0; i < workgroup_variables.size(); i++)
addDecoration(workgroup_variables[i], spv::DecorationAliased);
addDecoration(workgroup_variables[i], spv::Decoration::Aliased);
}
}
}
// SPIR-V requires that any instruction consuming the result of an OpSampledImage
// be in the same block as the OpSampledImage instruction. This pass goes finds
// uses of OpSampledImage where that is not the case and duplicates the
// OpSampledImage to be immediately before the instruction that consumes it.
// The old OpSampledImage is left in place, potentially with no users.
void Builder::postProcessSamplers()
{
// first, find all OpSampledImage instructions and store them in a map.
std::map<Id, Instruction*> sampledImageInstrs;
for (auto f: module.getFunctions()) {
for (auto b: f->getBlocks()) {
for (auto &i: b->getInstructions()) {
if (i->getOpCode() == spv::Op::OpSampledImage) {
sampledImageInstrs[i->getResultId()] = i.get();
}
}
}
}
// next find all uses of the given ids and rewrite them if needed.
for (auto f: module.getFunctions()) {
for (auto b: f->getBlocks()) {
auto &instrs = b->getInstructions();
for (size_t idx = 0; idx < instrs.size(); idx++) {
Instruction *i = instrs[idx].get();
for (int opnum = 0; opnum < i->getNumOperands(); opnum++) {
// Is this operand of the current instruction the result of an OpSampledImage?
if (i->isIdOperand(opnum) &&
sampledImageInstrs.count(i->getIdOperand(opnum)))
{
Instruction *opSampImg = sampledImageInstrs[i->getIdOperand(opnum)];
if (i->getBlock() != opSampImg->getBlock()) {
Instruction *newInstr = new Instruction(getUniqueId(),
opSampImg->getTypeId(),
spv::Op::OpSampledImage);
newInstr->addIdOperand(opSampImg->getIdOperand(0));
newInstr->addIdOperand(opSampImg->getIdOperand(1));
newInstr->setBlock(b);
// rewrite the user of the OpSampledImage to use the new instruction.
i->setIdOperand(opnum, newInstr->getResultId());
// insert the new OpSampledImage right before the current instruction.
instrs.insert(instrs.begin() + idx,
std::unique_ptr<Instruction>(newInstr));
idx++;
}
}
}
}
}
}
}
// comment in header
void Builder::postProcess(bool compileOnly)
{
@ -491,6 +617,7 @@ void Builder::postProcess(bool compileOnly)
postProcessCFG();
postProcessFeatures();
postProcessSamplers();
}
}; // end spv namespace
} // end spv namespace

View file

@ -44,6 +44,7 @@
#include "SpvTools.h"
#include "spirv-tools/optimizer.hpp"
#include "glslang/MachineIndependent/localintermediate.h"
namespace glslang {
@ -70,6 +71,8 @@ spv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLog
return spv_target_env::SPV_ENV_VULKAN_1_2;
case glslang::EShTargetVulkan_1_3:
return spv_target_env::SPV_ENV_VULKAN_1_3;
case glslang::EShTargetVulkan_1_4:
return spv_target_env::SPV_ENV_VULKAN_1_4;
default:
break;
}
@ -81,6 +84,11 @@ spv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLog
return spv_target_env::SPV_ENV_UNIVERSAL_1_0;
}
spv_target_env MapToSpirvToolsEnv(const glslang::TIntermediate& intermediate, spv::SpvBuildLogger* logger)
{
return MapToSpirvToolsEnv(intermediate.getSpv(), logger);
}
// Callback passed to spvtools::Optimizer::SetMessageConsumer
void OptimizerMesssageConsumer(spv_message_level_t level, const char *source,
const spv_position_t &position, const char *message)
@ -157,6 +165,7 @@ void SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector<
spvValidatorOptionsSetBeforeHlslLegalization(options, prelegalization);
spvValidatorOptionsSetScalarBlockLayout(options, intermediate.usingScalarBlockLayout());
spvValidatorOptionsSetWorkgroupScalarBlockLayout(options, intermediate.usingScalarBlockLayout());
spvValidatorOptionsSetAllowOffsetTextureOperand(options, intermediate.usingTextureOffsetNonConst());
spvValidateWithOptions(context, options, &binary, &diagnostic);
// report
@ -218,9 +227,20 @@ void SpirvToolsTransform(const glslang::TIntermediate& intermediate, std::vector
optimizer.RegisterPass(spvtools::CreateCFGCleanupPass());
spvtools::OptimizerOptions spvOptOptions;
if (options->optimizerAllowExpandedIDBound)
spvOptOptions.set_max_id_bound(0x3FFFFFFF);
optimizer.SetTargetEnv(MapToSpirvToolsEnv(intermediate.getSpv(), logger));
spvOptOptions.set_run_validator(false); // The validator may run as a separate step later on
optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);
if (options->optimizerAllowExpandedIDBound) {
if (spirv.size() > 3 && spirv[3] > kDefaultMaxIdBound) {
spvtools::Optimizer optimizer2(target_env);
optimizer2.SetMessageConsumer(OptimizerMesssageConsumer);
optimizer2.RegisterPass(spvtools::CreateCompactIdsPass());
optimizer2.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);
}
}
}
bool SpirvToolsAnalyzeDeadOutputStores(spv_target_env target_env, std::vector<unsigned int>& spirv,
@ -292,6 +312,6 @@ void SpirvToolsStripDebugInfo(const glslang::TIntermediate& intermediate,
optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);
}
}; // end namespace glslang
} // end namespace glslang
#endif

View file

@ -44,10 +44,12 @@
#if ENABLE_OPT
#include <vector>
#include <ostream>
#include <unordered_set>
#include "spirv-tools/libspirv.h"
#endif
#include "glslang/MachineIndependent/localintermediate.h"
#include "glslang/MachineIndependent/Versions.h"
#include "glslang/Include/visibility.h"
#include "GlslangToSpv.h"
#include "Logger.h"
@ -55,45 +57,50 @@ namespace glslang {
#if ENABLE_OPT
class TIntermediate;
// Translate glslang's view of target versioning to what SPIRV-Tools uses.
spv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLogger* logger);
GLSLANG_EXPORT spv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLogger* logger);
GLSLANG_EXPORT spv_target_env MapToSpirvToolsEnv(const glslang::TIntermediate& intermediate, spv::SpvBuildLogger* logger);
// Use the SPIRV-Tools disassembler to print SPIR-V using a SPV_ENV_UNIVERSAL_1_3 environment.
void SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv);
GLSLANG_EXPORT void SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv);
// Use the SPIRV-Tools disassembler to print SPIR-V with a provided SPIR-V environment.
void SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv,
spv_target_env requested_context);
GLSLANG_EXPORT void SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv,
spv_target_env requested_context);
// Apply the SPIRV-Tools validator to generated SPIR-V.
void SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
spv::SpvBuildLogger*, bool prelegalization);
GLSLANG_EXPORT void SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
spv::SpvBuildLogger*, bool prelegalization);
// Apply the SPIRV-Tools optimizer to generated SPIR-V. HLSL SPIR-V is legalized in the process.
void SpirvToolsTransform(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
spv::SpvBuildLogger*, const SpvOptions*);
GLSLANG_EXPORT void SpirvToolsTransform(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
spv::SpvBuildLogger*, const SpvOptions*);
// Apply the SPIRV-Tools EliminateDeadInputComponents pass to generated SPIR-V. Put result in |spirv|.
void SpirvToolsEliminateDeadInputComponents(spv_target_env target_env, std::vector<unsigned int>& spirv,
spv::SpvBuildLogger*);
GLSLANG_EXPORT void SpirvToolsEliminateDeadInputComponents(spv_target_env target_env, std::vector<unsigned int>& spirv,
spv::SpvBuildLogger*);
// Apply the SPIRV-Tools AnalyzeDeadOutputStores pass to generated SPIR-V. Put result in |live_locs|.
// Return true if the result is valid.
bool SpirvToolsAnalyzeDeadOutputStores(spv_target_env target_env, std::vector<unsigned int>& spirv,
std::unordered_set<uint32_t>* live_locs,
std::unordered_set<uint32_t>* live_builtins, spv::SpvBuildLogger*);
GLSLANG_EXPORT bool SpirvToolsAnalyzeDeadOutputStores(spv_target_env target_env, std::vector<unsigned int>& spirv,
std::unordered_set<uint32_t>* live_locs,
std::unordered_set<uint32_t>* live_builtins,
spv::SpvBuildLogger*);
// Apply the SPIRV-Tools EliminateDeadOutputStores and AggressiveDeadCodeElimination passes to generated SPIR-V using
// |live_locs|. Put result in |spirv|.
void SpirvToolsEliminateDeadOutputStores(spv_target_env target_env, std::vector<unsigned int>& spirv,
std::unordered_set<uint32_t>* live_locs,
std::unordered_set<uint32_t>* live_builtins, spv::SpvBuildLogger*);
GLSLANG_EXPORT void SpirvToolsEliminateDeadOutputStores(spv_target_env target_env, std::vector<unsigned int>& spirv,
std::unordered_set<uint32_t>* live_locs,
std::unordered_set<uint32_t>* live_builtins,
spv::SpvBuildLogger*);
// Apply the SPIRV-Tools optimizer to strip debug info from SPIR-V. This is implicitly done by
// SpirvToolsTransform if spvOptions->stripDebugInfo is set, but can be called separately if
// optimization is disabled.
void SpirvToolsStripDebugInfo(const glslang::TIntermediate& intermediate,
std::vector<unsigned int>& spirv, spv::SpvBuildLogger*);
GLSLANG_EXPORT void SpirvToolsStripDebugInfo(const glslang::TIntermediate& intermediate,
std::vector<unsigned int>& spirv, spv::SpvBuildLogger*);
#endif

View file

@ -36,6 +36,7 @@
// Disassembler for SPIR-V.
//
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <cassert>
@ -47,6 +48,7 @@
#include "disassemble.h"
#include "doc.h"
#include "spvUtil.h"
namespace spv {
extern "C" {
@ -59,7 +61,7 @@ namespace spv {
#include "GLSL.ext.QCOM.h"
}
}
const char* GlslStd450DebugNames[spv::GLSLstd450Count];
static const char* GlslStd450DebugNames[spv::GLSLstd450Count];
namespace spv {
@ -96,7 +98,7 @@ public:
protected:
SpirvStream(const SpirvStream&);
SpirvStream& operator=(const SpirvStream&);
Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : OpNop; }
Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : Op::OpNop; }
// Output methods
void outputIndent();
@ -186,14 +188,14 @@ void SpirvStream::processInstructions()
// Type <id>
Id typeId = 0;
if (InstructionDesc[opCode].hasType()) {
if (InstructionDesc[enumCast(opCode)].hasType()) {
typeId = stream[word++];
--numOperands;
}
// Result <id>
Id resultId = 0;
if (InstructionDesc[opCode].hasResult()) {
if (InstructionDesc[enumCast(opCode)].hasResult()) {
resultId = stream[word++];
--numOperands;
@ -338,26 +340,38 @@ int SpirvStream::disassembleString()
return decoderes.first;
}
static uint32_t popcount(uint32_t mask)
{
uint32_t count = 0;
while (mask) {
if (mask & 1) {
count++;
}
mask >>= 1;
}
return count;
}
void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands)
{
// Process the opcode
out << (OpcodeString(opCode) + 2); // leave out the "Op"
out << (OpcodeString((int)opCode) + 2); // leave out the "Op"
if (opCode == OpLoopMerge || opCode == OpSelectionMerge)
if (opCode == Op::OpLoopMerge || opCode == Op::OpSelectionMerge)
nextNestedControl = stream[word];
else if (opCode == OpBranchConditional || opCode == OpSwitch) {
else if (opCode == Op::OpBranchConditional || opCode == Op::OpSwitch) {
if (nextNestedControl) {
nestedControl.push(nextNestedControl);
nextNestedControl = 0;
}
} else if (opCode == OpExtInstImport) {
} else if (opCode == Op::OpExtInstImport) {
idDescriptor[resultId] = decodeString().second;
}
else {
if (resultId != 0 && idDescriptor[resultId].size() == 0) {
switch (opCode) {
case OpTypeInt:
case Op::OpTypeInt:
switch (stream[word]) {
case 8: idDescriptor[resultId] = "int8_t"; break;
case 16: idDescriptor[resultId] = "int16_t"; break;
@ -366,26 +380,49 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
case 64: idDescriptor[resultId] = "int64_t"; break;
}
break;
case OpTypeFloat:
case Op::OpTypeFloat:
switch (stream[word]) {
case 16: idDescriptor[resultId] = "float16_t"; break;
case 8:
case 16:
if (numOperands > 1) {
switch (stream[word+1]) {
default:
assert(0); [[fallthrough]];
case (int)spv::FPEncoding::BFloat16KHR:
idDescriptor[resultId] = "bfloat16_t";
break;
case (int)spv::FPEncoding::Float8E4M3EXT:
idDescriptor[resultId] = "floate4m3_t";
break;
case (int)spv::FPEncoding::Float8E5M2EXT:
idDescriptor[resultId] = "floate5m2_t";
break;
}
} else {
idDescriptor[resultId] = "float16_t";
}
break;
default: assert(0); [[fallthrough]];
case 32: idDescriptor[resultId] = "float"; break;
case 64: idDescriptor[resultId] = "float64_t"; break;
}
break;
case OpTypeBool:
case Op::OpTypeBool:
idDescriptor[resultId] = "bool";
break;
case OpTypeStruct:
case Op::OpTypeStruct:
idDescriptor[resultId] = "struct";
break;
case OpTypePointer:
case Op::OpTypePointer:
idDescriptor[resultId] = "ptr";
break;
case OpTypeVector:
case Op::OpTypeVector:
if (idDescriptor[stream[word]].size() > 0) {
idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1);
if (idDescriptor[stream[word]].substr(0,2) == "bf") {
idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 2);
} else {
idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1);
}
if (strstr(idDescriptor[stream[word]].c_str(), "8")) {
idDescriptor[resultId].append("8");
}
@ -417,10 +454,10 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
// swapped in mid-traversal.
// Handle images specially, so can put out helpful strings.
if (opCode == OpTypeImage) {
if (opCode == Op::OpTypeImage) {
out << " ";
disassembleIds(1);
out << " " << DimensionString((Dim)stream[word++]);
out << " " << DimensionString((int)(Dim)stream[word++]);
out << (stream[word++] != 0 ? " depth" : "");
out << (stream[word++] != 0 ? " array" : "");
out << (stream[word++] != 0 ? " multi-sampled" : "");
@ -429,7 +466,7 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
case 1: out << " sampled"; break;
case 2: out << " nonsampled"; break;
}
out << " format:" << ImageFormatString((ImageFormat)stream[word++]);
out << " format:" << ImageFormatString((int)(ImageFormat)stream[word++]);
if (numOperands == 8) {
out << " " << AccessQualifierString(stream[word++]);
@ -438,9 +475,9 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
}
// Handle all the parameterized operands
for (int op = 0; op < InstructionDesc[opCode].operands.getNum() && numOperands > 0; ++op) {
for (int op = 0; op < InstructionDesc[enumCast(opCode)].operands.getNum() && numOperands > 0; ++op) {
out << " ";
OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op);
OperandClass operandClass = InstructionDesc[enumCast(opCode)].operands.getClass(op);
switch (operandClass) {
case OperandId:
case OperandScope:
@ -448,7 +485,7 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
disassembleIds(1);
--numOperands;
// Get names for printing "(XXX)" for readability, *after* this id
if (opCode == OpName)
if (opCode == Op::OpName)
idDescriptor[stream[word - 1]] = decodeString().second;
break;
case OperandVariableIds:
@ -461,8 +498,8 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
return;
case OperandOptionalLiteral:
case OperandVariableLiterals:
if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) ||
(opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) {
if ((opCode == Op::OpDecorate && stream[word - 1] == Decoration::BuiltIn) ||
(opCode == Op::OpMemberDecorate && stream[word - 1] == Decoration::BuiltIn)) {
out << BuiltInString(stream[word++]);
--numOperands;
++op;
@ -498,7 +535,7 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
case OperandLiteralNumber:
disassembleImmediates(1);
--numOperands;
if (opCode == OpExtInst) {
if (opCode == Op::OpExtInst) {
ExtInstSet extInstSet = GLSL450Inst;
const char* name = idDescriptor[stream[word - 2]].c_str();
if (strcmp("OpenCL.std", name) == 0) {
@ -552,18 +589,41 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
numOperands -= disassembleString();
return;
case OperandMemoryAccess:
outputMask(OperandMemoryAccess, stream[word++]);
--numOperands;
// Aligned is the only memory access operand that uses an immediate
// value, and it is also the first operand that uses a value at all.
if (stream[word-1] & MemoryAccessAlignedMask) {
disassembleImmediates(1);
numOperands--;
if (numOperands)
{
outputMask(OperandMemoryAccess, stream[word++]);
--numOperands;
// Put a space after "None" if there are any remaining operands
if (numOperands && stream[word-1] == 0) {
out << " ";
}
uint32_t mask = stream[word-1];
// Aligned is the only memory access operand that uses an immediate
// value, and it is also the first operand that uses a value at all.
if (mask & (uint32_t)MemoryAccessMask::Aligned) {
disassembleImmediates(1);
numOperands--;
if (numOperands)
out << " ";
}
uint32_t bitCount = popcount(mask & (uint32_t)(MemoryAccessMask::MakePointerAvailable | MemoryAccessMask::MakePointerVisible));
disassembleIds(bitCount);
numOperands -= bitCount;
}
disassembleIds(numOperands);
return;
break;
case OperandTensorAddressingOperands:
{
outputMask(OperandTensorAddressingOperands, stream[word++]);
--numOperands;
// Put a space after "None" if there are any remaining operands
if (numOperands && stream[word-1] == 0) {
out << " ";
}
uint32_t bitCount = popcount(stream[word-1]);
disassembleIds(bitCount);
numOperands -= bitCount;
}
break;
default:
assert(operandClass >= OperandSource && operandClass < OperandOpcode);
@ -721,41 +781,41 @@ static const char* GLSLextNVGetDebugNames(const char* name, unsigned entrypoint)
strcmp(name, spv::E_SPV_NV_shader_image_footprint) == 0) {
switch (entrypoint) {
// NV builtins
case BuiltInViewportMaskNV: return "ViewportMaskNV";
case BuiltInSecondaryPositionNV: return "SecondaryPositionNV";
case BuiltInSecondaryViewportMaskNV: return "SecondaryViewportMaskNV";
case BuiltInPositionPerViewNV: return "PositionPerViewNV";
case BuiltInViewportMaskPerViewNV: return "ViewportMaskPerViewNV";
case BuiltInBaryCoordNV: return "BaryCoordNV";
case BuiltInBaryCoordNoPerspNV: return "BaryCoordNoPerspNV";
case BuiltInTaskCountNV: return "TaskCountNV";
case BuiltInPrimitiveCountNV: return "PrimitiveCountNV";
case BuiltInPrimitiveIndicesNV: return "PrimitiveIndicesNV";
case BuiltInClipDistancePerViewNV: return "ClipDistancePerViewNV";
case BuiltInCullDistancePerViewNV: return "CullDistancePerViewNV";
case BuiltInLayerPerViewNV: return "LayerPerViewNV";
case BuiltInMeshViewCountNV: return "MeshViewCountNV";
case BuiltInMeshViewIndicesNV: return "MeshViewIndicesNV";
case (unsigned)BuiltIn::ViewportMaskNV: return "ViewportMaskNV";
case (unsigned)BuiltIn::SecondaryPositionNV: return "SecondaryPositionNV";
case (unsigned)BuiltIn::SecondaryViewportMaskNV: return "SecondaryViewportMaskNV";
case (unsigned)BuiltIn::PositionPerViewNV: return "PositionPerViewNV";
case (unsigned)BuiltIn::ViewportMaskPerViewNV: return "ViewportMaskPerViewNV";
case (unsigned)BuiltIn::BaryCoordNV: return "BaryCoordNV";
case (unsigned)BuiltIn::BaryCoordNoPerspNV: return "BaryCoordNoPerspNV";
case (unsigned)BuiltIn::TaskCountNV: return "TaskCountNV";
case (unsigned)BuiltIn::PrimitiveCountNV: return "PrimitiveCountNV";
case (unsigned)BuiltIn::PrimitiveIndicesNV: return "PrimitiveIndicesNV";
case (unsigned)BuiltIn::ClipDistancePerViewNV: return "ClipDistancePerViewNV";
case (unsigned)BuiltIn::CullDistancePerViewNV: return "CullDistancePerViewNV";
case (unsigned)BuiltIn::LayerPerViewNV: return "LayerPerViewNV";
case (unsigned)BuiltIn::MeshViewCountNV: return "MeshViewCountNV";
case (unsigned)BuiltIn::MeshViewIndicesNV: return "MeshViewIndicesNV";
// NV Capabilities
case CapabilityGeometryShaderPassthroughNV: return "GeometryShaderPassthroughNV";
case CapabilityShaderViewportMaskNV: return "ShaderViewportMaskNV";
case CapabilityShaderStereoViewNV: return "ShaderStereoViewNV";
case CapabilityPerViewAttributesNV: return "PerViewAttributesNV";
case CapabilityFragmentBarycentricNV: return "FragmentBarycentricNV";
case CapabilityMeshShadingNV: return "MeshShadingNV";
case CapabilityImageFootprintNV: return "ImageFootprintNV";
case CapabilitySampleMaskOverrideCoverageNV:return "SampleMaskOverrideCoverageNV";
case (unsigned)Capability::GeometryShaderPassthroughNV: return "GeometryShaderPassthroughNV";
case (unsigned)Capability::ShaderViewportMaskNV: return "ShaderViewportMaskNV";
case (unsigned)Capability::ShaderStereoViewNV: return "ShaderStereoViewNV";
case (unsigned)Capability::PerViewAttributesNV: return "PerViewAttributesNV";
case (unsigned)Capability::FragmentBarycentricNV: return "FragmentBarycentricNV";
case (unsigned)Capability::MeshShadingNV: return "MeshShadingNV";
case (unsigned)Capability::ImageFootprintNV: return "ImageFootprintNV";
case (unsigned)Capability::SampleMaskOverrideCoverageNV:return "SampleMaskOverrideCoverageNV";
// NV Decorations
case DecorationOverrideCoverageNV: return "OverrideCoverageNV";
case DecorationPassthroughNV: return "PassthroughNV";
case DecorationViewportRelativeNV: return "ViewportRelativeNV";
case DecorationSecondaryViewportRelativeNV: return "SecondaryViewportRelativeNV";
case DecorationPerVertexNV: return "PerVertexNV";
case DecorationPerPrimitiveNV: return "PerPrimitiveNV";
case DecorationPerViewNV: return "PerViewNV";
case DecorationPerTaskNV: return "PerTaskNV";
case (unsigned)Decoration::OverrideCoverageNV: return "OverrideCoverageNV";
case (unsigned)Decoration::PassthroughNV: return "PassthroughNV";
case (unsigned)Decoration::ViewportRelativeNV: return "ViewportRelativeNV";
case (unsigned)Decoration::SecondaryViewportRelativeNV: return "SecondaryViewportRelativeNV";
case (unsigned)Decoration::PerVertexNV: return "PerVertexNV";
case (unsigned)Decoration::PerPrimitiveNV: return "PerPrimitiveNV";
case (unsigned)Decoration::PerViewNV: return "PerViewNV";
case (unsigned)Decoration::PerTaskNV: return "PerTaskNV";
default: return "Bad";
}
@ -825,4 +885,4 @@ void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
SpirvStream.processInstructions();
}
}; // end namespace spv
} // end namespace spv

View file

@ -43,10 +43,12 @@
#include <iostream>
#include <vector>
#include "glslang/Include/visibility.h"
namespace spv {
// disassemble with glslang custom disassembler
void Disassemble(std::ostream& out, const std::vector<unsigned int>&);
GLSLANG_EXPORT void Disassemble(std::ostream& out, const std::vector<unsigned int>&);
} // end namespace spv

File diff suppressed because it is too large Load diff

View file

@ -38,7 +38,7 @@
#pragma once
#include "spirv.hpp"
#include "spirv.hpp11"
#include <vector>
@ -157,6 +157,7 @@ enum OperandClass {
OperandKernelProfilingInfo,
OperandCapability,
OperandCooperativeMatrixOperands,
OperandTensorAddressingOperands,
OperandOpcode,

View file

@ -50,6 +50,52 @@ class Float16 {
uint16_t val;
};
class FloatE5M2 {
public:
FloatE5M2(uint8_t v) : val(v) {}
FloatE5M2() {}
static bool isNan(const FloatE5M2& val) {
return ((val.val & 0x7C) == 0x7C) && ((val.val & 0x3) != 0);
}
// Returns true if the given value is any kind of infinity.
static bool isInfinity(const FloatE5M2& val) {
return ((val.val & 0x7C) == 0x7C) && ((val.val & 0x3) == 0);
}
FloatE5M2(const FloatE5M2& other) { val = other.val; }
uint8_t get_value() const { return val; }
// Returns the maximum normal value.
static FloatE5M2 max() { return FloatE5M2(0x7B); }
// Returns the lowest normal value.
static FloatE5M2 lowest() { return FloatE5M2(0xFB); }
private:
uint8_t val;
};
class FloatE4M3 {
public:
FloatE4M3(uint8_t v) : val(v) {}
FloatE4M3() {}
static bool isNan(const FloatE4M3& val) {
return (val.val & 0x7F) == 0x7F;
}
// Returns true if the given value is any kind of infinity.
static bool isInfinity(const FloatE4M3&) {
return false;
}
FloatE4M3(const FloatE4M3& other) { val = other.val; }
uint8_t get_value() const { return val; }
// Returns the maximum normal value.
static FloatE4M3 max() { return FloatE4M3(0x7E); }
// Returns the lowest normal value.
static FloatE4M3 lowest() { return FloatE4M3(0xFE); }
private:
uint8_t val;
};
// To specialize this type, you must override uint_type to define
// an unsigned integer that can fit your floating point type.
// You must also add a isNan function that returns true if
@ -95,6 +141,30 @@ struct FloatProxyTraits<Float16> {
static Float16 lowest() { return Float16::lowest(); }
};
template <>
struct FloatProxyTraits<FloatE5M2> {
typedef uint8_t uint_type;
static bool isNan(FloatE5M2 f) { return FloatE5M2::isNan(f); }
// Returns true if the given value is any kind of infinity.
static bool isInfinity(FloatE5M2 f) { return FloatE5M2::isInfinity(f); }
// Returns the maximum normal value.
static FloatE5M2 max() { return FloatE5M2::max(); }
// Returns the lowest normal value.
static FloatE5M2 lowest() { return FloatE5M2::lowest(); }
};
template <>
struct FloatProxyTraits<FloatE4M3> {
typedef uint8_t uint_type;
static bool isNan(FloatE4M3 f) { return FloatE4M3::isNan(f); }
// Returns true if the given value is any kind of infinity.
static bool isInfinity(FloatE4M3 f) { return FloatE4M3::isInfinity(f); }
// Returns the maximum normal value.
static FloatE4M3 max() { return FloatE4M3::max(); }
// Returns the lowest normal value.
static FloatE4M3 lowest() { return FloatE4M3::lowest(); }
};
// Since copying a floating point number (especially if it is NaN)
// does not guarantee that bits are preserved, this class lets us
// store the type and use it as a float when necessary.
@ -182,6 +252,7 @@ struct HexFloatTraits {
// The bias of the exponent. (How much we need to subtract from the stored
// value to get the correct value.)
static const uint32_t exponent_bias = 0;
static bool supportsInfinity() { return true; }
};
// Traits for IEEE float.
@ -196,6 +267,7 @@ struct HexFloatTraits<FloatProxy<float>> {
static const uint_type num_exponent_bits = 8;
static const uint_type num_fraction_bits = 23;
static const uint_type exponent_bias = 127;
static bool supportsInfinity() { return true; }
};
// Traits for IEEE double.
@ -210,6 +282,7 @@ struct HexFloatTraits<FloatProxy<double>> {
static const uint_type num_exponent_bits = 11;
static const uint_type num_fraction_bits = 52;
static const uint_type exponent_bias = 1023;
static bool supportsInfinity() { return true; }
};
// Traits for IEEE half.
@ -224,6 +297,33 @@ struct HexFloatTraits<FloatProxy<Float16>> {
static const uint_type num_exponent_bits = 5;
static const uint_type num_fraction_bits = 10;
static const uint_type exponent_bias = 15;
static bool supportsInfinity() { return true; }
};
template <>
struct HexFloatTraits<FloatProxy<FloatE5M2>> {
typedef uint8_t uint_type;
typedef int8_t int_type;
typedef uint8_t underlying_type;
typedef uint8_t native_type;
static const uint_type num_used_bits = 8;
static const uint_type num_exponent_bits = 5;
static const uint_type num_fraction_bits = 2;
static const uint_type exponent_bias = 15;
static bool supportsInfinity() { return true; }
};
template <>
struct HexFloatTraits<FloatProxy<FloatE4M3>> {
typedef uint8_t uint_type;
typedef int8_t int_type;
typedef uint8_t underlying_type;
typedef uint8_t native_type;
static const uint_type num_used_bits = 8;
static const uint_type num_exponent_bits = 4;
static const uint_type num_fraction_bits = 3;
static const uint_type exponent_bias = 7;
static bool supportsInfinity() { return false; }
};
enum round_direction {
@ -243,6 +343,7 @@ class HexFloat {
typedef typename Traits::int_type int_type;
typedef typename Traits::underlying_type underlying_type;
typedef typename Traits::native_type native_type;
using Traits_T = Traits;
explicit HexFloat(T f) : value_(f) {}
@ -584,14 +685,22 @@ class HexFloat {
(getBits() & exponent_mask) == exponent_mask && significand != 0;
bool is_inf =
!is_nan &&
((exponent + carried) > static_cast<int_type>(other_T::exponent_bias) ||
(((exponent + carried) > static_cast<int_type>(other_T::exponent_bias) && other_T::Traits_T::supportsInfinity()) ||
((exponent + carried) > static_cast<int_type>(other_T::exponent_bias + 1) && !other_T::Traits_T::supportsInfinity()) ||
(significand == 0 && (getBits() & exponent_mask) == exponent_mask));
// If we are Nan or Inf we should pass that through.
if (is_inf) {
other.set_value(BitwiseCast<typename other_T::underlying_type>(
static_cast<typename other_T::uint_type>(
(negate ? other_T::sign_mask : 0) | other_T::exponent_mask)));
if (other_T::Traits_T::supportsInfinity()) {
// encode as +/-inf
other.set_value(BitwiseCast<typename other_T::underlying_type>(
static_cast<typename other_T::uint_type>(
(negate ? other_T::sign_mask : 0) | other_T::exponent_mask)));
} else {
// encode as +/-nan
other.set_value(BitwiseCast<typename other_T::underlying_type>(
static_cast<typename other_T::uint_type>(negate ? ~0 : ~other_T::sign_mask)));
}
return;
}
if (is_nan) {

View file

@ -47,7 +47,7 @@
#ifndef spvIR_H
#define spvIR_H
#include "spirv.hpp"
#include "spirv.hpp11"
#include <algorithm>
#include <cassert>
@ -67,7 +67,7 @@ class Module;
const Id NoResult = 0;
const Id NoType = 0;
const Decoration NoPrecision = DecorationMax;
const Decoration NoPrecision = Decoration::Max;
#ifdef __GNUC__
# define POTENTIALLY_UNUSED __attribute__((unused))
@ -77,15 +77,19 @@ const Decoration NoPrecision = DecorationMax;
POTENTIALLY_UNUSED
const MemorySemanticsMask MemorySemanticsAllMemory =
(MemorySemanticsMask)(MemorySemanticsUniformMemoryMask |
MemorySemanticsWorkgroupMemoryMask |
MemorySemanticsAtomicCounterMemoryMask |
MemorySemanticsImageMemoryMask);
(MemorySemanticsMask)(MemorySemanticsMask::UniformMemory |
MemorySemanticsMask::WorkgroupMemory |
MemorySemanticsMask::AtomicCounterMemory |
MemorySemanticsMask::ImageMemory);
struct IdImmediate {
bool isId; // true if word is an Id, false if word is an immediate
unsigned word;
IdImmediate(bool i, unsigned w) : isId(i), word(w) {}
IdImmediate(bool i, spv::MemoryAccessMask w) : isId(i), word((unsigned)w) {}
IdImmediate(bool i, spv::TensorAddressingOperandsMask w) : isId(i), word((unsigned)w) {}
IdImmediate(bool i, spv::ImageOperandsMask w) : isId(i), word((unsigned)w) {}
IdImmediate(bool i, spv::CooperativeMatrixOperandsMask w) : isId(i), word((unsigned)w) {}
};
//
@ -107,10 +111,79 @@ public:
operands.push_back(id);
idOperand.push_back(true);
}
// This method is potentially dangerous as it can break assumptions
// about SSA and lack of forward references.
void setIdOperand(unsigned idx, Id id) {
assert(id);
assert(idOperand[idx]);
operands[idx] = id;
}
void addImmediateOperand(unsigned int immediate) {
operands.push_back(immediate);
idOperand.push_back(false);
}
void addImmediateOperand(spv::StorageClass immediate) {
addImmediateOperand((unsigned)immediate);
}
void addImmediateOperand(spv::ExecutionMode immediate) {
addImmediateOperand((unsigned)immediate);
}
void addImmediateOperand(spv::ExecutionModel immediate) {
addImmediateOperand((unsigned)immediate);
}
void addImmediateOperand(spv::Decoration immediate) {
addImmediateOperand((unsigned)immediate);
}
void addImmediateOperand(spv::LinkageType immediate) {
addImmediateOperand((unsigned)immediate);
}
void addImmediateOperand(spv::MemoryAccessMask immediate) {
addImmediateOperand((unsigned)immediate);
}
void addImmediateOperand(spv::Capability immediate) {
addImmediateOperand((unsigned)immediate);
}
void addImmediateOperand(spv::AddressingModel immediate) {
addImmediateOperand((unsigned)immediate);
}
void addImmediateOperand(spv::MemoryModel immediate) {
addImmediateOperand((unsigned)immediate);
}
void addImmediateOperand(spv::FPEncoding immediate) {
addImmediateOperand((unsigned)immediate);
}
void addImmediateOperand(spv::SourceLanguage immediate) {
addImmediateOperand((unsigned)immediate);
}
void addImmediateOperand(spv::Dim immediate) {
addImmediateOperand((unsigned)immediate);
}
void addImmediateOperand(spv::FunctionControlMask immediate){
addImmediateOperand((unsigned)immediate);
}
void addImmediateOperand(spv::SelectionControlMask immediate) {
addImmediateOperand((unsigned)immediate);
}
void addImmediateOperand(spv::LoopControlMask immediate) {
addImmediateOperand((unsigned)immediate);
}
void setImmediateOperand(unsigned idx, unsigned int immediate) {
assert(!idOperand[idx]);
operands[idx] = immediate;
@ -120,7 +193,7 @@ public:
{
unsigned int word = 0;
unsigned int shiftAmount = 0;
char c;
unsigned char c;
do {
c = *(str++);
@ -170,7 +243,7 @@ public:
wordCount += (unsigned int)operands.size();
// Write out the beginning of the instruction
out.push_back(((wordCount) << WordCountShift) | opCode);
out.push_back(((wordCount) << WordCountShift) | (unsigned)opCode);
if (typeId)
out.push_back(typeId);
if (resultId)
@ -181,6 +254,15 @@ public:
out.push_back(operands[op]);
}
const char *getNameString() const {
if (opCode == Op::OpString) {
return (const char *)&operands[0];
} else {
assert(opCode == Op::OpName);
return (const char *)&operands[1];
}
}
protected:
Instruction(const Instruction&);
Id resultId;
@ -238,7 +320,7 @@ public:
void addLocalVariable(std::unique_ptr<Instruction> inst) { localVariables.push_back(std::move(inst)); }
const std::vector<Block*>& getPredecessors() const { return predecessors; }
const std::vector<Block*>& getSuccessors() const { return successors; }
const std::vector<std::unique_ptr<Instruction> >& getInstructions() const {
std::vector<std::unique_ptr<Instruction> >& getInstructions() {
return instructions;
}
const std::vector<std::unique_ptr<Instruction> >& getLocalVariables() const { return localVariables; }
@ -249,8 +331,8 @@ public:
if (instructions.size() < 2) return nullptr;
const Instruction* nextToLast = (instructions.cend() - 2)->get();
switch (nextToLast->getOpCode()) {
case OpSelectionMerge:
case OpLoopMerge:
case Op::OpSelectionMerge:
case Op::OpLoopMerge:
return nextToLast;
default:
return nullptr;
@ -267,7 +349,7 @@ public:
assert(instructions.size() > 0);
instructions.resize(1);
successors.clear();
addInstruction(std::unique_ptr<Instruction>(new Instruction(OpUnreachable)));
addInstruction(std::unique_ptr<Instruction>(new Instruction(Op::OpUnreachable)));
}
// Change this block into a canonical dead continue target branching to the
// given header ID. Delete instructions as necessary. A canonical dead continue
@ -281,7 +363,7 @@ public:
successors.clear();
// Add OpBranch back to the header.
assert(header != nullptr);
Instruction* branch = new Instruction(OpBranch);
Instruction* branch = new Instruction(Op::OpBranch);
branch->addIdOperand(header->getId());
addInstruction(std::unique_ptr<Instruction>(branch));
successors.push_back(header);
@ -290,14 +372,14 @@ public:
bool isTerminated() const
{
switch (instructions.back()->getOpCode()) {
case OpBranch:
case OpBranchConditional:
case OpSwitch:
case OpKill:
case OpTerminateInvocation:
case OpReturn:
case OpReturnValue:
case OpUnreachable:
case Op::OpBranch:
case Op::OpBranchConditional:
case Op::OpSwitch:
case Op::OpKill:
case Op::OpTerminateInvocation:
case Op::OpReturn:
case Op::OpReturnValue:
case Op::OpUnreachable:
return true;
default:
return false;
@ -394,14 +476,14 @@ public:
Id getFuncTypeId() const { return functionInstruction.getIdOperand(1); }
void setReturnPrecision(Decoration precision)
{
if (precision == DecorationRelaxedPrecision)
if (precision == Decoration::RelaxedPrecision)
reducedPrecisionReturn = true;
}
Decoration getReturnPrecision() const
{ return reducedPrecisionReturn ? DecorationRelaxedPrecision : NoPrecision; }
{ return reducedPrecisionReturn ? Decoration::RelaxedPrecision : NoPrecision; }
void setDebugLineInfo(Id fileName, int line, int column) {
lineInstruction = std::unique_ptr<Instruction>{new Instruction(OpLine)};
lineInstruction = std::unique_ptr<Instruction>{new Instruction(Op::OpLine)};
lineInstruction->reserveOperands(3);
lineInstruction->addIdOperand(fileName);
lineInstruction->addImmediateOperand(line);
@ -414,13 +496,13 @@ public:
void addParamPrecision(unsigned param, Decoration precision)
{
if (precision == DecorationRelaxedPrecision)
if (precision == Decoration::RelaxedPrecision)
reducedPrecisionParams.insert(param);
}
Decoration getParamPrecision(unsigned param) const
{
return reducedPrecisionParams.find(param) != reducedPrecisionParams.end() ?
DecorationRelaxedPrecision : NoPrecision;
Decoration::RelaxedPrecision : NoPrecision;
}
void dump(std::vector<unsigned int>& out) const
@ -439,7 +521,7 @@ public:
// Blocks
inReadableOrder(blocks[0], [&out](const Block* b, ReachReason, Block*) { b->dump(out); });
Instruction end(0, 0, OpFunctionEnd);
Instruction end(0, 0, Op::OpFunctionEnd);
end.dump(out);
}
@ -492,7 +574,7 @@ public:
}
StorageClass getStorageClass(Id typeId) const
{
assert(idToInstruction[typeId]->getOpCode() == spv::OpTypePointer);
assert(idToInstruction[typeId]->getOpCode() == spv::Op::OpTypePointer);
return (StorageClass)idToInstruction[typeId]->getImmediateOperand(0);
}
@ -521,13 +603,13 @@ protected:
// - all the OpFunctionParameter instructions
__inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, LinkageType linkage, const std::string& name, Module& parent)
: parent(parent), lineInstruction(nullptr),
functionInstruction(id, resultType, OpFunction), implicitThis(false),
functionInstruction(id, resultType, Op::OpFunction), implicitThis(false),
reducedPrecisionReturn(false),
linkType(linkage)
{
// OpFunction
functionInstruction.reserveOperands(2);
functionInstruction.addImmediateOperand(FunctionControlMaskNone);
functionInstruction.addImmediateOperand(FunctionControlMask::MaskNone);
functionInstruction.addIdOperand(functionType);
parent.mapInstruction(&functionInstruction);
parent.addFunction(this);
@ -536,13 +618,13 @@ __inline Function::Function(Id id, Id resultType, Id functionType, Id firstParam
Instruction* typeInst = parent.getInstruction(functionType);
int numParams = typeInst->getNumOperands() - 1;
for (int p = 0; p < numParams; ++p) {
Instruction* param = new Instruction(firstParamId + p, typeInst->getIdOperand(p + 1), OpFunctionParameter);
Instruction* param = new Instruction(firstParamId + p, typeInst->getIdOperand(p + 1), Op::OpFunctionParameter);
parent.mapInstruction(param);
parameterInstructions.push_back(param);
}
// If importing/exporting, save the function name (without the mangled parameters) for the linkage decoration
if (linkType != LinkageTypeMax) {
if (linkType != LinkageType::Max) {
exportName = name.substr(0, name.find_first_of('('));
}
}
@ -556,7 +638,7 @@ __inline void Function::addLocalVariable(std::unique_ptr<Instruction> inst)
__inline Block::Block(Id id, Function& parent) : parent(parent), unreachable(false)
{
instructions.push_back(std::unique_ptr<Instruction>(new Instruction(id, NoType, OpLabel)));
instructions.push_back(std::unique_ptr<Instruction>(new Instruction(id, NoType, Op::OpLabel)));
instructions.back()->setBlock(this);
parent.getParent().mapInstruction(instructions.back().get());
}

88
thirdparty/glslang/SPIRV/spvUtil.h vendored Normal file
View file

@ -0,0 +1,88 @@
//
// Copyright (C) 2025 Jan Kelemen
//
// 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.
//
#pragma once
#ifndef spvUtil_H
#define spvUtil_H
#include <cstdint>
#include <type_traits>
#include "spirv.hpp11"
namespace spv {
__inline uint32_t operator&(uint32_t value, spv::MemoryAccessMask mask) { return value & (unsigned)mask; }
__inline bool operator==(uint32_t word, spv::FPEncoding encoding) { return word == (unsigned)encoding; }
__inline bool operator!=(uint32_t word, spv::FPEncoding encoding) { return !(word == encoding); }
__inline bool operator==(uint32_t word, spv::Decoration decoration) { return word == (unsigned)decoration; }
__inline bool operator!=(uint32_t word, spv::Decoration decoration) { return !(word == decoration); }
__inline bool operator==(uint32_t word, spv::Op op) { return word == (unsigned)op; }
__inline bool operator!=(uint32_t word, spv::Op op) { return !(word == op); }
__inline bool operator==(uint32_t word, spv::StorageClass storage) { return word == (unsigned)storage; }
__inline bool operator!=(uint32_t word, spv::StorageClass storage) { return !(word == storage); }
__inline bool anySet(spv::MemoryAccessMask value, spv::MemoryAccessMask mask)
{
return (value & mask) != spv::MemoryAccessMask::MaskNone;
}
__inline bool anySet(spv::ImageOperandsMask value, spv::ImageOperandsMask mask)
{
return (value & mask) != spv::ImageOperandsMask::MaskNone;
}
__inline bool anySet(spv::MemorySemanticsMask value, spv::MemorySemanticsMask mask)
{
return (value & mask) != spv::MemorySemanticsMask::MaskNone;
}
__inline void addMask(uint32_t& word, spv::TensorAddressingOperandsMask mask) { word |= (unsigned)mask; }
__inline void addMask(spv::CooperativeMatrixOperandsMask& word, spv::CooperativeMatrixOperandsMask mask)
{
word = word | mask;
}
template<typename Enum, typename To = std::underlying_type_t<Enum>>
__inline To enumCast(Enum value)
{
return static_cast<To>(value);
}
}
#endif // spvUtil_H

View file

@ -49,6 +49,9 @@ enum TBasicType {
EbtFloat,
EbtDouble,
EbtFloat16,
EbtBFloat16,
EbtFloatE5M2,
EbtFloatE4M3,
EbtInt8,
EbtUint8,
EbtInt16,
@ -66,7 +69,13 @@ enum TBasicType {
EbtReference,
EbtRayQuery,
EbtHitObjectNV,
EbtHitObjectEXT,
EbtCoopmat,
EbtFunction,
EbtTensorLayoutNV,
EbtTensorViewNV,
EbtCoopvecNV,
EbtTensorARM,
// SPIR-V type defined by spirv_type
EbtSpirvType,
@ -103,6 +112,7 @@ enum TStorageQualifier {
EvqCallableData,
EvqCallableDataIn,
EvqHitObjectAttrNV,
EvqHitObjectAttrEXT,
EvqtaskPayloadSharedEXT,
@ -268,7 +278,6 @@ enum TBuiltInVariable {
EbvRayTmin,
EbvRayTmax,
EbvCullMask,
EbvHitT,
EbvHitKind,
EbvObjectToWorld,
EbvObjectToWorld3x4,
@ -276,6 +285,7 @@ enum TBuiltInVariable {
EbvWorldToObject3x4,
EbvIncomingRayFlags,
EbvCurrentRayTimeNV,
EbvClusterIDNV,
// barycentrics
EbvBaryCoordNV,
EbvBaryCoordNoPerspNV,
@ -296,6 +306,13 @@ enum TBuiltInVariable {
EbvHitKindFrontFacingMicroTriangleNV,
EbvHitKindBackFacingMicroTriangleNV,
EbvHitIsSphereNV,
EbvHitIsLSSNV,
EbvHitSpherePositionNV,
EbvHitSphereRadiusNV,
EbvHitLSSPositionsNV,
EbvHitLSSRadiiNV,
//GL_EXT_mesh_shader
EbvPrimitivePointIndicesEXT,
EbvPrimitiveLineIndicesEXT,
@ -332,6 +349,11 @@ enum TBuiltInVariable {
EbvPositionFetch,
// SPV_QCOM_tile_shading
EbvTileOffsetQCOM,
EbvTileDimensionQCOM,
EbvTileApronSizeQCOM,
EbvLast
};
@ -378,7 +400,8 @@ __inline const char* GetStorageQualifierString(TStorageQualifier q)
case EvqCallableData: return "callableDataNV"; break;
case EvqCallableDataIn: return "callableDataInNV"; break;
case EvqtaskPayloadSharedEXT: return "taskPayloadSharedEXT"; break;
case EvqHitObjectAttrNV:return "hitObjectAttributeNV"; break;
case EvqHitObjectAttrNV: return "hitObjectAttributeNV"; break;
case EvqHitObjectAttrEXT:return "hitObjectAttributeEXT"; break;
default: return "unknown qualifier";
}
}
@ -495,12 +518,12 @@ __inline const char* GetBuiltInVariableString(TBuiltInVariable v)
case EbvObjectRayDirection: return "ObjectRayDirectionNV";
case EbvRayTmin: return "ObjectRayTminNV";
case EbvRayTmax: return "ObjectRayTmaxNV";
case EbvHitT: return "HitTNV";
case EbvHitKind: return "HitKindNV";
case EbvIncomingRayFlags: return "IncomingRayFlagsNV";
case EbvObjectToWorld: return "ObjectToWorldNV";
case EbvWorldToObject: return "WorldToObjectNV";
case EbvCurrentRayTimeNV: return "CurrentRayTimeNV";
case EbvClusterIDNV: return "ClusterIDNV";
case EbvBaryCoordEXT:
case EbvBaryCoordNV: return "BaryCoordKHR";
@ -532,6 +555,13 @@ __inline const char* GetBuiltInVariableString(TBuiltInVariable v)
case EbvHitKindFrontFacingMicroTriangleNV: return "HitKindFrontFacingMicroTriangleNV";
case EbvHitKindBackFacingMicroTriangleNV: return "HitKindBackFacingMicroTriangleNV";
case EbvHitIsSphereNV: return "HitIsSphereNV";
case EbvHitIsLSSNV: return "HitIsLSSNV";
case EbvHitSpherePositionNV: return "HitSpherePositionNV";
case EbvHitSphereRadiusNV: return "HitSphereRadiusNV";
case EbvHitLSSPositionsNV: return "HitSpherePositionsNV";
case EbvHitLSSRadiiNV: return "HitLSSRadiiNV";
default: return "unknown built-in variable";
}
}
@ -584,12 +614,42 @@ __inline bool isTypeFloat(TBasicType type)
case EbtFloat:
case EbtDouble:
case EbtFloat16:
case EbtBFloat16:
case EbtFloatE5M2:
case EbtFloatE4M3:
return true;
default:
return false;
}
}
__inline uint32_t GetNumBits(TBasicType type)
{
switch (type) {
case EbtInt8:
case EbtUint8:
case EbtFloatE5M2:
case EbtFloatE4M3:
return 8;
case EbtBFloat16:
case EbtFloat16:
case EbtInt16:
case EbtUint16:
return 16;
case EbtInt:
case EbtUint:
case EbtFloat:
return 32;
case EbtDouble:
case EbtInt64:
case EbtUint64:
return 64;
default:
assert(false);
return 0;
}
}
__inline int getTypeRank(TBasicType type)
{
int res = -1;

View file

@ -94,6 +94,11 @@ std::string to_string(const T& val) {
#pragma warning(disable : 4201) // nameless union
#endif
// Allow compilation to WASI which does not support threads yet.
#ifdef __wasi__
#define DISABLE_THREAD_SUPPORT
#endif
#include "PoolAlloc.h"
//

View file

@ -899,6 +899,17 @@ public:
unionArray = new TConstUnionVector(size, val);
}
TConstUnionArray* clone() const
{
TConstUnionArray *copy = new TConstUnionArray(size());
if (unionArray) {
for (const auto i : *unionArray) {
copy->unionArray->push_back(i);
}
}
return copy;
}
int size() const { return unionArray ? (int)unionArray->size() : 0; }
TConstUnion& operator[](size_t index) { return (*unionArray)[index]; }
const TConstUnion& operator[](size_t index) const { return (*unionArray)[index]; }

View file

@ -95,10 +95,14 @@ public:
default: append("UNKNOWN ERROR: "); break;
}
}
void location(const TSourceLoc& loc, bool absolute = false) {
void location(const TSourceLoc& loc, bool absolute = false, bool displayColumn = false) {
const int maxSize = 24;
char locText[maxSize];
snprintf(locText, maxSize, ":%d", loc.line);
if (displayColumn) {
snprintf(locText, maxSize, ":%d:%d", loc.line, loc.column);
} else {
snprintf(locText, maxSize, ":%d", loc.line);
}
if(loc.getFilename() == nullptr && shaderFileName != nullptr && absolute) {
//append(std::filesystem::absolute(shaderFileName).string());
@ -119,9 +123,11 @@ public:
append(s);
append("\n");
}
void message(TPrefixType message, const char* s, const TSourceLoc& loc) {
void message(TPrefixType message, const char* s, const TSourceLoc& loc, bool absolute = false,
bool displayColumn = false)
{
prefix(message);
location(loc);
location(loc, absolute, displayColumn);
append(s);
append("\n");
}

View file

@ -61,6 +61,8 @@
// class as the allocator (second) template argument.
//
#include "visibility.h"
#include <cstddef>
#include <cstring>
#include <vector>
@ -179,6 +181,7 @@ public:
// Call allocate() to actually acquire memory. Returns nullptr if no memory
// available, otherwise a properly aligned pointer to 'numBytes' of memory.
//
GLSLANG_EXPORT_FOR_TESTS
void* allocate(size_t numBytes);
//
@ -255,6 +258,7 @@ private:
// different times. But a simple use is to have a global pop
// with everyone using the same global allocator.
//
GLSLANG_EXPORT_FOR_TESTS
extern TPoolAllocator& GetThreadPoolAllocator();
void SetThreadPoolAllocator(TPoolAllocator* poolAllocator);
@ -288,7 +292,7 @@ public:
template<class Other>
pool_allocator(const pool_allocator<Other>& p) : allocator(p.getAllocator()) { }
pointer allocate(size_type n) {
return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T))); }
pointer allocate(size_type n, const void*) {

View file

@ -85,6 +85,7 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
bool image : 1; // image, combined should be false
bool combined : 1; // true means texture is combined with a sampler, false means texture with no sampler
bool sampler : 1; // true means a pure sampler, other fields should be clear()
bool tileQCOM : 1; // is tile shading attachment
unsigned int vectorSize : 3; // vector return type size.
// Some languages support structures as sample results. Storing the whole structure in the
@ -127,6 +128,15 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
bool isShadow() const { return shadow; }
bool isArrayed() const { return arrayed; }
bool isTileAttachmentQCOM() const { return tileQCOM; }
// For combined sampler, returns the underlying texture. Otherwise, returns identity.
TSampler removeCombined() const {
TSampler result = *this;
result.combined = false;
return result;
}
void clear()
{
type = EbtVoid;
@ -139,6 +149,7 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
sampler = false;
external = false;
yuv = false;
tileQCOM = false;
#ifdef ENABLE_HLSL
clearReturnStruct();
@ -220,7 +231,8 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
isCombined() == right.isCombined() &&
isPureSampler() == right.isPureSampler() &&
isExternal() == right.isExternal() &&
isYuv() == right.isYuv()
isYuv() == right.isYuv() &&
isTileAttachmentQCOM() == right.isTileAttachmentQCOM()
#ifdef ENABLE_HLSL
&& getVectorSize() == right.getVectorSize() &&
getStructReturnIndex() == right.getStructReturnIndex()
@ -233,9 +245,9 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
return ! operator==(right);
}
TString getString() const
std::string getString() const
{
TString s;
std::string s;
if (isPureSampler()) {
s.append("sampler");
@ -246,6 +258,9 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
case EbtInt: s.append("i"); break;
case EbtUint: s.append("u"); break;
case EbtFloat16: s.append("f16"); break;
case EbtBFloat16: s.append("bf16"); break;
case EbtFloatE5M2: s.append("fe5m2"); break;
case EbtFloatE4M3: s.append("fe4m3"); break;
case EbtInt8: s.append("i8"); break;
case EbtUint16: s.append("u8"); break;
case EbtInt16: s.append("i16"); break;
@ -259,6 +274,8 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
s.append("attachmentEXT");
else if (isSubpass())
s.append("subpass");
else if (isTileAttachmentQCOM())
s.append("attachmentQCOM");
else
s.append("image");
} else if (isCombined()) {
@ -307,21 +324,6 @@ typedef TVector<TTypeLoc> TTypeList;
typedef TVector<TString*> TIdentifierList;
//
// Following are a series of helper enums for managing layouts and qualifiers,
// used for TPublicType, TType, others.
//
enum TLayoutPacking {
ElpNone,
ElpShared, // default, but different than saying nothing
ElpStd140,
ElpStd430,
ElpPacked,
ElpScalar,
ElpCount // If expanding, see bitfield width below
};
enum TLayoutMatrix {
ElmNone,
ElmRowMajor,
@ -567,6 +569,7 @@ public:
shadercallcoherent = false;
nonprivate = false;
volatil = false;
nontemporal = false;
restrict = false;
readonly = false;
writeonly = false;
@ -604,6 +607,7 @@ public:
bool writeonly : 1;
bool coherent : 1;
bool volatil : 1;
bool nontemporal : 1;
bool devicecoherent : 1;
bool queuefamilycoherent : 1;
bool workgroupcoherent : 1;
@ -618,14 +622,15 @@ public:
bool isRestrict() const { return restrict; }
bool isCoherent() const { return coherent; }
bool isVolatile() const { return volatil; }
bool isNonTemporal() const { return nontemporal; }
bool isSample() const { return sample; }
bool isMemory() const
{
return shadercallcoherent || subgroupcoherent || workgroupcoherent || queuefamilycoherent || devicecoherent || coherent || volatil || restrict || readonly || writeonly || nonprivate;
return shadercallcoherent || subgroupcoherent || workgroupcoherent || queuefamilycoherent || devicecoherent || coherent || volatil || nontemporal || restrict || readonly || writeonly || nonprivate;
}
bool isMemoryQualifierImageAndSSBOOnly() const
{
return shadercallcoherent || subgroupcoherent || workgroupcoherent || queuefamilycoherent || devicecoherent || coherent || volatil || restrict || readonly || writeonly;
return shadercallcoherent || subgroupcoherent || workgroupcoherent || queuefamilycoherent || devicecoherent || coherent || volatil || nontemporal || restrict || readonly || writeonly;
}
bool bufferReferenceNeedsVulkanMemoryModel() const
{
@ -820,6 +825,9 @@ public:
bool isHitObjectAttrNV() const {
return storage == EvqHitObjectAttrNV;
}
bool isHitObjectAttrEXT() const {
return storage == EvqHitObjectAttrEXT;
}
// True if this type of IO is supposed to be arrayed with extra level for per-vertex data
bool isArrayedIo(EShLanguage language) const
@ -856,11 +864,14 @@ public:
layoutFullQuads = false;
layoutQuadDeriv = false;
layoutHitObjectShaderRecordNV = false;
layoutHitObjectShaderRecordEXT = false;
layoutBindlessSampler = false;
layoutBindlessImage = false;
layoutBufferReferenceAlign = layoutBufferReferenceAlignEnd;
layoutFormat = ElfNone;
layoutTileAttachmentQCOM = false;
clearInterstageLayout();
layoutSpecConstantId = layoutSpecConstantIdEnd;
@ -954,6 +965,7 @@ public:
bool layoutFullQuads;
bool layoutQuadDeriv;
bool layoutHitObjectShaderRecordNV;
bool layoutHitObjectShaderRecordEXT;
// GL_EXT_spirv_intrinsics
int spirvStorageClass;
@ -962,6 +974,8 @@ public:
bool layoutBindlessSampler;
bool layoutBindlessImage;
bool layoutTileAttachmentQCOM;
bool hasUniformLayout() const
{
return hasMatrix() ||
@ -1063,6 +1077,7 @@ public:
bool isFullQuads() const { return layoutFullQuads; }
bool isQuadDeriv() const { return layoutQuadDeriv; }
bool hasHitObjectShaderRecordNV() const { return layoutHitObjectShaderRecordNV; }
bool hasHitObjectShaderRecordEXT() const { return layoutHitObjectShaderRecordEXT; }
bool hasBufferReference() const { return layoutBufferReference; }
bool hasBufferReferenceAlign() const
{
@ -1080,6 +1095,10 @@ public:
{
return layoutBindlessImage;
}
bool isTileAttachmentQCOM() const
{
return layoutTileAttachmentQCOM;
}
// GL_EXT_spirv_intrinsics
bool hasSpirvDecorate() const { return spirvDecorate != nullptr; }
@ -1293,7 +1312,7 @@ public:
}
};
// Qualifiers that don't need to be keep per object. They have shader scope, not object scope.
// Qualifiers that don't need to be kept per object. They have shader scope, not object scope.
// So, they will not be part of TType, TQualifier, etc.
struct TShaderQualifiers {
TLayoutGeometry geometry; // geometry/tessellation shader in/out primitives
@ -1323,6 +1342,9 @@ struct TShaderQualifiers {
bool layoutDerivativeGroupLinear; // true if layout derivative_group_linearNV set
int primitives; // mesh shader "max_primitives"DerivativeGroupLinear; // true if layout derivative_group_linearNV set
bool layoutPrimitiveCulling; // true if layout primitive_culling set
bool layoutNonCoherentTileAttachmentReadQCOM; // fragment shaders -- per object
int layoutTileShadingRateQCOM[3]; // compute shader
bool layoutTileShadingRateQCOMNotDefault[3]; // compute shader
TLayoutDepth getDepth() const { return layoutDepth; }
TLayoutStencil getStencil() const { return layoutStencil; }
@ -1359,6 +1381,13 @@ struct TShaderQualifiers {
layoutDerivativeGroupQuads = false;
layoutDerivativeGroupLinear = false;
layoutPrimitiveCulling = false;
layoutNonCoherentTileAttachmentReadQCOM = false;
layoutTileShadingRateQCOM[0] = 0;
layoutTileShadingRateQCOM[1] = 0;
layoutTileShadingRateQCOM[2] = 0;
layoutTileShadingRateQCOMNotDefault[0] = false;
layoutTileShadingRateQCOMNotDefault[1] = false;
layoutTileShadingRateQCOMNotDefault[2] = false;
primitives = TQualifier::layoutNotSet;
interlockOrdering = EioNone;
}
@ -1428,6 +1457,15 @@ struct TShaderQualifiers {
interlockOrdering = src.interlockOrdering;
if (src.layoutPrimitiveCulling)
layoutPrimitiveCulling = src.layoutPrimitiveCulling;
if (src.layoutNonCoherentTileAttachmentReadQCOM)
layoutNonCoherentTileAttachmentReadQCOM = src.layoutNonCoherentTileAttachmentReadQCOM;
for (int i = 0; i < 3; ++i) {
if (src.layoutTileShadingRateQCOM[i] > 1)
layoutTileShadingRateQCOM[i] = src.layoutTileShadingRateQCOM[i];
}
for (int i = 0; i < 3; ++i) {
layoutTileShadingRateQCOMNotDefault[i] = src.layoutTileShadingRateQCOMNotDefault[i] || layoutTileShadingRateQCOMNotDefault[i];
}
}
};
@ -1475,6 +1513,9 @@ public:
uint32_t matrixRows : 4;
bool coopmatNV : 1;
bool coopmatKHR : 1;
bool coopvecNV : 1;
bool tileAttachmentQCOM: 1;
uint32_t tensorRankARM : 4;
TArraySizes* arraySizes;
const TType* userDef;
TSourceLoc loc;
@ -1485,6 +1526,12 @@ public:
bool isCoopmat() const { return coopmatNV || coopmatKHR; }
bool isCoopmatNV() const { return coopmatNV; }
bool isCoopmatKHR() const { return coopmatKHR; }
bool isCoopvecNV() const { return coopvecNV; }
bool isTensorARM() const { return tensorRankARM; }
bool hasTypeParameter() const { return isCoopmat() || isCoopvecNV() || isTensorARM(); }
bool isTensorLayoutNV() const { return basicType == EbtTensorLayoutNV; }
bool isTensorViewNV() const { return basicType == EbtTensorViewNV; }
void initType(const TSourceLoc& l)
{
@ -1498,6 +1545,9 @@ public:
typeParameters = nullptr;
coopmatNV = false;
coopmatKHR = false;
coopvecNV = false;
tileAttachmentQCOM = false;
tensorRankARM = 0;
spirvType = nullptr;
}
@ -1557,8 +1607,8 @@ public:
// for "empty" type (no args) or simple scalar/vector/matrix
explicit TType(TBasicType t = EbtVoid, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0,
bool isVector = false) :
basicType(t), vectorSize(static_cast<uint32_t>(vs) & 0b1111), matrixCols(static_cast<uint32_t>(mc) & 0b1111), matrixRows(static_cast<uint32_t>(mr) & 0b1111), vector1(isVector && vs == 1), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false),
arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr),
basicType(t), vectorSize(static_cast<uint32_t>(vs) & 0b1111), matrixCols(static_cast<uint32_t>(mc) & 0b1111), matrixRows(static_cast<uint32_t>(mr) & 0b1111), vector1(isVector && vs == 1), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false), coopvecNV(false),
tileAttachmentQCOM(false), tensorRankARM(0), arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr),
spirvType(nullptr)
{
assert(vs >= 0);
@ -1573,8 +1623,8 @@ public:
// for explicit precision qualifier
TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0,
bool isVector = false) :
basicType(t), vectorSize(static_cast<uint32_t>(vs) & 0b1111), matrixCols(static_cast<uint32_t>(mc) & 0b1111), matrixRows(static_cast<uint32_t>(mr) & 0b1111), vector1(isVector && vs == 1), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false),
arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr),
basicType(t), vectorSize(static_cast<uint32_t>(vs) & 0b1111), matrixCols(static_cast<uint32_t>(mc) & 0b1111), matrixRows(static_cast<uint32_t>(mr) & 0b1111), vector1(isVector && vs == 1), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false), coopvecNV(false),
tileAttachmentQCOM(false), tensorRankARM(0), arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr),
spirvType(nullptr)
{
assert(vs >= 0);
@ -1591,8 +1641,8 @@ public:
// for turning a TPublicType into a TType, using a shallow copy
explicit TType(const TPublicType& p) :
basicType(p.basicType),
vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), vector1(false), coopmatNV(p.coopmatNV), coopmatKHR(p.coopmatKHR), coopmatKHRuse(0), coopmatKHRUseValid(false),
arraySizes(p.arraySizes), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(p.typeParameters),
vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), vector1(false), coopmatNV(p.coopmatNV), coopmatKHR(p.coopmatKHR), coopmatKHRuse(0), coopmatKHRUseValid(false), coopvecNV(p.coopvecNV),
tileAttachmentQCOM(p.tileAttachmentQCOM), tensorRankARM(p.tensorRankARM), arraySizes(p.arraySizes), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(p.typeParameters),
spirvType(p.spirvType)
{
if (basicType == EbtSampler)
@ -1640,14 +1690,22 @@ public:
assert(dimSize >= 0);
coopmatKHRuse = static_cast<uint32_t>(dimSize) & 0b111;
coopmatKHRUseValid = true;
p.typeParameters->arraySizes->removeLastSize();
}
}
if (p.isCoopvecNV() && p.typeParameters) {
basicType = p.typeParameters->basicType;
}
if (p.isTensorARM() && p.typeParameters) {
basicType = p.typeParameters->basicType;
if (p.typeParameters->arraySizes->getNumDims() > 0) {
tensorRankARM = static_cast<uint32_t>(p.typeParameters->arraySizes->getDimSize(0)) & 0b1111;
}
}
}
// for construction of sampler types
TType(const TSampler& sampler, TStorageQualifier q = EvqUniform, TArraySizes* as = nullptr) :
basicType(EbtSampler), vectorSize(1u), matrixCols(0u), matrixRows(0u), vector1(false), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false),
arraySizes(as), structure(nullptr), fieldName(nullptr), typeName(nullptr),
basicType(EbtSampler), vectorSize(1u), matrixCols(0u), matrixRows(0u), vector1(false), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false), coopvecNV(false),
tileAttachmentQCOM(false), tensorRankARM(0), arraySizes(as), structure(nullptr), fieldName(nullptr), typeName(nullptr),
sampler(sampler), typeParameters(nullptr), spirvType(nullptr)
{
qualifier.clear();
@ -1689,19 +1747,23 @@ public:
// dereference from vector to scalar
vectorSize = 1;
vector1 = false;
} else if (isCoopMat()) {
} else if (isCoopMat() || isCoopVecNV()) {
coopmatNV = false;
coopmatKHR = false;
coopmatKHRuse = 0;
coopmatKHRUseValid = false;
coopvecNV = false;
typeParameters = nullptr;
} else if (isTileAttachmentQCOM()) {
tileAttachmentQCOM = false;
typeParameters = nullptr;
}
}
}
// for making structures, ...
TType(TTypeList* userDef, const TString& n) :
basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false),
arraySizes(nullptr), structure(userDef), fieldName(nullptr), typeParameters(nullptr),
basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false), coopvecNV(false),
tileAttachmentQCOM(false), tensorRankARM(0), arraySizes(nullptr), structure(userDef), fieldName(nullptr), typeParameters(nullptr),
spirvType(nullptr)
{
sampler.clear();
@ -1710,8 +1772,8 @@ public:
}
// For interface blocks
TType(TTypeList* userDef, const TString& n, const TQualifier& q) :
basicType(EbtBlock), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false),
qualifier(q), arraySizes(nullptr), structure(userDef), fieldName(nullptr), typeParameters(nullptr),
basicType(EbtBlock), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false), coopvecNV(false),
tileAttachmentQCOM(false), tensorRankARM(0), qualifier(q), arraySizes(nullptr), structure(userDef), fieldName(nullptr), typeParameters(nullptr),
spirvType(nullptr)
{
sampler.clear();
@ -1720,7 +1782,7 @@ public:
// for block reference (first parameter must be EbtReference)
explicit TType(TBasicType t, const TType &p, const TString& n) :
basicType(t), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false),
arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr),
tileAttachmentQCOM(false), tensorRankARM(0), arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr),
spirvType(nullptr)
{
assert(t == EbtReference);
@ -1758,6 +1820,9 @@ public:
coopmatKHR = copyOf.isCoopMatKHR();
coopmatKHRuse = copyOf.coopmatKHRuse;
coopmatKHRUseValid = copyOf.coopmatKHRUseValid;
coopvecNV = copyOf.isCoopVecNV();
tileAttachmentQCOM = copyOf.tileAttachmentQCOM;
tensorRankARM = copyOf.tensorRankARM;
}
// Make complete copy of the whole type graph rooted at 'copyOf'.
@ -1797,6 +1862,7 @@ public:
return *typeName;
}
virtual bool hasFieldName() const { return (fieldName != nullptr); }
virtual const TString& getFieldName() const
{
assert(fieldName);
@ -1841,7 +1907,7 @@ public:
virtual const TTypeParameters* getTypeParameters() const { return typeParameters; }
virtual TTypeParameters* getTypeParameters() { return typeParameters; }
virtual bool isScalar() const { return ! isVector() && ! isMatrix() && ! isStruct() && ! isArray(); }
virtual bool isScalar() const { return ! isVector() && ! isMatrix() && ! isStruct() && ! isArray() && ! isCoopVecNV(); }
virtual bool isScalarOrVec1() const { return isScalar() || vector1; }
virtual bool isScalarOrVector() const { return !isMatrix() && !isStruct() && !isArray(); }
virtual bool isVector() const { return vectorSize > 1u || vector1; }
@ -1855,7 +1921,8 @@ public:
virtual void updateImplicitArraySize(int size) { assert(isArray()); arraySizes->updateImplicitSize(size); }
virtual void setImplicitlySized(bool isImplicitSized) { arraySizes->setImplicitlySized(isImplicitSized); }
virtual bool isStruct() const { return basicType == EbtStruct || basicType == EbtBlock; }
virtual bool isFloatingDomain() const { return basicType == EbtFloat || basicType == EbtDouble || basicType == EbtFloat16; }
virtual bool isFloatingDomain() const { return basicType == EbtFloat || basicType == EbtDouble || basicType == EbtFloat16 ||
basicType == EbtBFloat16 || basicType == EbtFloatE5M2 || basicType == EbtFloatE4M3; }
virtual bool isIntegerDomain() const
{
switch (basicType) {
@ -1876,7 +1943,9 @@ public:
}
virtual bool isOpaque() const { return basicType == EbtSampler
|| basicType == EbtAtomicUint || basicType == EbtAccStruct || basicType == EbtRayQuery
|| basicType == EbtHitObjectNV; }
|| basicType == EbtHitObjectNV || basicType == EbtHitObjectEXT || isTileAttachmentQCOM()
|| isTensorARM();
}
virtual bool isBuiltIn() const { return getQualifier().builtIn != EbvNone; }
virtual bool isAttachmentEXT() const { return basicType == EbtSampler && getSampler().isAttachmentEXT(); }
@ -1892,10 +1961,18 @@ public:
bool isCoopMat() const { return coopmatNV || coopmatKHR; }
bool isCoopMatNV() const { return coopmatNV; }
bool isCoopMatKHR() const { return coopmatKHR; }
bool isCoopVecNV() const { return coopvecNV; }
bool isTileAttachmentQCOM() const { return tileAttachmentQCOM; }
bool isTensorARM() const { return tensorRankARM; }
bool hasTypeParameter() const { return isCoopMat() || isCoopVecNV() || isTensorARM(); }
int getTensorRankARM() const { return static_cast<int>(tensorRankARM); }
bool isReference() const { return getBasicType() == EbtReference; }
bool isSpirvType() const { return getBasicType() == EbtSpirvType; }
int getCoopMatKHRuse() const { return static_cast<int>(coopmatKHRuse); }
bool isTensorLayoutNV() const { return getBasicType() == EbtTensorLayoutNV; }
bool isTensorViewNV() const { return getBasicType() == EbtTensorViewNV; }
// return true if this type contains any subtype which satisfies the given predicate.
template <typename P>
bool contains(P predicate) const
@ -1950,12 +2027,20 @@ public:
virtual bool containsNonOpaque() const
{
if (isTensorARM()) {
// Tensors have a numerical basicType even though it is Opaque
return false;
}
const auto nonOpaque = [](const TType* t) {
switch (t->basicType) {
case EbtVoid:
case EbtFloat:
case EbtDouble:
case EbtFloat16:
case EbtBFloat16:
case EbtFloatE5M2:
case EbtFloatE4M3:
case EbtInt8:
case EbtUint8:
case EbtInt16:
@ -1988,6 +2073,14 @@ public:
{
return containsBasicType(EbtFloat16);
}
bool containsBFloat16() const
{
return containsBasicType(EbtBFloat16);
}
bool contains8BitFloat() const
{
return containsBasicType(EbtFloatE5M2) || containsBasicType(EbtFloatE4M3);
}
bool contains64BitInt() const
{
return containsBasicType(EbtInt64) || containsBasicType(EbtUint64);
@ -2004,6 +2097,10 @@ public:
{
return contains([](const TType* t) { return t->coopmatNV || t->coopmatKHR; } );
}
bool containsCoopVec() const
{
return contains([](const TType* t) { return t->coopvecNV; } );
}
bool containsReference() const
{
return containsBasicType(EbtReference);
@ -2105,6 +2202,9 @@ public:
case EbtVoid: return "void";
case EbtDouble: return "double";
case EbtFloat16: return "float16_t";
case EbtBFloat16: return "bfloat16_t";
case EbtFloatE5M2: return "floate5m2_t";
case EbtFloatE4M3: return "floate4m3_t";
case EbtInt8: return "int8_t";
case EbtUint8: return "uint8_t";
case EbtInt16: return "int16_t";
@ -2121,6 +2221,10 @@ public:
case EbtString: return "string";
case EbtSpirvType: return "spirv_type";
case EbtCoopmat: return "coopmat";
case EbtTensorLayoutNV: return "tensorLayoutNV";
case EbtTensorViewNV: return "tensorViewNV";
case EbtCoopvecNV: return "coopvecNV";
case EbtTensorARM: return "tensorARM";
default: return "unknown type";
}
}
@ -2226,7 +2330,7 @@ public:
appendStr(" layoutSecondaryViewportRelativeOffset=");
appendInt(qualifier.layoutSecondaryViewportRelativeOffset);
}
if (qualifier.layoutShaderRecord)
appendStr(" shaderRecordNV");
if (qualifier.layoutFullQuads)
@ -2235,6 +2339,8 @@ public:
appendStr(" quad_derivatives");
if (qualifier.layoutHitObjectShaderRecordNV)
appendStr(" hitobjectshaderrecordnv");
if (qualifier.layoutHitObjectShaderRecordEXT)
appendStr(" hitobjectshaderrecordext");
if (qualifier.layoutBindlessSampler)
appendStr(" layoutBindlessSampler");
@ -2289,6 +2395,8 @@ public:
appendStr(" nonprivate");
if (qualifier.volatil)
appendStr(" volatile");
if (qualifier.nontemporal)
appendStr(" nontemporal");
if (qualifier.restrict)
appendStr(" restrict");
if (qualifier.readonly)
@ -2431,6 +2539,18 @@ public:
appendStr(" ");
appendStr("coopmat");
}
if (isTensorLayoutNV()) {
appendStr(" ");
appendStr("tensorLayoutNV");
}
if (isTensorViewNV()) {
appendStr(" ");
appendStr("tensorViewNV");
}
if (isCoopVecNV()) {
appendStr(" ");
appendStr("coopvecNV");
}
appendStr("<");
for (int i = 0; i < (int)typeParameters->arraySizes->getNumDims(); ++i) {
@ -2438,10 +2558,6 @@ public:
if (i != (int)typeParameters->arraySizes->getNumDims() - 1)
appendStr(", ");
}
if (coopmatKHRUseValid) {
appendStr(", ");
appendInt(coopmatKHRuse);
}
appendStr(">");
}
if (getPrecision && qualifier.precision != EpqNone) {
@ -2494,7 +2610,7 @@ public:
TString getBasicTypeString() const
{
if (basicType == EbtSampler)
return sampler.getString();
return TString{sampler.getString()};
else
return getBasicString();
}
@ -2516,7 +2632,9 @@ public:
{
uint32_t components = 0;
if (getBasicType() == EbtStruct || getBasicType() == EbtBlock) {
if (isCoopVecNV()) {
components = typeParameters->arraySizes->getDimSize(0);
} else if (getBasicType() == EbtStruct || getBasicType() == EbtBlock) {
for (TTypeList::const_iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++)
components += ((*tl).type)->computeNumComponents();
} else if (matrixCols)
@ -2720,6 +2838,8 @@ public:
vector1 == right.vector1 &&
isCoopMatNV() == right.isCoopMatNV() &&
isCoopMatKHR() == right.isCoopMatKHR() &&
isCoopVecNV() == right.isCoopVecNV() &&
isTensorARM() == right.isTensorARM() &&
sameStructType(right, lpidx, rpidx) &&
sameReferenceType(right);
}
@ -2741,6 +2861,18 @@ public:
return false;
}
// See if a cooperative vector type parameter with unspecified parameters is
// an OK function parameter
bool coopVecParameterOK(const TType& right) const
{
if (isCoopVecNV() && right.isCoopVecNV()) {
return ((getBasicType() == right.getBasicType()) || (getBasicType() == EbtCoopvecNV) ||
(right.getBasicType() == EbtCoopvecNV)) &&
typeParameters == nullptr && right.typeParameters != nullptr;
}
return false;
}
bool sameCoopMatBaseType(const TType &right) const {
bool rv = false;
@ -2755,8 +2887,8 @@ public:
else
rv = false;
} else if (isCoopMatKHR() && right.isCoopMatKHR()) {
if (getBasicType() == EbtFloat || getBasicType() == EbtFloat16)
rv = right.getBasicType() == EbtFloat || right.getBasicType() == EbtFloat16 || right.getBasicType() == EbtCoopmat;
if (isFloatingDomain())
rv = right.isFloatingDomain() || right.getBasicType() == EbtCoopmat;
else if (getBasicType() == EbtUint || getBasicType() == EbtUint8 || getBasicType() == EbtUint16)
rv = right.getBasicType() == EbtUint || right.getBasicType() == EbtUint8 || right.getBasicType() == EbtUint16 || right.getBasicType() == EbtCoopmat;
else if (getBasicType() == EbtInt || getBasicType() == EbtInt8 || getBasicType() == EbtInt16)
@ -2767,24 +2899,69 @@ public:
return rv;
}
bool tensorParameterOK(const TType& right) const
{
if (isTensorLayoutNV()) {
return right.isTensorLayoutNV() && right.typeParameters == nullptr && typeParameters != nullptr;
}
if (isTensorViewNV()) {
return right.isTensorViewNV() && right.typeParameters == nullptr && typeParameters != nullptr;
}
if (isTensorARM()) {
return right.isTensorARM() && right.typeParameters == nullptr && typeParameters != nullptr;
}
return false;
}
bool sameTensorBaseTypeARM(const TType &right) const {
return (typeParameters == nullptr || right.typeParameters == nullptr ||
(tensorRankARM == right.tensorRankARM && getBasicType() == right.getBasicType()));
}
bool sameCoopVecBaseType(const TType &right) const {
bool rv = false;
if (isCoopVecNV() && right.isCoopVecNV()) {
if (getBasicType() == EbtFloat || getBasicType() == EbtFloat16)
rv = right.getBasicType() == EbtFloat || right.getBasicType() == EbtFloat16 || right.getBasicType() == EbtCoopvecNV;
else if (getBasicType() == EbtUint || getBasicType() == EbtUint8 || getBasicType() == EbtUint16)
rv = right.getBasicType() == EbtUint || right.getBasicType() == EbtUint8 || right.getBasicType() == EbtUint16 || right.getBasicType() == EbtCoopvecNV;
else if (getBasicType() == EbtInt || getBasicType() == EbtInt8 || getBasicType() == EbtInt16)
rv = right.getBasicType() == EbtInt || right.getBasicType() == EbtInt8 || right.getBasicType() == EbtInt16 || right.getBasicType() == EbtCoopvecNV;
else
rv = false;
}
return rv;
}
bool sameCoopMatUse(const TType &right) const {
return coopmatKHRuse == right.coopmatKHRuse;
}
bool sameCoopMatShapeAndUse(const TType &right) const
bool sameCoopMatShape(const TType &right) const
{
if (!isCoopMat() || !right.isCoopMat() || isCoopMatKHR() != right.isCoopMatKHR())
return false;
// Skip bit width type parameter (first array size) for coopmatNV
int firstArrayDimToCompare = isCoopMatNV() ? 1 : 0;
int lastArrayDimToCompare = typeParameters->arraySizes->getNumDims() - (isCoopMatKHR() ? 1 : 0);
for (int i = firstArrayDimToCompare; i < lastArrayDimToCompare; ++i) {
if (typeParameters->arraySizes->getDimSize(i) != right.typeParameters->arraySizes->getDimSize(i))
return false;
}
return true;
}
bool sameCoopMatShapeAndUse(const TType &right) const
{
if (!sameCoopMatShape(right))
return false;
if (coopmatKHRuse != right.coopmatKHRuse)
return false;
// Skip bit width type parameter (first array size) for coopmatNV
int firstArrayDimToCompare = isCoopMatNV() ? 1 : 0;
for (int i = firstArrayDimToCompare; i < typeParameters->arraySizes->getNumDims(); ++i) {
if (typeParameters->arraySizes->getDimSize(i) != right.typeParameters->arraySizes->getDimSize(i))
return false;
}
return true;
}
@ -2842,7 +3019,9 @@ protected:
typeParameters = new TTypeParameters;
typeParameters->arraySizes = new TArraySizes;
*typeParameters->arraySizes = *copyOf.typeParameters->arraySizes;
*typeParameters->spirvType = *copyOf.typeParameters->spirvType;
if (copyOf.typeParameters->spirvType) {
*typeParameters->spirvType = *copyOf.typeParameters->spirvType;
}
typeParameters->basicType = copyOf.basicType;
}
@ -2885,6 +3064,9 @@ protected:
bool coopmatKHR : 1;
uint32_t coopmatKHRuse : 3; // Accepts one of three values: 0, 1, 2 (gl_MatrixUseA, gl_MatrixUseB, gl_MatrixUseAccumulator)
bool coopmatKHRUseValid : 1; // True if coopmatKHRuse has been set
bool coopvecNV : 1;
bool tileAttachmentQCOM : 1;
uint32_t tensorRankARM : 4; // 0 means not a tensor; non-zero indicates the tensor rank.
TQualifier qualifier;
TArraySizes* arraySizes; // nullptr unless an array; can be shared across types

View file

@ -66,6 +66,7 @@ struct TArraySize {
return SameSpecializationConstants(node, rhs.node);
}
bool operator!=(const TArraySize& rhs) const { return !(*this == rhs); }
};
//
@ -198,6 +199,12 @@ struct TSmallArrayVector {
}
bool operator!=(const TSmallArrayVector& rhs) const { return ! operator==(rhs); }
const TArraySize& operator[](int index) const
{
assert(sizes && index < (int)sizes->size());
return (*sizes)[index];
}
protected:
TSmallArrayVector(const TSmallArrayVector&);
@ -336,6 +343,10 @@ struct TArraySizes {
return true;
}
const TArraySize& getArraySize(int index) const
{
return sizes[index];
}
void setVariablyIndexed() { variablyIndexed = true; }
bool isVariablyIndexed() const { return variablyIndexed; }

View file

@ -87,189 +87,9 @@ enum TOperator {
EOpDeclare, // Used by debugging to force declaration of variable in correct scope
// (u)int* -> bool
EOpConvInt8ToBool,
EOpConvUint8ToBool,
EOpConvInt16ToBool,
EOpConvUint16ToBool,
EOpConvIntToBool,
EOpConvUintToBool,
EOpConvInt64ToBool,
EOpConvUint64ToBool,
// float* -> bool
EOpConvFloat16ToBool,
EOpConvFloatToBool,
EOpConvDoubleToBool,
// bool -> (u)int*
EOpConvBoolToInt8,
EOpConvBoolToUint8,
EOpConvBoolToInt16,
EOpConvBoolToUint16,
EOpConvBoolToInt,
EOpConvBoolToUint,
EOpConvBoolToInt64,
EOpConvBoolToUint64,
// bool -> float*
EOpConvBoolToFloat16,
EOpConvBoolToFloat,
EOpConvBoolToDouble,
// int8_t -> (u)int*
EOpConvInt8ToInt16,
EOpConvInt8ToInt,
EOpConvInt8ToInt64,
EOpConvInt8ToUint8,
EOpConvInt8ToUint16,
EOpConvInt8ToUint,
EOpConvInt8ToUint64,
// uint8_t -> (u)int*
EOpConvUint8ToInt8,
EOpConvUint8ToInt16,
EOpConvUint8ToInt,
EOpConvUint8ToInt64,
EOpConvUint8ToUint16,
EOpConvUint8ToUint,
EOpConvUint8ToUint64,
// int8_t -> float*
EOpConvInt8ToFloat16,
EOpConvInt8ToFloat,
EOpConvInt8ToDouble,
// uint8_t -> float*
EOpConvUint8ToFloat16,
EOpConvUint8ToFloat,
EOpConvUint8ToDouble,
// int16_t -> (u)int*
EOpConvInt16ToInt8,
EOpConvInt16ToInt,
EOpConvInt16ToInt64,
EOpConvInt16ToUint8,
EOpConvInt16ToUint16,
EOpConvInt16ToUint,
EOpConvInt16ToUint64,
// uint16_t -> (u)int*
EOpConvUint16ToInt8,
EOpConvUint16ToInt16,
EOpConvUint16ToInt,
EOpConvUint16ToInt64,
EOpConvUint16ToUint8,
EOpConvUint16ToUint,
EOpConvUint16ToUint64,
// int16_t -> float*
EOpConvInt16ToFloat16,
EOpConvInt16ToFloat,
EOpConvInt16ToDouble,
// uint16_t -> float*
EOpConvUint16ToFloat16,
EOpConvUint16ToFloat,
EOpConvUint16ToDouble,
// int32_t -> (u)int*
EOpConvIntToInt8,
EOpConvIntToInt16,
EOpConvIntToInt64,
EOpConvIntToUint8,
EOpConvIntToUint16,
EOpConvIntToUint,
EOpConvIntToUint64,
// uint32_t -> (u)int*
EOpConvUintToInt8,
EOpConvUintToInt16,
EOpConvUintToInt,
EOpConvUintToInt64,
EOpConvUintToUint8,
EOpConvUintToUint16,
EOpConvUintToUint64,
// int32_t -> float*
EOpConvIntToFloat16,
EOpConvIntToFloat,
EOpConvIntToDouble,
// uint32_t -> float*
EOpConvUintToFloat16,
EOpConvUintToFloat,
EOpConvUintToDouble,
// int64_t -> (u)int*
EOpConvInt64ToInt8,
EOpConvInt64ToInt16,
EOpConvInt64ToInt,
EOpConvInt64ToUint8,
EOpConvInt64ToUint16,
EOpConvInt64ToUint,
EOpConvInt64ToUint64,
// uint64_t -> (u)int*
EOpConvUint64ToInt8,
EOpConvUint64ToInt16,
EOpConvUint64ToInt,
EOpConvUint64ToInt64,
EOpConvUint64ToUint8,
EOpConvUint64ToUint16,
EOpConvUint64ToUint,
// int64_t -> float*
EOpConvInt64ToFloat16,
EOpConvInt64ToFloat,
EOpConvInt64ToDouble,
// uint64_t -> float*
EOpConvUint64ToFloat16,
EOpConvUint64ToFloat,
EOpConvUint64ToDouble,
// float16_t -> (u)int*
EOpConvFloat16ToInt8,
EOpConvFloat16ToInt16,
EOpConvFloat16ToInt,
EOpConvFloat16ToInt64,
EOpConvFloat16ToUint8,
EOpConvFloat16ToUint16,
EOpConvFloat16ToUint,
EOpConvFloat16ToUint64,
// float16_t -> float*
EOpConvFloat16ToFloat,
EOpConvFloat16ToDouble,
// float -> (u)int*
EOpConvFloatToInt8,
EOpConvFloatToInt16,
EOpConvFloatToInt,
EOpConvFloatToInt64,
EOpConvFloatToUint8,
EOpConvFloatToUint16,
EOpConvFloatToUint,
EOpConvFloatToUint64,
// float -> float*
EOpConvFloatToFloat16,
EOpConvFloatToDouble,
// float64 _t-> (u)int*
EOpConvDoubleToInt8,
EOpConvDoubleToInt16,
EOpConvDoubleToInt,
EOpConvDoubleToInt64,
EOpConvDoubleToUint8,
EOpConvDoubleToUint16,
EOpConvDoubleToUint,
EOpConvDoubleToUint64,
// float64_t -> float*
EOpConvDoubleToFloat16,
EOpConvDoubleToFloat,
// Operator used to represent all conversions between int, float, and bool.
// The specific types are inferred from TBasicType.
EOpConvNumeric,
// uint64_t <-> pointer
EOpConvUint64ToPtr,
@ -567,6 +387,11 @@ enum TOperator {
EOpSubgroupPartitionedExclusiveXor,
EOpSubgroupGuardStop,
// Integer dot product
EOpDotPackedEXT,
EOpDotAccSatEXT,
EOpDotPackedAccSatEXT,
EOpMinInvocations,
EOpMaxInvocations,
@ -628,7 +453,35 @@ enum TOperator {
EOpCooperativeMatrixMulAdd,
EOpCooperativeMatrixLoadNV,
EOpCooperativeMatrixStoreNV,
EOpCooperativeMatrixLoadTensorNV,
EOpCooperativeMatrixStoreTensorNV,
EOpCooperativeMatrixMulAddNV,
EOpCooperativeMatrixReduceNV,
EOpCooperativeMatrixPerElementOpNV,
EOpCooperativeMatrixTransposeNV,
EOpCreateTensorLayoutNV,
EOpTensorLayoutSetBlockSizeNV,
EOpTensorLayoutSetDimensionNV,
EOpTensorLayoutSetStrideNV,
EOpTensorLayoutSliceNV,
EOpTensorLayoutSetClampValueNV,
EOpCreateTensorViewNV,
EOpTensorViewSetDimensionNV,
EOpTensorViewSetStrideNV,
EOpTensorViewSetClipNV,
EOpCooperativeVectorMatMulNV,
EOpCooperativeVectorMatMulAddNV,
EOpCooperativeVectorLoadNV,
EOpCooperativeVectorStoreNV,
EOpCooperativeVectorOuterProductAccumulateNV,
EOpCooperativeVectorReduceSumAccumulateNV,
EOpTensorReadARM,
EOpTensorWriteARM,
EOpTensorSizeARM,
EOpBeginInvocationInterlock, // Fragment only
EOpEndInvocationInterlock, // Fragment only
@ -762,13 +615,27 @@ enum TOperator {
EOpConstructF16Mat4x2,
EOpConstructF16Mat4x3,
EOpConstructF16Mat4x4,
EOpConstructBFloat16,
EOpConstructBF16Vec2,
EOpConstructBF16Vec3,
EOpConstructBF16Vec4,
EOpConstructFloatE5M2,
EOpConstructFloatE5M2Vec2,
EOpConstructFloatE5M2Vec3,
EOpConstructFloatE5M2Vec4,
EOpConstructFloatE4M3,
EOpConstructFloatE4M3Vec2,
EOpConstructFloatE4M3Vec3,
EOpConstructFloatE4M3Vec4,
EOpConstructStruct,
EOpConstructTextureSampler,
EOpConstructNonuniform, // expected to be transformed away, not present in final AST
EOpConstructReference,
EOpConstructCooperativeMatrixNV,
EOpConstructCooperativeMatrixKHR,
EOpConstructCooperativeVectorNV,
EOpConstructAccStruct,
EOpConstructSaturated,
EOpConstructGuardEnd,
//
@ -1008,6 +875,44 @@ enum TOperator {
EOpFetchMicroTriangleVertexPositionNV,
EOpFetchMicroTriangleVertexBarycentricNV,
//
// GL_EXT_shader_invocation_reorder
//
EOpHitObjectTraceRayEXT,
EOpHitObjectTraceRayMotionEXT,
EOpHitObjectRecordMissEXT,
EOpHitObjectRecordMissMotionEXT,
EOpHitObjectRecordEmptyEXT,
EOpHitObjectExecuteShaderEXT,
EOpHitObjectIsEmptyEXT,
EOpHitObjectIsMissEXT,
EOpHitObjectIsHitEXT,
EOpHitObjectGetRayTMinEXT,
EOpHitObjectGetRayTMaxEXT,
EOpHitObjectGetRayFlagsEXT,
EOpHitObjectGetObjectRayOriginEXT,
EOpHitObjectGetObjectRayDirectionEXT,
EOpHitObjectGetWorldRayOriginEXT,
EOpHitObjectGetWorldRayDirectionEXT,
EOpHitObjectGetWorldToObjectEXT,
EOpHitObjectGetObjectToWorldEXT,
EOpHitObjectGetInstanceCustomIndexEXT,
EOpHitObjectGetInstanceIdEXT,
EOpHitObjectGetGeometryIndexEXT,
EOpHitObjectGetPrimitiveIndexEXT,
EOpHitObjectGetHitKindEXT,
EOpHitObjectGetShaderBindingTableRecordIndexEXT,
EOpHitObjectSetShaderBindingTableRecordIndexEXT,
EOpHitObjectGetShaderRecordBufferHandleEXT,
EOpHitObjectGetAttributesEXT,
EOpHitObjectGetCurrentTimeEXT,
EOpReorderThreadEXT,
EOpHitObjectReorderExecuteEXT,
EOpHitObjectTraceReorderExecuteEXT,
EOpHitObjectTraceMotionReorderExecuteEXT,
EOpHitObjectRecordFromQueryEXT,
EOpHitObjectGetIntersectionTriangleVertexPositionsEXT,
// HLSL operations
//
@ -1117,14 +1022,44 @@ enum TOperator {
EOpImageBlockMatchWindowSADQCOM,
EOpImageBlockMatchGatherSSDQCOM,
EOpImageBlockMatchGatherSADQCOM,
// Cooperative Matrix Conversion
EOpBitCastArrayQCOM,
EOpExtractSubArrayQCOM,
EOpCompositeConstructCoopMatQCOM,
EOpCompositeExtractCoopMatQCOM,
// GL_NV_cluster_acceleration_structure
EOpRayQueryGetIntersectionClusterIdNV,
EOpHitObjectGetClusterIdNV,
// GL_NV_linear_swept_spheres
EOpRayQueryGetIntersectionSpherePositionNV,
EOpRayQueryGetIntersectionSphereRadiusNV,
EOpRayQueryGetIntersectionLSSHitValueNV,
EOpRayQueryGetIntersectionLSSPositionsNV,
EOpRayQueryGetIntersectionLSSRadiiNV,
EOpRayQueryIsSphereHitNV,
EOpRayQueryIsLSSHitNV,
EOpHitObjectGetSpherePositionNV,
EOpHitObjectGetSphereRadiusNV,
EOpHitObjectGetLSSPositionsNV,
EOpHitObjectGetLSSRadiiNV,
EOpHitObjectIsSphereHitNV,
EOpHitObjectIsLSSHitNV,
};
inline bool IsOpNumericConv(const TOperator op) {
return op == EOpConvNumeric;
}
enum TLinkType {
ELinkNone,
ELinkExport,
};
class TIntermTraverser;
class TIntermVariableDecl;
class TIntermOperator;
class TIntermAggregate;
class TIntermUnary;
@ -1153,6 +1088,7 @@ public:
virtual const glslang::TSourceLoc& getLoc() const { return loc; }
virtual void setLoc(const glslang::TSourceLoc& l) { loc = l; }
virtual void traverse(glslang::TIntermTraverser*) = 0;
virtual glslang::TIntermVariableDecl* getAsVariableDecl() { return nullptr; }
virtual glslang::TIntermTyped* getAsTyped() { return nullptr; }
virtual glslang::TIntermOperator* getAsOperator() { return nullptr; }
virtual glslang::TIntermConstantUnion* getAsConstantUnion() { return nullptr; }
@ -1166,6 +1102,7 @@ public:
virtual glslang::TIntermBranch* getAsBranchNode() { return nullptr; }
virtual glslang::TIntermLoop* getAsLoopNode() { return nullptr; }
virtual const glslang::TIntermVariableDecl* getAsVariableDecl() const { return nullptr; }
virtual const glslang::TIntermTyped* getAsTyped() const { return nullptr; }
virtual const glslang::TIntermOperator* getAsOperator() const { return nullptr; }
virtual const glslang::TIntermConstantUnion* getAsConstantUnion() const { return nullptr; }
@ -1196,6 +1133,37 @@ struct TIntermNodePair {
TIntermNode* node2;
};
//
// Represent declaration of a variable.
//
class TIntermVariableDecl : public TIntermNode {
public:
TIntermVariableDecl(TIntermSymbol* declSymbol, TIntermNode* initNode) : declSymbol(declSymbol), initNode(initNode)
{
}
TIntermVariableDecl(const TIntermVariableDecl&) = delete;
TIntermVariableDecl& operator=(const TIntermVariableDecl&) = delete;
void traverse(glslang::TIntermTraverser* traverser) override;
TIntermVariableDecl* getAsVariableDecl() override { return this; }
const TIntermVariableDecl* getAsVariableDecl() const override { return this; }
TIntermSymbol* getDeclSymbol() { return declSymbol; }
const TIntermSymbol* getDeclSymbol() const { return declSymbol; }
TIntermNode* getInitNode() { return initNode; }
const TIntermNode* getInitNode() const { return initNode; }
private:
// This symbol represents the declared variable at its declaration point.
// It's not traversed by default. To traverse it, the visitor needs to have includeDeclSymbol enabled.
TIntermSymbol* declSymbol = nullptr;
// The initializer
TIntermNode* initNode = nullptr;
};
//
// Intermediate class for nodes that have a type.
//
@ -1218,6 +1186,7 @@ public:
virtual int getVectorSize() const { return type.getVectorSize(); }
virtual int getMatrixCols() const { return type.getMatrixCols(); }
virtual int getMatrixRows() const { return type.getMatrixRows(); }
virtual int getTensorRankARM() const { return type.getTensorRankARM(); }
virtual bool isMatrix() const { return type.isMatrix(); }
virtual bool isArray() const { return type.isArray(); }
virtual bool isVector() const { return type.isVector(); }
@ -1239,7 +1208,7 @@ protected:
//
class TIntermLoop : public TIntermNode {
public:
TIntermLoop(TIntermNode* aBody, TIntermTyped* aTest, TIntermTyped* aTerminal, bool testFirst) :
TIntermLoop(TIntermNode* aBody, TIntermNode* aTest, TIntermTyped* aTerminal, bool testFirst) :
body(aBody),
test(aTest),
terminal(aTerminal),
@ -1258,10 +1227,20 @@ public:
virtual const TIntermLoop* getAsLoopNode() const { return this; }
virtual void traverse(TIntermTraverser*);
TIntermNode* getBody() const { return body; }
TIntermTyped* getTest() const { return test; }
TIntermNode* getTest() const { return test; }
TIntermTyped* getTerminal() const { return terminal; }
bool testFirst() const { return first; }
// Because the test node can be a declaration in a while loop, this function unwraps it to get the actual expression.
TIntermTyped* getTestExpr() const {
if (auto decl = test->getAsVariableDecl()) {
return decl->getInitNode()->getAsTyped();
}
else {
return test->getAsTyped();
}
}
void setUnroll() { unroll = true; }
void setDontUnroll() {
dontUnroll = true;
@ -1295,7 +1274,7 @@ public:
protected:
TIntermNode* body; // code to loop over
TIntermTyped* test; // exit condition associated with loop, could be 0 for 'for' loops
TIntermNode* test; // exit condition associated with loop, could be 0 for 'for' loops
TIntermTyped* terminal; // exists for for-loops
bool first; // true for while and for, not for do-while
bool unroll; // true if unroll requested
@ -1356,11 +1335,19 @@ public:
// if symbol is initialized as symbol(sym), the memory comes from the pool allocator of sym. If sym comes from
// per process threadPoolAllocator, then it causes increased memory usage per compile
// it is essential to use "symbol = sym" to assign to symbol
TIntermSymbol(long long i, const TString& n, const TType& t)
: TIntermTyped(t), id(i), flattenSubset(-1), constSubtree(nullptr) { name = n; }
TIntermSymbol(long long i, const TString& n, EShLanguage s, const TType& t, const TString* mn = nullptr)
: TIntermTyped(t), id(i), flattenSubset(-1), stage(s), constSubtree(nullptr) {
name = n;
if (mn) {
mangledName = *mn;
} else {
mangledName = n;
}
}
virtual long long getId() const { return id; }
virtual void changeId(long long i) { id = i; }
virtual const TString& getName() const { return name; }
virtual const TString& getMangledName() const { return mangledName; }
virtual void traverse(TIntermTraverser*);
virtual TIntermSymbol* getAsSymbolNode() { return this; }
virtual const TIntermSymbol* getAsSymbolNode() const { return this; }
@ -1376,11 +1363,14 @@ public:
// This is meant for cases where a node has already been constructed, and
// later on, it becomes necessary to switch to a different symbol.
virtual void switchId(long long newId) { id = newId; }
EShLanguage getStage() const { return stage; }
protected:
long long id; // the unique id of the symbol this node represents
int flattenSubset; // how deeply the flattened object rooted at id has been dereferenced
TString name; // the name of the symbol this node represents
EShLanguage stage;
TString mangledName; // mangled function name, or a copy of name if not a function
TConstUnionArray constArray; // if the symbol is a front-end compile-time constant, this is its value
TIntermTyped* constSubtree;
};
@ -1694,8 +1684,12 @@ typedef TVector<TStorageQualifier> TQualifierList;
//
class TIntermAggregate : public TIntermOperator {
public:
TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), pragmaTable(nullptr) { }
TIntermAggregate(TOperator o) : TIntermOperator(o), pragmaTable(nullptr) { }
TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), pragmaTable(nullptr) {
endLoc.init();
}
TIntermAggregate(TOperator o) : TIntermOperator(o), pragmaTable(nullptr) {
endLoc.init();
}
~TIntermAggregate() { delete pragmaTable; }
virtual TIntermAggregate* getAsAggregate() { return this; }
virtual const TIntermAggregate* getAsAggregate() const { return this; }
@ -1719,6 +1713,9 @@ public:
void setSpirvInstruction(const TSpirvInstruction& inst) { spirvInst = inst; }
const TSpirvInstruction& getSpirvInstruction() const { return spirvInst; }
void setEndLoc(TSourceLoc loc) { endLoc = loc; }
TSourceLoc getEndLoc() const { return endLoc; }
void setLinkType(TLinkType l) { linkType = l; }
TLinkType getLinkType() const { return linkType; }
protected:
@ -1733,6 +1730,10 @@ protected:
TPragmaTable* pragmaTable;
TSpirvInstruction spirvInst;
TLinkType linkType = ELinkNone;
// Marking the end source location of the aggregate.
// This is currently only set for a compound statement or a function body, pointing to '}'.
TSourceLoc endLoc;
};
//
@ -1834,24 +1835,26 @@ enum TVisit
class TIntermTraverser {
public:
POOL_ALLOCATOR_NEW_DELETE(glslang::GetThreadPoolAllocator())
TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) :
TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false, bool includeDeclSymbol = false) :
preVisit(preVisit),
inVisit(inVisit),
postVisit(postVisit),
rightToLeft(rightToLeft),
includeDeclSymbol(includeDeclSymbol),
depth(0),
maxDepth(0) { }
virtual ~TIntermTraverser() { }
virtual void visitSymbol(TIntermSymbol*) { }
virtual void visitConstantUnion(TIntermConstantUnion*) { }
virtual bool visitBinary(TVisit, TIntermBinary*) { return true; }
virtual bool visitUnary(TVisit, TIntermUnary*) { return true; }
virtual bool visitSelection(TVisit, TIntermSelection*) { return true; }
virtual bool visitAggregate(TVisit, TIntermAggregate*) { return true; }
virtual bool visitLoop(TVisit, TIntermLoop*) { return true; }
virtual bool visitBranch(TVisit, TIntermBranch*) { return true; }
virtual bool visitSwitch(TVisit, TIntermSwitch*) { return true; }
virtual void visitSymbol(TIntermSymbol*) { }
virtual void visitConstantUnion(TIntermConstantUnion*) { }
virtual bool visitBinary(TVisit, TIntermBinary*) { return true; }
virtual bool visitUnary(TVisit, TIntermUnary*) { return true; }
virtual bool visitSelection(TVisit, TIntermSelection*) { return true; }
virtual bool visitAggregate(TVisit, TIntermAggregate*) { return true; }
virtual bool visitLoop(TVisit, TIntermLoop*) { return true; }
virtual bool visitBranch(TVisit, TIntermBranch*) { return true; }
virtual bool visitSwitch(TVisit, TIntermSwitch*) { return true; }
virtual bool visitVariableDecl(TVisit, TIntermVariableDecl*) { return true; }
int getMaxDepth() const { return maxDepth; }
@ -1878,6 +1881,11 @@ public:
const bool postVisit;
const bool rightToLeft;
// Whether to traverse declaration symbols in the traversal.
// By default, declaration symbols are not visited in the traversal to avoid
// visiting them in SPIR-V generation where they are not needed.
const bool includeDeclSymbol;
protected:
TIntermTraverser& operator=(TIntermTraverser&);

View file

@ -0,0 +1,58 @@
//
// Copyright (C) 2023 LunarG, Inc.
//
// 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.
//
#ifdef GLSLANG_IS_SHARED_LIBRARY
#ifdef _WIN32
#ifdef GLSLANG_EXPORTING
#define GLSLANG_EXPORT __declspec(dllexport)
#else
#define GLSLANG_EXPORT __declspec(dllimport)
#endif
#elif __GNUC__ >= 4
#define GLSLANG_EXPORT __attribute__((visibility("default")))
#endif
#endif // GLSLANG_IS_SHARED_LIBRARY
#ifndef GLSLANG_EXPORT
#define GLSLANG_EXPORT
#endif
// Symbols marked with this macro are only meant for public use by the test suite
// and do not appear in publicly installed headers. They are not considered to be
// part of the glslang library ABI.
#ifdef GLSLANG_TEST_BUILD
#define GLSLANG_EXPORT_FOR_TESTS GLSLANG_EXPORT
#else
#define GLSLANG_EXPORT_FOR_TESTS
#endif

View file

@ -151,6 +151,9 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* right
case EbtDouble:
case EbtFloat:
case EbtFloat16:
case EbtBFloat16:
case EbtFloatE5M2:
case EbtFloatE4M3:
if (rightUnionArray[i].getDConst() != 0.0)
newConstArray[i].setDConst(leftUnionArray[i].getDConst() / rightUnionArray[i].getDConst());
else if (leftUnionArray[i].getDConst() > 0.0)
@ -490,11 +493,180 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType)
// Process component-wise operations
for (int i = 0; i < objectSize; i++) {
// First read the value and convert to i64/u64/f64/bool, then convert
// to the destination type (still 64b), then convert down to the
// destination size.
if (IsOpNumericConv(op)) {
enum ConvType { CONV_FLOAT, CONV_INT, CONV_UINT, CONV_BOOL };
ConvType srcType = CONV_UINT, dstType = CONV_UINT;
double valf = 0.0;
uint64_t valu = 0;
int64_t vali = 0;
bool valb = false;
switch (getType().getBasicType()) {
case EbtDouble:
case EbtFloat16:
case EbtBFloat16:
case EbtFloatE5M2:
case EbtFloatE4M3:
case EbtFloat:
valf = unionArray[i].getDConst();
srcType = CONV_FLOAT;
break;
case EbtInt8:
vali = unionArray[i].getI8Const();
srcType = CONV_INT;
break;
case EbtInt16:
vali = unionArray[i].getI16Const();
srcType = CONV_INT;
break;
case EbtInt:
vali = unionArray[i].getIConst();
srcType = CONV_INT;
break;
case EbtInt64:
vali = unionArray[i].getI64Const();
srcType = CONV_INT;
break;
case EbtUint8:
valu = unionArray[i].getU8Const();
srcType = CONV_UINT;
break;
case EbtUint16:
valu = unionArray[i].getU16Const();
srcType = CONV_UINT;
break;
case EbtUint:
valu = unionArray[i].getUConst();
srcType = CONV_UINT;
break;
case EbtUint64:
valu = unionArray[i].getU64Const();
srcType = CONV_UINT;
break;
case EbtBool:
valb = unionArray[i].getBConst();
srcType = CONV_BOOL;
break;
default:
assert(0);
break;
}
switch (returnType.getBasicType()) {
case EbtDouble:
case EbtFloat16:
case EbtBFloat16:
case EbtFloatE5M2:
case EbtFloatE4M3:
case EbtFloat:
dstType = CONV_FLOAT;
break;
case EbtInt8:
case EbtInt16:
case EbtInt:
case EbtInt64:
dstType = CONV_INT;
break;
case EbtUint8:
case EbtUint16:
case EbtUint:
case EbtUint64:
dstType = CONV_UINT;
break;
case EbtBool:
dstType = CONV_BOOL;
break;
default:
assert(0);
break;
}
if (dstType == CONV_BOOL) {
switch (srcType) {
case CONV_FLOAT:
valb = (valf != 0.0); break;
case CONV_INT:
valb = (vali != 0.0); break;
case CONV_UINT:
valb = (valu != 0.0); break;
default:
break;
}
} else if (dstType == CONV_FLOAT) {
switch (srcType) {
case CONV_BOOL:
valf = (double)valb; break;
case CONV_INT:
valf = (double)vali; break;
case CONV_UINT:
valf = (double)valu; break;
default:
break;
}
} else if (dstType == CONV_INT) {
switch (srcType) {
case CONV_BOOL:
vali = (int64_t)valb; break;
case CONV_FLOAT:
vali = (int64_t)valf; break;
case CONV_UINT:
vali = (int64_t)valu; break;
default:
break;
}
} else if (dstType == CONV_UINT) {
switch (srcType) {
case CONV_BOOL:
valu = (uint64_t)valb; break;
case CONV_FLOAT:
valu = (uint64_t)valf; break;
case CONV_INT:
valu = (uint64_t)vali; break;
default:
break;
}
}
switch (returnType.getBasicType()) {
case EbtDouble:
case EbtFloat16:
case EbtBFloat16:
case EbtFloatE5M2:
case EbtFloatE4M3:
case EbtFloat:
newConstArray[i].setDConst(valf); break;
case EbtInt8:
newConstArray[i].setI8Const(static_cast<int8_t>(vali)); break;
case EbtInt16:
newConstArray[i].setI16Const(static_cast<int16_t>(vali)); break;
case EbtInt:
newConstArray[i].setIConst(static_cast<int32_t>(vali)); break;
case EbtInt64:
newConstArray[i].setI64Const(vali); break;
case EbtUint8:
newConstArray[i].setU8Const(static_cast<uint8_t>(valu)); break;
case EbtUint16:
newConstArray[i].setU16Const(static_cast<uint16_t>(valu)); break;
case EbtUint:
newConstArray[i].setUConst(static_cast<uint32_t>(valu)); break;
case EbtUint64:
newConstArray[i].setU64Const(valu); break;
case EbtBool:
newConstArray[i].setBConst(valb); break;
default:
assert(0);
break;
}
continue;
}
switch (op) {
case EOpNegative:
switch (getType().getBasicType()) {
case EbtDouble:
case EbtFloat16:
case EbtBFloat16:
case EbtFloatE5M2:
case EbtFloatE4M3:
case EbtFloat: newConstArray[i].setDConst(-unionArray[i].getDConst()); break;
// Note: avoid UBSAN error regarding negating 0x80000000
case EbtInt: newConstArray[i].setIConst(
@ -507,7 +679,11 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType)
case EbtUint8: newConstArray[i].setU8Const(static_cast<unsigned int>(-static_cast<signed int>(unionArray[i].getU8Const()))); break;
case EbtInt16: newConstArray[i].setI16Const(-unionArray[i].getI16Const()); break;
case EbtUint16:newConstArray[i].setU16Const(static_cast<unsigned int>(-static_cast<signed int>(unionArray[i].getU16Const()))); break;
case EbtInt64: newConstArray[i].setI64Const(-unionArray[i].getI64Const()); break;
case EbtInt64: {
int64_t i64val = unionArray[i].getI64Const();
newConstArray[i].setI64Const(i64val == INT64_MIN ? INT64_MIN : -i64val);
break;
}
case EbtUint64: newConstArray[i].setU64Const(static_cast<unsigned long long>(-static_cast<long long>(unionArray[i].getU64Const()))); break;
default:
return nullptr;
@ -637,277 +813,6 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType)
break;
}
case EOpConvIntToBool:
newConstArray[i].setBConst(unionArray[i].getIConst() != 0); break;
case EOpConvUintToBool:
newConstArray[i].setBConst(unionArray[i].getUConst() != 0); break;
case EOpConvBoolToInt:
newConstArray[i].setIConst(unionArray[i].getBConst()); break;
case EOpConvBoolToUint:
newConstArray[i].setUConst(unionArray[i].getBConst()); break;
case EOpConvIntToUint:
newConstArray[i].setUConst(unionArray[i].getIConst()); break;
case EOpConvUintToInt:
newConstArray[i].setIConst(unionArray[i].getUConst()); break;
case EOpConvFloatToBool:
case EOpConvDoubleToBool:
newConstArray[i].setBConst(unionArray[i].getDConst() != 0); break;
case EOpConvBoolToFloat:
case EOpConvBoolToDouble:
newConstArray[i].setDConst(unionArray[i].getBConst()); break;
case EOpConvIntToFloat:
case EOpConvIntToDouble:
newConstArray[i].setDConst(unionArray[i].getIConst()); break;
case EOpConvUintToFloat:
case EOpConvUintToDouble:
newConstArray[i].setDConst(unionArray[i].getUConst()); break;
case EOpConvDoubleToFloat:
case EOpConvFloatToDouble:
newConstArray[i].setDConst(unionArray[i].getDConst()); break;
case EOpConvFloatToUint:
case EOpConvDoubleToUint:
newConstArray[i].setUConst(static_cast<unsigned int>(unionArray[i].getDConst())); break;
case EOpConvFloatToInt:
case EOpConvDoubleToInt:
newConstArray[i].setIConst(static_cast<int>(unionArray[i].getDConst())); break;
case EOpConvInt8ToBool:
newConstArray[i].setBConst(unionArray[i].getI8Const() != 0); break;
case EOpConvUint8ToBool:
newConstArray[i].setBConst(unionArray[i].getU8Const() != 0); break;
case EOpConvInt16ToBool:
newConstArray[i].setBConst(unionArray[i].getI16Const() != 0); break;
case EOpConvUint16ToBool:
newConstArray[i].setBConst(unionArray[i].getU16Const() != 0); break;
case EOpConvInt64ToBool:
newConstArray[i].setBConst(unionArray[i].getI64Const() != 0); break;
case EOpConvUint64ToBool:
newConstArray[i].setBConst(unionArray[i].getU64Const() != 0); break;
case EOpConvFloat16ToBool:
newConstArray[i].setBConst(unionArray[i].getDConst() != 0); break;
case EOpConvBoolToInt8:
newConstArray[i].setI8Const(unionArray[i].getBConst()); break;
case EOpConvBoolToUint8:
newConstArray[i].setU8Const(unionArray[i].getBConst()); break;
case EOpConvBoolToInt16:
newConstArray[i].setI16Const(unionArray[i].getBConst()); break;
case EOpConvBoolToUint16:
newConstArray[i].setU16Const(unionArray[i].getBConst()); break;
case EOpConvBoolToInt64:
newConstArray[i].setI64Const(unionArray[i].getBConst()); break;
case EOpConvBoolToUint64:
newConstArray[i].setU64Const(unionArray[i].getBConst()); break;
case EOpConvBoolToFloat16:
newConstArray[i].setDConst(unionArray[i].getBConst()); break;
case EOpConvInt8ToInt16:
newConstArray[i].setI16Const(unionArray[i].getI8Const()); break;
case EOpConvInt8ToInt:
newConstArray[i].setIConst(unionArray[i].getI8Const()); break;
case EOpConvInt8ToInt64:
newConstArray[i].setI64Const(unionArray[i].getI8Const()); break;
case EOpConvInt8ToUint8:
newConstArray[i].setU8Const(unionArray[i].getI8Const()); break;
case EOpConvInt8ToUint16:
newConstArray[i].setU16Const(unionArray[i].getI8Const()); break;
case EOpConvInt8ToUint:
newConstArray[i].setUConst(unionArray[i].getI8Const()); break;
case EOpConvInt8ToUint64:
newConstArray[i].setU64Const(unionArray[i].getI8Const()); break;
case EOpConvUint8ToInt8:
newConstArray[i].setI8Const(unionArray[i].getU8Const()); break;
case EOpConvUint8ToInt16:
newConstArray[i].setI16Const(unionArray[i].getU8Const()); break;
case EOpConvUint8ToInt:
newConstArray[i].setIConst(unionArray[i].getU8Const()); break;
case EOpConvUint8ToInt64:
newConstArray[i].setI64Const(unionArray[i].getU8Const()); break;
case EOpConvUint8ToUint16:
newConstArray[i].setU16Const(unionArray[i].getU8Const()); break;
case EOpConvUint8ToUint:
newConstArray[i].setUConst(unionArray[i].getU8Const()); break;
case EOpConvUint8ToUint64:
newConstArray[i].setU64Const(unionArray[i].getU8Const()); break;
case EOpConvInt8ToFloat16:
newConstArray[i].setDConst(unionArray[i].getI8Const()); break;
case EOpConvInt8ToFloat:
newConstArray[i].setDConst(unionArray[i].getI8Const()); break;
case EOpConvInt8ToDouble:
newConstArray[i].setDConst(unionArray[i].getI8Const()); break;
case EOpConvUint8ToFloat16:
newConstArray[i].setDConst(unionArray[i].getU8Const()); break;
case EOpConvUint8ToFloat:
newConstArray[i].setDConst(unionArray[i].getU8Const()); break;
case EOpConvUint8ToDouble:
newConstArray[i].setDConst(unionArray[i].getU8Const()); break;
case EOpConvInt16ToInt8:
newConstArray[i].setI8Const(static_cast<signed char>(unionArray[i].getI16Const())); break;
case EOpConvInt16ToInt:
newConstArray[i].setIConst(unionArray[i].getI16Const()); break;
case EOpConvInt16ToInt64:
newConstArray[i].setI64Const(unionArray[i].getI16Const()); break;
case EOpConvInt16ToUint8:
newConstArray[i].setU8Const(static_cast<unsigned char>(unionArray[i].getI16Const())); break;
case EOpConvInt16ToUint16:
newConstArray[i].setU16Const(unionArray[i].getI16Const()); break;
case EOpConvInt16ToUint:
newConstArray[i].setUConst(unionArray[i].getI16Const()); break;
case EOpConvInt16ToUint64:
newConstArray[i].setU64Const(unionArray[i].getI16Const()); break;
case EOpConvUint16ToInt8:
newConstArray[i].setI8Const(static_cast<signed char>(unionArray[i].getU16Const())); break;
case EOpConvUint16ToInt16:
newConstArray[i].setI16Const(unionArray[i].getU16Const()); break;
case EOpConvUint16ToInt:
newConstArray[i].setIConst(unionArray[i].getU16Const()); break;
case EOpConvUint16ToInt64:
newConstArray[i].setI64Const(unionArray[i].getU16Const()); break;
case EOpConvUint16ToUint8:
newConstArray[i].setU8Const(static_cast<unsigned char>(unionArray[i].getU16Const())); break;
case EOpConvUint16ToUint:
newConstArray[i].setUConst(unionArray[i].getU16Const()); break;
case EOpConvUint16ToUint64:
newConstArray[i].setU64Const(unionArray[i].getU16Const()); break;
case EOpConvInt16ToFloat16:
newConstArray[i].setDConst(unionArray[i].getI16Const()); break;
case EOpConvInt16ToFloat:
newConstArray[i].setDConst(unionArray[i].getI16Const()); break;
case EOpConvInt16ToDouble:
newConstArray[i].setDConst(unionArray[i].getI16Const()); break;
case EOpConvUint16ToFloat16:
newConstArray[i].setDConst(unionArray[i].getU16Const()); break;
case EOpConvUint16ToFloat:
newConstArray[i].setDConst(unionArray[i].getU16Const()); break;
case EOpConvUint16ToDouble:
newConstArray[i].setDConst(unionArray[i].getU16Const()); break;
case EOpConvIntToInt8:
newConstArray[i].setI8Const((signed char)unionArray[i].getIConst()); break;
case EOpConvIntToInt16:
newConstArray[i].setI16Const((signed short)unionArray[i].getIConst()); break;
case EOpConvIntToInt64:
newConstArray[i].setI64Const(unionArray[i].getIConst()); break;
case EOpConvIntToUint8:
newConstArray[i].setU8Const((unsigned char)unionArray[i].getIConst()); break;
case EOpConvIntToUint16:
newConstArray[i].setU16Const((unsigned char)unionArray[i].getIConst()); break;
case EOpConvIntToUint64:
newConstArray[i].setU64Const(unionArray[i].getIConst()); break;
case EOpConvUintToInt8:
newConstArray[i].setI8Const((signed char)unionArray[i].getUConst()); break;
case EOpConvUintToInt16:
newConstArray[i].setI16Const((signed short)unionArray[i].getUConst()); break;
case EOpConvUintToInt64:
newConstArray[i].setI64Const(unionArray[i].getUConst()); break;
case EOpConvUintToUint8:
newConstArray[i].setU8Const((unsigned char)unionArray[i].getUConst()); break;
case EOpConvUintToUint16:
newConstArray[i].setU16Const((unsigned short)unionArray[i].getUConst()); break;
case EOpConvUintToUint64:
newConstArray[i].setU64Const(unionArray[i].getUConst()); break;
case EOpConvIntToFloat16:
newConstArray[i].setDConst(unionArray[i].getIConst()); break;
case EOpConvUintToFloat16:
newConstArray[i].setDConst(unionArray[i].getUConst()); break;
case EOpConvInt64ToInt8:
newConstArray[i].setI8Const(static_cast<signed char>(unionArray[i].getI64Const())); break;
case EOpConvInt64ToInt16:
newConstArray[i].setI16Const(static_cast<signed short>(unionArray[i].getI64Const())); break;
case EOpConvInt64ToInt:
newConstArray[i].setIConst(static_cast<int>(unionArray[i].getI64Const())); break;
case EOpConvInt64ToUint8:
newConstArray[i].setU8Const(static_cast<unsigned char>(unionArray[i].getI64Const())); break;
case EOpConvInt64ToUint16:
newConstArray[i].setU16Const(static_cast<unsigned short>(unionArray[i].getI64Const())); break;
case EOpConvInt64ToUint:
newConstArray[i].setUConst(static_cast<unsigned int>(unionArray[i].getI64Const())); break;
case EOpConvInt64ToUint64:
newConstArray[i].setU64Const(unionArray[i].getI64Const()); break;
case EOpConvUint64ToInt8:
newConstArray[i].setI8Const(static_cast<signed char>(unionArray[i].getU64Const())); break;
case EOpConvUint64ToInt16:
newConstArray[i].setI16Const(static_cast<signed short>(unionArray[i].getU64Const())); break;
case EOpConvUint64ToInt:
newConstArray[i].setIConst(static_cast<int>(unionArray[i].getU64Const())); break;
case EOpConvUint64ToInt64:
newConstArray[i].setI64Const(unionArray[i].getU64Const()); break;
case EOpConvUint64ToUint8:
newConstArray[i].setU8Const(static_cast<unsigned char>(unionArray[i].getU64Const())); break;
case EOpConvUint64ToUint16:
newConstArray[i].setU16Const(static_cast<unsigned short>(unionArray[i].getU64Const())); break;
case EOpConvUint64ToUint:
newConstArray[i].setUConst(static_cast<unsigned int>(unionArray[i].getU64Const())); break;
case EOpConvInt64ToFloat16:
newConstArray[i].setDConst(static_cast<double>(unionArray[i].getI64Const())); break;
case EOpConvInt64ToFloat:
newConstArray[i].setDConst(static_cast<double>(unionArray[i].getI64Const())); break;
case EOpConvInt64ToDouble:
newConstArray[i].setDConst(static_cast<double>(unionArray[i].getI64Const())); break;
case EOpConvUint64ToFloat16:
newConstArray[i].setDConst(static_cast<double>(unionArray[i].getU64Const())); break;
case EOpConvUint64ToFloat:
newConstArray[i].setDConst(static_cast<double>(unionArray[i].getU64Const())); break;
case EOpConvUint64ToDouble:
newConstArray[i].setDConst(static_cast<double>(unionArray[i].getU64Const())); break;
case EOpConvFloat16ToInt8:
newConstArray[i].setI8Const(static_cast<signed char>(unionArray[i].getDConst())); break;
case EOpConvFloat16ToInt16:
newConstArray[i].setI16Const(static_cast<signed short>(unionArray[i].getDConst())); break;
case EOpConvFloat16ToInt:
newConstArray[i].setIConst(static_cast<int>(unionArray[i].getDConst())); break;
case EOpConvFloat16ToInt64:
newConstArray[i].setI64Const(static_cast<long long>(unionArray[i].getDConst())); break;
case EOpConvFloat16ToUint8:
newConstArray[i].setU8Const(static_cast<unsigned char>(unionArray[i].getDConst())); break;
case EOpConvFloat16ToUint16:
newConstArray[i].setU16Const(static_cast<unsigned short>(unionArray[i].getDConst())); break;
case EOpConvFloat16ToUint:
newConstArray[i].setUConst(static_cast<unsigned int>(unionArray[i].getDConst())); break;
case EOpConvFloat16ToUint64:
newConstArray[i].setU64Const(static_cast<unsigned long long>(unionArray[i].getDConst())); break;
case EOpConvFloat16ToFloat:
newConstArray[i].setDConst(unionArray[i].getDConst()); break;
case EOpConvFloat16ToDouble:
newConstArray[i].setDConst(unionArray[i].getDConst()); break;
case EOpConvFloatToInt8:
newConstArray[i].setI8Const(static_cast<signed char>(unionArray[i].getDConst())); break;
case EOpConvFloatToInt16:
newConstArray[i].setI16Const(static_cast<signed short>(unionArray[i].getDConst())); break;
case EOpConvFloatToInt64:
newConstArray[i].setI64Const(static_cast<long long>(unionArray[i].getDConst())); break;
case EOpConvFloatToUint8:
newConstArray[i].setU8Const(static_cast<unsigned char>(unionArray[i].getDConst())); break;
case EOpConvFloatToUint16:
newConstArray[i].setU16Const(static_cast<unsigned short>(unionArray[i].getDConst())); break;
case EOpConvFloatToUint64:
newConstArray[i].setU64Const(static_cast<unsigned long long>(unionArray[i].getDConst())); break;
case EOpConvFloatToFloat16:
newConstArray[i].setDConst(unionArray[i].getDConst()); break;
case EOpConvDoubleToInt8:
newConstArray[i].setI8Const(static_cast<signed char>(unionArray[i].getDConst())); break;
case EOpConvDoubleToInt16:
newConstArray[i].setI16Const(static_cast<signed short>(unionArray[i].getDConst())); break;
case EOpConvDoubleToInt64:
newConstArray[i].setI64Const(static_cast<long long>(unionArray[i].getDConst())); break;
case EOpConvDoubleToUint8:
newConstArray[i].setU8Const(static_cast<unsigned char>(unionArray[i].getDConst())); break;
case EOpConvDoubleToUint16:
newConstArray[i].setU16Const(static_cast<unsigned short>(unionArray[i].getDConst())); break;
case EOpConvDoubleToUint64:
newConstArray[i].setU64Const(static_cast<unsigned long long>(unionArray[i].getDConst())); break;
case EOpConvDoubleToFloat16:
newConstArray[i].setDConst(unionArray[i].getDConst()); break;
case EOpConvPtrToUint64:
case EOpConvUint64ToPtr:
case EOpConstructReference:
@ -1009,6 +914,12 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode)
objectSize = std::max(children[0]->getAsTyped()->getType().getVectorSize(),
children[2]->getAsTyped()->getType().getVectorSize());
break;
case EOpMul:
{
TIntermConstantUnion* left = children[0]->getAsConstantUnion();
TIntermConstantUnion* right = children[1]->getAsConstantUnion();
return left->fold(EOpMul, right);
}
default:
return aggrNode;
}
@ -1048,6 +959,9 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode)
case EOpMin:
switch(children[0]->getAsTyped()->getBasicType()) {
case EbtFloat16:
case EbtBFloat16:
case EbtFloatE5M2:
case EbtFloatE4M3:
case EbtFloat:
case EbtDouble:
newConstArray[comp].setDConst(std::min(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
@ -1082,6 +996,9 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode)
case EOpMax:
switch(children[0]->getAsTyped()->getBasicType()) {
case EbtFloat16:
case EbtBFloat16:
case EbtFloatE5M2:
case EbtFloatE4M3:
case EbtFloat:
case EbtDouble:
newConstArray[comp].setDConst(std::max(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
@ -1116,6 +1033,9 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode)
case EOpClamp:
switch(children[0]->getAsTyped()->getBasicType()) {
case EbtFloat16:
case EbtBFloat16:
case EbtFloatE5M2:
case EbtFloatE4M3:
case EbtFloat:
case EbtDouble:
newConstArray[comp].setDConst(std::min(std::max(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()),
@ -1223,6 +1143,9 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode)
break;
}
case EOpDot:
if (!children[0]->getAsTyped()->isFloatingDomain()) {
return aggrNode;
}
newConstArray[0].setDConst(childConstUnions[0].dot(childConstUnions[1]));
break;
case EOpCross:

File diff suppressed because it is too large Load diff

View file

@ -306,4 +306,35 @@ void TIntermSwitch::traverse(TIntermTraverser* it)
it->visitSwitch(EvPostVisit, this);
}
//
// Traverse a variable declaration.
//
void TIntermVariableDecl::traverse(TIntermTraverser *it)
{
bool visit = true;
if (it->preVisit)
visit = it->visitVariableDecl(EvPreVisit, this);
if (visit) {
it->incrementDepth(this);
if (it->rightToLeft) {
if (it->includeDeclSymbol)
declSymbol->traverse(it);
if (initNode)
initNode->traverse(it);
}
else {
if (initNode)
initNode->traverse(it);
if (it->includeDeclSymbol)
declSymbol->traverse(it);
}
it->decrementDepth();
}
if (visit && it->postVisit)
it->visitVariableDecl(EvPostVisit, this);
}
} // end namespace glslang

View file

@ -46,6 +46,7 @@
#include "propagateNoContraction.h"
#include <cfloat>
#include <limits>
#include <utility>
#include <tuple>
@ -65,10 +66,10 @@ namespace glslang {
// Returns the added node.
//
TIntermSymbol* TIntermediate::addSymbol(long long id, const TString& name, const TType& type, const TConstUnionArray& constArray,
TIntermSymbol* TIntermediate::addSymbol(long long id, const TString& name, const TString& mangledName, const TType& type, const TConstUnionArray& constArray,
TIntermTyped* constSubtree, const TSourceLoc& loc)
{
TIntermSymbol* node = new TIntermSymbol(id, name, type);
TIntermSymbol* node = new TIntermSymbol(id, name, getStage(), type, &mangledName);
node->setLoc(loc);
node->setConstArray(constArray);
node->setConstSubtree(constSubtree);
@ -80,6 +81,7 @@ TIntermSymbol* TIntermediate::addSymbol(const TIntermSymbol& intermSymbol)
{
return addSymbol(intermSymbol.getId(),
intermSymbol.getName(),
intermSymbol.getMangledName(),
intermSymbol.getType(),
intermSymbol.getConstArray(),
intermSymbol.getConstSubtree(),
@ -96,14 +98,14 @@ TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable)
TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable, const TSourceLoc& loc)
{
return addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), variable.getConstArray(), variable.getConstSubtree(), loc);
return addSymbol(variable.getUniqueId(), variable.getName(), variable.getMangledName(), variable.getType(), variable.getConstArray(), variable.getConstSubtree(), loc);
}
TIntermSymbol* TIntermediate::addSymbol(const TType& type, const TSourceLoc& loc)
{
TConstUnionArray unionArray; // just a null constant
return addSymbol(0, "", type, unionArray, nullptr, loc);
return addSymbol(0, "", "", type, unionArray, nullptr, loc);
}
//
@ -116,7 +118,8 @@ TIntermSymbol* TIntermediate::addSymbol(const TType& type, const TSourceLoc& loc
TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& loc)
{
// No operations work on blocks
if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock ||
left->getType().getBasicType() == EbtString || right->getType().getBasicType() == EbtString)
return nullptr;
// Convert "reference +/- int" and "reference - reference" to integer math
@ -163,8 +166,8 @@ TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIn
left = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, left, TType(EbtUint64));
right = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, right, TType(EbtUint64));
left = addBuiltInFunctionCall(loc, EOpConvUint64ToInt64, true, left, TType(EbtInt64));
right = addBuiltInFunctionCall(loc, EOpConvUint64ToInt64, true, right, TType(EbtInt64));
left = addBuiltInFunctionCall(loc, EOpConvNumeric, true, left, TType(EbtInt64));
right = addBuiltInFunctionCall(loc, EOpConvNumeric, true, right, TType(EbtInt64));
left = addBinaryMath(EOpSub, left, right, loc);
@ -397,6 +400,9 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child,
case EOpConstructUint64: newType = EbtUint64; break;
case EOpConstructDouble: newType = EbtDouble; break;
case EOpConstructFloat16: newType = EbtFloat16; break;
case EOpConstructBFloat16: newType = EbtBFloat16; break;
case EOpConstructFloatE4M3: newType = EbtFloatE4M3; break;
case EOpConstructFloatE5M2: newType = EbtFloatE5M2; break;
default: break; // some compilers want this
}
@ -426,7 +432,10 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child,
case EOpConstructBool:
case EOpConstructFloat:
case EOpConstructDouble:
case EOpConstructFloat16: {
case EOpConstructFloat16:
case EOpConstructBFloat16:
case EOpConstructFloatE5M2:
case EOpConstructFloatE4M3: {
TIntermUnary* unary_node = child->getAsUnaryNode();
if (unary_node != nullptr)
unary_node->updatePrecision();
@ -567,222 +576,18 @@ bool TIntermediate::isConversionAllowed(TOperator op, TIntermTyped* node) const
bool TIntermediate::buildConvertOp(TBasicType dst, TBasicType src, TOperator& newOp) const
{
switch (dst) {
case EbtDouble:
switch (src) {
case EbtUint: newOp = EOpConvUintToDouble; break;
case EbtBool: newOp = EOpConvBoolToDouble; break;
case EbtFloat: newOp = EOpConvFloatToDouble; break;
case EbtInt: newOp = EOpConvIntToDouble; break;
case EbtInt8: newOp = EOpConvInt8ToDouble; break;
case EbtUint8: newOp = EOpConvUint8ToDouble; break;
case EbtInt16: newOp = EOpConvInt16ToDouble; break;
case EbtUint16: newOp = EOpConvUint16ToDouble; break;
case EbtFloat16: newOp = EOpConvFloat16ToDouble; break;
case EbtInt64: newOp = EOpConvInt64ToDouble; break;
case EbtUint64: newOp = EOpConvUint64ToDouble; break;
default:
return false;
}
break;
case EbtFloat:
switch (src) {
case EbtInt: newOp = EOpConvIntToFloat; break;
case EbtUint: newOp = EOpConvUintToFloat; break;
case EbtBool: newOp = EOpConvBoolToFloat; break;
case EbtDouble: newOp = EOpConvDoubleToFloat; break;
case EbtInt8: newOp = EOpConvInt8ToFloat; break;
case EbtUint8: newOp = EOpConvUint8ToFloat; break;
case EbtInt16: newOp = EOpConvInt16ToFloat; break;
case EbtUint16: newOp = EOpConvUint16ToFloat; break;
case EbtFloat16: newOp = EOpConvFloat16ToFloat; break;
case EbtInt64: newOp = EOpConvInt64ToFloat; break;
case EbtUint64: newOp = EOpConvUint64ToFloat; break;
default:
return false;
}
break;
case EbtFloat16:
switch (src) {
case EbtInt8: newOp = EOpConvInt8ToFloat16; break;
case EbtUint8: newOp = EOpConvUint8ToFloat16; break;
case EbtInt16: newOp = EOpConvInt16ToFloat16; break;
case EbtUint16: newOp = EOpConvUint16ToFloat16; break;
case EbtInt: newOp = EOpConvIntToFloat16; break;
case EbtUint: newOp = EOpConvUintToFloat16; break;
case EbtBool: newOp = EOpConvBoolToFloat16; break;
case EbtFloat: newOp = EOpConvFloatToFloat16; break;
case EbtDouble: newOp = EOpConvDoubleToFloat16; break;
case EbtInt64: newOp = EOpConvInt64ToFloat16; break;
case EbtUint64: newOp = EOpConvUint64ToFloat16; break;
default:
return false;
}
break;
case EbtBool:
switch (src) {
case EbtInt: newOp = EOpConvIntToBool; break;
case EbtUint: newOp = EOpConvUintToBool; break;
case EbtFloat: newOp = EOpConvFloatToBool; break;
case EbtDouble: newOp = EOpConvDoubleToBool; break;
case EbtInt8: newOp = EOpConvInt8ToBool; break;
case EbtUint8: newOp = EOpConvUint8ToBool; break;
case EbtInt16: newOp = EOpConvInt16ToBool; break;
case EbtUint16: newOp = EOpConvUint16ToBool; break;
case EbtFloat16: newOp = EOpConvFloat16ToBool; break;
case EbtInt64: newOp = EOpConvInt64ToBool; break;
case EbtUint64: newOp = EOpConvUint64ToBool; break;
default:
return false;
}
break;
case EbtInt8:
switch (src) {
case EbtUint8: newOp = EOpConvUint8ToInt8; break;
case EbtInt16: newOp = EOpConvInt16ToInt8; break;
case EbtUint16: newOp = EOpConvUint16ToInt8; break;
case EbtInt: newOp = EOpConvIntToInt8; break;
case EbtUint: newOp = EOpConvUintToInt8; break;
case EbtInt64: newOp = EOpConvInt64ToInt8; break;
case EbtUint64: newOp = EOpConvUint64ToInt8; break;
case EbtBool: newOp = EOpConvBoolToInt8; break;
case EbtFloat: newOp = EOpConvFloatToInt8; break;
case EbtDouble: newOp = EOpConvDoubleToInt8; break;
case EbtFloat16: newOp = EOpConvFloat16ToInt8; break;
default:
return false;
}
break;
case EbtUint8:
switch (src) {
case EbtInt8: newOp = EOpConvInt8ToUint8; break;
case EbtInt16: newOp = EOpConvInt16ToUint8; break;
case EbtUint16: newOp = EOpConvUint16ToUint8; break;
case EbtInt: newOp = EOpConvIntToUint8; break;
case EbtUint: newOp = EOpConvUintToUint8; break;
case EbtInt64: newOp = EOpConvInt64ToUint8; break;
case EbtUint64: newOp = EOpConvUint64ToUint8; break;
case EbtBool: newOp = EOpConvBoolToUint8; break;
case EbtFloat: newOp = EOpConvFloatToUint8; break;
case EbtDouble: newOp = EOpConvDoubleToUint8; break;
case EbtFloat16: newOp = EOpConvFloat16ToUint8; break;
default:
return false;
}
break;
case EbtInt16:
switch (src) {
case EbtUint8: newOp = EOpConvUint8ToInt16; break;
case EbtInt8: newOp = EOpConvInt8ToInt16; break;
case EbtUint16: newOp = EOpConvUint16ToInt16; break;
case EbtInt: newOp = EOpConvIntToInt16; break;
case EbtUint: newOp = EOpConvUintToInt16; break;
case EbtInt64: newOp = EOpConvInt64ToInt16; break;
case EbtUint64: newOp = EOpConvUint64ToInt16; break;
case EbtBool: newOp = EOpConvBoolToInt16; break;
case EbtFloat: newOp = EOpConvFloatToInt16; break;
case EbtDouble: newOp = EOpConvDoubleToInt16; break;
case EbtFloat16: newOp = EOpConvFloat16ToInt16; break;
default:
return false;
}
break;
case EbtUint16:
switch (src) {
case EbtInt8: newOp = EOpConvInt8ToUint16; break;
case EbtUint8: newOp = EOpConvUint8ToUint16; break;
case EbtInt16: newOp = EOpConvInt16ToUint16; break;
case EbtInt: newOp = EOpConvIntToUint16; break;
case EbtUint: newOp = EOpConvUintToUint16; break;
case EbtInt64: newOp = EOpConvInt64ToUint16; break;
case EbtUint64: newOp = EOpConvUint64ToUint16; break;
case EbtBool: newOp = EOpConvBoolToUint16; break;
case EbtFloat: newOp = EOpConvFloatToUint16; break;
case EbtDouble: newOp = EOpConvDoubleToUint16; break;
case EbtFloat16: newOp = EOpConvFloat16ToUint16; break;
default:
return false;
}
break;
case EbtInt:
switch (src) {
case EbtUint: newOp = EOpConvUintToInt; break;
case EbtBool: newOp = EOpConvBoolToInt; break;
case EbtFloat: newOp = EOpConvFloatToInt; break;
case EbtInt8: newOp = EOpConvInt8ToInt; break;
case EbtUint8: newOp = EOpConvUint8ToInt; break;
case EbtInt16: newOp = EOpConvInt16ToInt; break;
case EbtUint16: newOp = EOpConvUint16ToInt; break;
case EbtDouble: newOp = EOpConvDoubleToInt; break;
case EbtFloat16: newOp = EOpConvFloat16ToInt; break;
case EbtInt64: newOp = EOpConvInt64ToInt; break;
case EbtUint64: newOp = EOpConvUint64ToInt; break;
default:
return false;
}
break;
case EbtUint:
switch (src) {
case EbtInt: newOp = EOpConvIntToUint; break;
case EbtBool: newOp = EOpConvBoolToUint; break;
case EbtFloat: newOp = EOpConvFloatToUint; break;
case EbtInt8: newOp = EOpConvInt8ToUint; break;
case EbtUint8: newOp = EOpConvUint8ToUint; break;
case EbtInt16: newOp = EOpConvInt16ToUint; break;
case EbtUint16: newOp = EOpConvUint16ToUint; break;
case EbtDouble: newOp = EOpConvDoubleToUint; break;
case EbtFloat16: newOp = EOpConvFloat16ToUint; break;
case EbtInt64: newOp = EOpConvInt64ToUint; break;
case EbtUint64: newOp = EOpConvUint64ToUint; break;
// For bindless texture type conversion, add a dummy convert op, just
// to generate a new TIntermTyped
// uvec2(any sampler type)
// uvec2(any image type)
case EbtSampler: newOp = EOpConvIntToUint; break;
default:
return false;
}
break;
case EbtInt64:
switch (src) {
case EbtInt8: newOp = EOpConvInt8ToInt64; break;
case EbtUint8: newOp = EOpConvUint8ToInt64; break;
case EbtInt16: newOp = EOpConvInt16ToInt64; break;
case EbtUint16: newOp = EOpConvUint16ToInt64; break;
case EbtInt: newOp = EOpConvIntToInt64; break;
case EbtUint: newOp = EOpConvUintToInt64; break;
case EbtBool: newOp = EOpConvBoolToInt64; break;
case EbtFloat: newOp = EOpConvFloatToInt64; break;
case EbtDouble: newOp = EOpConvDoubleToInt64; break;
case EbtFloat16: newOp = EOpConvFloat16ToInt64; break;
case EbtUint64: newOp = EOpConvUint64ToInt64; break;
default:
return false;
}
break;
case EbtUint64:
switch (src) {
case EbtInt8: newOp = EOpConvInt8ToUint64; break;
case EbtUint8: newOp = EOpConvUint8ToUint64; break;
case EbtInt16: newOp = EOpConvInt16ToUint64; break;
case EbtUint16: newOp = EOpConvUint16ToUint64; break;
case EbtInt: newOp = EOpConvIntToUint64; break;
case EbtUint: newOp = EOpConvUintToUint64; break;
case EbtBool: newOp = EOpConvBoolToUint64; break;
case EbtFloat: newOp = EOpConvFloatToUint64; break;
case EbtDouble: newOp = EOpConvDoubleToUint64; break;
case EbtFloat16: newOp = EOpConvFloat16ToUint64; break;
case EbtInt64: newOp = EOpConvInt64ToUint64; break;
default:
return false;
}
break;
default:
// (bfloat16_t,fp8) <-> bool not supported
if (((src == EbtBFloat16 || src == EbtFloatE5M2 || src == EbtFloatE4M3) && dst == EbtBool) ||
((dst == EbtBFloat16 || dst == EbtFloatE5M2 || dst == EbtFloatE4M3) && src == EbtBool)) {
return false;
}
return true;
if ((isTypeInt(dst) || isTypeFloat(dst) || dst == EbtBool) &&
(isTypeInt(src) || isTypeFloat(src) || src == EbtBool)) {
newOp = EOpConvNumeric;
return true;
}
return false;
}
// This is 'mechanism' here, it does any conversion told.
@ -804,11 +609,15 @@ TIntermTyped* TIntermediate::createConversion(TBasicType convertTo, TIntermTyped
node->getBasicType() == EbtInt || node->getBasicType() == EbtUint ||
node->getBasicType() == EbtInt64 || node->getBasicType() == EbtUint64);
bool convertToFloatTypes = (convertTo == EbtFloat16 || convertTo == EbtFloat || convertTo == EbtDouble);
bool convertToFloatTypes = (convertTo == EbtFloat16 || convertTo == EbtBFloat16 || convertTo == EbtFloat || convertTo == EbtDouble ||
convertTo == EbtFloatE5M2 || convertTo == EbtFloatE4M3);
bool convertFromFloatTypes = (node->getBasicType() == EbtFloat16 ||
node->getBasicType() == EbtBFloat16 ||
node->getBasicType() == EbtFloat ||
node->getBasicType() == EbtDouble);
node->getBasicType() == EbtDouble ||
node->getBasicType() == EbtFloatE5M2 ||
node->getBasicType() == EbtFloatE4M3);
if (((convertTo == EbtInt8 || convertTo == EbtUint8) && ! convertFromIntTypes) ||
((node->getBasicType() == EbtInt8 || node->getBasicType() == EbtUint8) && ! convertToIntTypes)) {
@ -1031,7 +840,17 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt
// Reject implicit conversions to cooperative matrix types
if (node->getType().isCoopMat() &&
op != EOpConstructCooperativeMatrixNV &&
op != EOpConstructCooperativeMatrixKHR)
op != EOpConstructCooperativeMatrixKHR &&
op != glslang::EOpCompositeConstructCoopMatQCOM)
return nullptr;
if (node->getType().isTensorLayoutNV() ||
node->getType().isTensorViewNV())
return nullptr;
// Reject implicit conversions to cooperative vector types
if (node->getType().isCoopVecNV() &&
op != EOpConstructCooperativeVectorNV)
return nullptr;
// Note: callers are responsible for other aspects of shape,
@ -1047,12 +866,16 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt
case EOpConstructUint:
case EOpConstructDouble:
case EOpConstructFloat16:
case EOpConstructBFloat16:
case EOpConstructFloatE5M2:
case EOpConstructFloatE4M3:
case EOpConstructInt8:
case EOpConstructUint8:
case EOpConstructInt16:
case EOpConstructUint16:
case EOpConstructInt64:
case EOpConstructUint64:
case EOpConstructSaturated:
break;
//
@ -1101,6 +924,7 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt
case EOpConstructStruct:
case EOpConstructCooperativeMatrixNV:
case EOpConstructCooperativeMatrixKHR:
case EOpConstructCooperativeVectorNV:
if (type.isReference() || node->getType().isReference()) {
// types must match to assign a reference
@ -1152,6 +976,11 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt
// changing language sementics on the fly by asking what extensions are in use
// - at the time of this writing (14-Aug-2020), no test results are changed by this.
switch (op) {
case EOpConstructBFloat16:
case EOpConstructFloatE5M2:
case EOpConstructFloatE4M3:
canPromoteConstant = true;
break;
case EOpConstructFloat16:
canPromoteConstant = numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float16);
@ -1454,6 +1283,9 @@ bool TIntermediate::isFPPromotion(TBasicType from, TBasicType to) const
// floating-point promotions
if (to == EbtDouble) {
switch(from) {
case EbtBFloat16:
case EbtFloatE5M2:
case EbtFloatE4M3:
case EbtFloat16:
case EbtFloat:
return true;
@ -1546,7 +1378,7 @@ bool TIntermediate::isIntegralConversion(TBasicType from, TBasicType to) const
bool TIntermediate::isFPConversion(TBasicType from, TBasicType to) const
{
if (to == EbtFloat && from == EbtFloat16) {
if (to == EbtFloat && (from == EbtFloat16 || from == EbtBFloat16 || from == EbtFloatE5M2 || from == EbtFloatE4M3)) {
return true;
} else {
return false;
@ -1694,10 +1526,19 @@ bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperat
case EbtInt16:
case EbtUint16:
return (version >= 400 || numericFeatures.contains(TNumericFeatures::gpu_shader_fp64)) &&
numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
(numericFeatures.contains(TNumericFeatures::nv_gpu_shader5_types) ||
numericFeatures.contains(TNumericFeatures::gpu_shader_int16));
case EbtFloat16:
return (version >= 400 || numericFeatures.contains(TNumericFeatures::gpu_shader_fp64)) &&
numericFeatures.contains(TNumericFeatures::gpu_shader_half_float);
(numericFeatures.contains(TNumericFeatures::nv_gpu_shader5_types) ||
numericFeatures.contains(TNumericFeatures::gpu_shader_half_float));
case EbtBFloat16:
case EbtFloatE5M2:
case EbtFloatE4M3:
return true;
case EbtInt8:
case EbtUint8:
return numericFeatures.contains(TNumericFeatures::nv_gpu_shader5_types);
default:
return false;
}
@ -1710,22 +1551,37 @@ bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperat
return getSource() == EShSourceHlsl;
case EbtInt16:
case EbtUint16:
return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
return numericFeatures.contains(TNumericFeatures::gpu_shader_int16) ||
numericFeatures.contains(TNumericFeatures::nv_gpu_shader5_types);
case EbtFloat16:
return numericFeatures.contains(TNumericFeatures::gpu_shader_half_float) ||
numericFeatures.contains(TNumericFeatures::nv_gpu_shader5_types) ||
getSource() == EShSourceHlsl;
case EbtBFloat16:
case EbtFloatE5M2:
case EbtFloatE4M3:
return true;
case EbtInt8:
case EbtUint8:
return numericFeatures.contains(TNumericFeatures::nv_gpu_shader5_types);
default:
return false;
}
case EbtUint:
switch (from) {
case EbtInt:
return version >= 400 || getSource() == EShSourceHlsl || IsRequestedExtension(E_GL_ARB_gpu_shader5);
return version >= 400 || getSource() == EShSourceHlsl ||
IsRequestedExtension(E_GL_ARB_gpu_shader5) ||
numericFeatures.contains(TNumericFeatures::nv_gpu_shader5_types);
case EbtBool:
return getSource() == EShSourceHlsl;
case EbtInt16:
case EbtUint16:
return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
return numericFeatures.contains(TNumericFeatures::gpu_shader_int16) ||
numericFeatures.contains(TNumericFeatures::nv_gpu_shader5_types);
case EbtInt8:
case EbtUint8:
return numericFeatures.contains(TNumericFeatures::nv_gpu_shader5_types);
default:
return false;
}
@ -1734,7 +1590,10 @@ bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperat
case EbtBool:
return getSource() == EShSourceHlsl;
case EbtInt16:
return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
return numericFeatures.contains(TNumericFeatures::gpu_shader_int16) ||
numericFeatures.contains(TNumericFeatures::nv_gpu_shader5_types);
case EbtInt8:
return numericFeatures.contains(TNumericFeatures::nv_gpu_shader5_types);
default:
return false;
}
@ -1746,7 +1605,11 @@ bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperat
return true;
case EbtInt16:
case EbtUint16:
return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
return numericFeatures.contains(TNumericFeatures::gpu_shader_int16) ||
numericFeatures.contains(TNumericFeatures::nv_gpu_shader5_types);
case EbtInt8:
case EbtUint8:
return numericFeatures.contains(TNumericFeatures::nv_gpu_shader5_types);
default:
return false;
}
@ -1754,8 +1617,11 @@ bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperat
switch (from) {
case EbtInt:
return true;
case EbtInt8:
return numericFeatures.contains(TNumericFeatures::nv_gpu_shader5_types);
case EbtInt16:
return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
return numericFeatures.contains(TNumericFeatures::gpu_shader_int16) ||
numericFeatures.contains(TNumericFeatures::nv_gpu_shader5_types);
default:
return false;
}
@ -1764,6 +1630,18 @@ bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperat
case EbtInt16:
case EbtUint16:
return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
case EbtFloatE5M2:
case EbtFloatE4M3:
return true;
default:
break;
}
return false;
case EbtBFloat16:
switch (from) {
case EbtFloatE5M2:
case EbtFloatE4M3:
return true;
default:
break;
}
@ -1922,6 +1800,10 @@ std::tuple<TBasicType, TBasicType> TIntermediate::getConversionDestinationType(T
(type1 == EbtFloat16 && canImplicitlyPromote(type0, EbtFloat16, op)) ) {
res0 = EbtFloat16;
res1 = EbtFloat16;
} else if ((type0 == EbtBFloat16 && canImplicitlyPromote(type1, EbtBFloat16, op)) ||
(type1 == EbtBFloat16 && canImplicitlyPromote(type0, EbtBFloat16, op)) ) {
res0 = EbtBFloat16;
res1 = EbtBFloat16;
} else if (isTypeInt(type0) && isTypeInt(type1) &&
(canImplicitlyPromote(type0, type1, op) || canImplicitlyPromote(type1, type0, op))) {
if ((isTypeSignedInt(type0) && isTypeSignedInt(type1)) ||
@ -1977,6 +1859,9 @@ TOperator TIntermediate::mapTypeToConstructorOp(const TType& type) const
if (type.isCoopMatKHR())
return EOpConstructCooperativeMatrixKHR;
if (type.isCoopVecNV())
return EOpConstructCooperativeVectorNV;
switch (type.getBasicType()) {
case EbtStruct:
op = EOpConstructStruct;
@ -2215,6 +2100,33 @@ TOperator TIntermediate::mapTypeToConstructorOp(const TType& type) const
}
}
break;
case EbtBFloat16:
switch (type.getVectorSize()) {
case 1: op = EOpConstructBFloat16; break;
case 2: op = EOpConstructBF16Vec2; break;
case 3: op = EOpConstructBF16Vec3; break;
case 4: op = EOpConstructBF16Vec4; break;
default: break; // some compilers want this
}
break;
case EbtFloatE5M2:
switch (type.getVectorSize()) {
case 1: op = EOpConstructFloatE5M2; break;
case 2: op = EOpConstructFloatE5M2Vec2; break;
case 3: op = EOpConstructFloatE5M2Vec3; break;
case 4: op = EOpConstructFloatE5M2Vec4; break;
default: break; // some compilers want this
}
break;
case EbtFloatE4M3:
switch (type.getVectorSize()) {
case 1: op = EOpConstructFloatE4M3; break;
case 2: op = EOpConstructFloatE4M3Vec2; break;
case 3: op = EOpConstructFloatE4M3Vec3; break;
case 4: op = EOpConstructFloatE4M3Vec4; break;
default: break; // some compilers want this
}
break;
case EbtInt8:
switch(type.getVectorSize()) {
case 1: op = EOpConstructInt8; break;
@ -2471,7 +2383,8 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* true
trueBlock = std::get<0>(children);
falseBlock = std::get<1>(children);
if (trueBlock == nullptr || falseBlock == nullptr)
if (trueBlock == nullptr || falseBlock == nullptr ||
trueBlock->getBasicType() == EbtString || falseBlock->getBasicType() == EbtString)
return nullptr;
// Handle a vector condition as a mix
@ -2624,7 +2537,7 @@ TIntermConstantUnion* TIntermediate::addConstantUnion(bool b, const TSourceLoc&
TIntermConstantUnion* TIntermediate::addConstantUnion(double d, TBasicType baseType, const TSourceLoc& loc, bool literal) const
{
assert(baseType == EbtFloat || baseType == EbtDouble || baseType == EbtFloat16);
assert(baseType == EbtFloat || baseType == EbtDouble || baseType == EbtFloat16 || baseType == EbtBFloat16 || baseType == EbtFloatE5M2 || baseType == EbtFloatE4M3);
if (isEsProfile() && (baseType == EbtFloat || baseType == EbtFloat16)) {
int exponent = 0;
@ -2739,7 +2652,7 @@ const TIntermTyped* TIntermediate::traverseLValueBase(const TIntermTyped* node,
//
// Create while and do-while loop nodes.
//
TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst,
TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermNode* test, TIntermTyped* terminal, bool testFirst,
const TSourceLoc& loc)
{
TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
@ -2751,7 +2664,7 @@ TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TInte
//
// Create a for-loop sequence.
//
TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* initializer, TIntermTyped* test,
TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* initializer, TIntermNode* test,
TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc, TIntermLoop*& node)
{
node = new TIntermLoop(body, test, terminal, testFirst);
@ -2962,17 +2875,16 @@ bool TIntermediate::isSpecializationOperation(const TIntermOperator& node) const
// (However, some floating-point operations result in bool, like ">",
// so are handled later.)
if (node.getType().isFloatingDomain()) {
if (IsOpNumericConv(node.getOp()) &&
isTypeFloat(node.getType().getBasicType()) &&
isTypeFloat(node.getAsUnaryNode()->getOperand()->getAsTyped()->getType().getBasicType())) {
return true;
}
switch (node.getOp()) {
case EOpIndexDirect:
case EOpIndexIndirect:
case EOpIndexDirectStruct:
case EOpVectorSwizzle:
case EOpConvFloatToDouble:
case EOpConvDoubleToFloat:
case EOpConvFloat16ToFloat:
case EOpConvFloatToFloat16:
case EOpConvFloat16ToDouble:
case EOpConvDoubleToFloat16:
return true;
default:
return false;
@ -2987,6 +2899,15 @@ bool TIntermediate::isSpecializationOperation(const TIntermOperator& node) const
// So, for now, we can assume everything left is non-floating-point...
if (IsOpNumericConv(node.getOp())) {
TBasicType srcType = node.getAsUnaryNode()->getOperand()->getAsTyped()->getType().getBasicType();
TBasicType dstType = node.getType().getBasicType();
if ((isTypeInt(srcType) || srcType == EbtBool) &&
(isTypeInt(dstType) || dstType == EbtBool)) {
return true;
}
}
// Now check for integer/bool-based operations
switch (node.getOp()) {
@ -2996,98 +2917,6 @@ bool TIntermediate::isSpecializationOperation(const TIntermOperator& node) const
case EOpIndexDirectStruct:
case EOpVectorSwizzle:
// (u)int* -> bool
case EOpConvInt8ToBool:
case EOpConvInt16ToBool:
case EOpConvIntToBool:
case EOpConvInt64ToBool:
case EOpConvUint8ToBool:
case EOpConvUint16ToBool:
case EOpConvUintToBool:
case EOpConvUint64ToBool:
// bool -> (u)int*
case EOpConvBoolToInt8:
case EOpConvBoolToInt16:
case EOpConvBoolToInt:
case EOpConvBoolToInt64:
case EOpConvBoolToUint8:
case EOpConvBoolToUint16:
case EOpConvBoolToUint:
case EOpConvBoolToUint64:
// int8_t -> (u)int*
case EOpConvInt8ToInt16:
case EOpConvInt8ToInt:
case EOpConvInt8ToInt64:
case EOpConvInt8ToUint8:
case EOpConvInt8ToUint16:
case EOpConvInt8ToUint:
case EOpConvInt8ToUint64:
// int16_t -> (u)int*
case EOpConvInt16ToInt8:
case EOpConvInt16ToInt:
case EOpConvInt16ToInt64:
case EOpConvInt16ToUint8:
case EOpConvInt16ToUint16:
case EOpConvInt16ToUint:
case EOpConvInt16ToUint64:
// int32_t -> (u)int*
case EOpConvIntToInt8:
case EOpConvIntToInt16:
case EOpConvIntToInt64:
case EOpConvIntToUint8:
case EOpConvIntToUint16:
case EOpConvIntToUint:
case EOpConvIntToUint64:
// int64_t -> (u)int*
case EOpConvInt64ToInt8:
case EOpConvInt64ToInt16:
case EOpConvInt64ToInt:
case EOpConvInt64ToUint8:
case EOpConvInt64ToUint16:
case EOpConvInt64ToUint:
case EOpConvInt64ToUint64:
// uint8_t -> (u)int*
case EOpConvUint8ToInt8:
case EOpConvUint8ToInt16:
case EOpConvUint8ToInt:
case EOpConvUint8ToInt64:
case EOpConvUint8ToUint16:
case EOpConvUint8ToUint:
case EOpConvUint8ToUint64:
// uint16_t -> (u)int*
case EOpConvUint16ToInt8:
case EOpConvUint16ToInt16:
case EOpConvUint16ToInt:
case EOpConvUint16ToInt64:
case EOpConvUint16ToUint8:
case EOpConvUint16ToUint:
case EOpConvUint16ToUint64:
// uint32_t -> (u)int*
case EOpConvUintToInt8:
case EOpConvUintToInt16:
case EOpConvUintToInt:
case EOpConvUintToInt64:
case EOpConvUintToUint8:
case EOpConvUintToUint16:
case EOpConvUintToUint64:
// uint64_t -> (u)int*
case EOpConvUint64ToInt8:
case EOpConvUint64ToInt16:
case EOpConvUint64ToInt:
case EOpConvUint64ToInt64:
case EOpConvUint64ToUint8:
case EOpConvUint64ToUint16:
case EOpConvUint64ToUint:
// unary operations
case EOpNegative:
case EOpLogicalNot:
@ -3590,6 +3419,43 @@ bool TIntermediate::promoteBinary(TIntermBinary& node)
return false;
}
if (left->getType().isCoopVecNV() || right->getType().isCoopVecNV()) {
// Operations on two cooperative vectors must have identical types
if (left->getType().isCoopVecNV() && right->getType().isCoopVecNV() &&
left->getType() != right->getType()) {
return false;
}
switch (op) {
case EOpMul:
case EOpMulAssign:
// Use VectorTimesScalar if either operand is not a vector. Otherwise use Mul.
if (!left->getType().isCoopVecNV() || !right->getType().isCoopVecNV()) {
node.setOp(op == EOpMulAssign ? EOpVectorTimesScalarAssign : EOpVectorTimesScalar);
}
// In case of scalar*vector, take the result type from the vector.
if (right->getType().isCoopVecNV()) {
node.setType(right->getType());
}
return true;
case EOpLeftShift:
case EOpLeftShiftAssign:
case EOpRightShift:
case EOpRightShiftAssign:
case EOpAdd:
case EOpSub:
case EOpDiv:
case EOpAssign:
// These require both to be cooperative vectors
if (!left->getType().isCoopVecNV() || !right->getType().isCoopVecNV()) {
return false;
}
return true;
default:
break;
}
return false;
}
// Finish handling the case, for all ops, where both operands are scalars.
if (left->isScalar() && right->isScalar())
return true;
@ -3925,6 +3791,9 @@ TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermC
#define TO_ALL(Get) \
switch (promoteTo) { \
case EbtBFloat16: PROMOTE(setDConst, double, Get); break; \
case EbtFloatE5M2: PROMOTE(setDConst, double, Get); break; \
case EbtFloatE4M3: PROMOTE(setDConst, double, Get); break; \
case EbtFloat16: PROMOTE(setDConst, double, Get); break; \
case EbtFloat: PROMOTE(setDConst, double, Get); break; \
case EbtDouble: PROMOTE(setDConst, double, Get); break; \
@ -3946,6 +3815,9 @@ TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermC
case EbtUint: TO_ALL(getUConst); break;
case EbtBool: TO_ALL(getBConst); break;
case EbtFloat16: TO_ALL(getDConst); break;
case EbtBFloat16: TO_ALL(getDConst); break;
case EbtFloatE5M2: TO_ALL(getDConst); break;
case EbtFloatE4M3: TO_ALL(getDConst); break;
case EbtDouble: TO_ALL(getDConst); break;
case EbtInt8: TO_ALL(getI8Const); break;
case EbtInt16: TO_ALL(getI16Const); break;
@ -4034,12 +3906,15 @@ void TIntermediate::performTextureUpgradeAndSamplerRemovalTransformation(TInterm
const char* TIntermediate::getResourceName(TResourceType res)
{
switch (res) {
case EResSampler: return "shift-sampler-binding";
case EResTexture: return "shift-texture-binding";
case EResImage: return "shift-image-binding";
case EResUbo: return "shift-UBO-binding";
case EResSsbo: return "shift-ssbo-binding";
case EResUav: return "shift-uav-binding";
case EResSampler: return "shift-sampler-binding";
case EResTexture: return "shift-texture-binding";
case EResImage: return "shift-image-binding";
case EResUbo: return "shift-ubo-binding";
case EResSsbo: return "shift-ssbo-binding";
case EResUav: return "shift-uav-binding";
case EResCombinedSampler: return "shift-combined-sampler-binding";
case EResAs: return "shift-as-binding";
case EResTensor: return nullptr;
default:
assert(0); // internal error: should only be called with valid resource types.
return nullptr;

View file

@ -59,8 +59,8 @@ namespace glslang {
class TLiveTraverser : public TIntermTraverser {
public:
TLiveTraverser(const TIntermediate& i, bool traverseAll = false,
bool preVisit = true, bool inVisit = false, bool postVisit = false) :
TIntermTraverser(preVisit, inVisit, postVisit),
bool preVisit = true, bool inVisit = false, bool postVisit = false, bool includeDeclSymbol = false) :
TIntermTraverser(preVisit, inVisit, postVisit, false, includeDeclSymbol),
intermediate(i), traverseAll(traverseAll)
{ }
@ -132,6 +132,47 @@ protected:
return true; // traverse the whole subtree
}
// To prune semantically dead paths in switch statements with constant expressions.
virtual bool visitSwitch(TVisit /* visit */, TIntermSwitch* node)
{
if (traverseAll)
return true; // traverse all code
TIntermConstantUnion* constant = node->getCondition()->getAsConstantUnion();
if (constant) {
TConstUnion switchValue = constant->getConstArray()[0];
int liveBranch = -1;
const auto& body = node->getBody()->getSequence();
for (unsigned int i = 0; i < body.size(); ++i) {
if (body[i]->getAsBranchNode()) {
if (body[i]->getAsBranchNode()->getFlowOp() == glslang::EOpCase) {
TConstUnion caseValue =
body[i]->getAsBranchNode()->getExpression()->getAsConstantUnion()->getConstArray()[0];
if (switchValue == caseValue.getIConst()) {
liveBranch = (int)i;
break;
}
} else if (body[i]->getAsBranchNode()->getFlowOp() == glslang::EOpDefault) {
liveBranch = (int)i;
}
}
}
if (liveBranch != -1) {
for (int i = liveBranch; i < (int)body.size(); ++i) {
if (body[i]->getAsAggregate()) {
for (auto* inst : body[i]->getAsAggregate()->getSequence()) {
if (inst->getAsBranchNode() && (inst->getAsBranchNode()->getFlowOp() == glslang::EOpBreak))
return false; // found and traversed the live case(s)
inst->traverse(this);
}
}
}
}
return false; // finished traversing all cases
} else
return true; // traverse the whole subtree
}
// Track live functions as well as uniforms, so that we don't visit dead functions
// and only visit each function once.
void addFunctionCall(TIntermAggregate* call)

View file

@ -59,7 +59,7 @@ void TParseContextBase::outputMessage(const TSourceLoc& loc, const char* szReaso
safe_vsprintf(szExtraInfo, maxSize, szExtraInfoFormat, args);
infoSink.info.prefix(prefix);
infoSink.info.location(loc, messages & EShMsgAbsolutePath);
infoSink.info.location(loc, messages & EShMsgAbsolutePath, messages & EShMsgDisplayErrorColumn);
infoSink.info << "'" << szToken << "' : " << szReason << " " << szExtraInfo << "\n";
if (prefix == EPrefixError) {
@ -171,6 +171,9 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op,
case EbtHitObjectNV:
message = "can't modify hitObjectNV";
break;
case EbtHitObjectEXT:
message = "can't modify hitObjectEXT";
break;
default:
break;
}
@ -279,7 +282,7 @@ void TParseContextBase::trackLinkage(TSymbol& symbol)
// Ensure index is in bounds, correct if necessary.
// Give an error if not.
void TParseContextBase::checkIndex(const TSourceLoc& loc, const TType& type, int& index)
void TParseContextBase::checkIndex(const TSourceLoc& loc, const TType& type, int64_t& index)
{
const auto sizeIsSpecializationExpression = [&type]() {
return type.containsSpecializationSize() &&
@ -305,6 +308,11 @@ void TParseContextBase::checkIndex(const TSourceLoc& loc, const TType& type, int
error(loc, "", "[", "matrix index out of range '%d'", index);
index = type.getMatrixCols() - 1;
}
} else if (type.isCoopVecNV()) {
if (index >= type.computeNumComponents()) {
error(loc, "", "[", "cooperative vector index out of range '%d'", index);
index = type.computeNumComponents() - 1;
}
}
}
@ -419,7 +427,7 @@ const TFunction* TParseContextBase::selectFunction(
// to even be a potential match, number of arguments must be >= the number of
// fixed (non-default) parameters, and <= the total (including parameter with defaults).
if (call.getParamCount() < candidate.getFixedParamCount() ||
call.getParamCount() > candidate.getParamCount())
(call.getParamCount() > candidate.getParamCount() && !candidate.isVariadic()))
continue;
// see if arguments are convertible
@ -458,7 +466,8 @@ const TFunction* TParseContextBase::selectFunction(
const auto betterParam = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool {
// is call -> can2 better than call -> can1 for any parameter
bool hasBetterParam = false;
for (int param = 0; param < call.getParamCount(); ++param) {
const int paramCount = std::min({call.getParamCount(), can1.getParamCount(), can2.getParamCount()});
for (int param = 0; param < paramCount; ++param) {
if (better(*call[param].type, *can1[param].type, *can2[param].type)) {
hasBetterParam = true;
break;
@ -469,7 +478,8 @@ const TFunction* TParseContextBase::selectFunction(
const auto equivalentParams = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool {
// is call -> can2 equivalent to call -> can1 for all the call parameters?
for (int param = 0; param < call.getParamCount(); ++param) {
const int paramCount = std::min({call.getParamCount(), can1.getParamCount(), can2.getParamCount()});
for (int param = 0; param < paramCount; ++param) {
if (better(*call[param].type, *can1[param].type, *can2[param].type) ||
better(*call[param].type, *can2[param].type, *can1[param].type))
return false;
@ -477,6 +487,16 @@ const TFunction* TParseContextBase::selectFunction(
return true;
};
const auto enabled = [this](const TFunction& candidate) -> bool {
bool enabled = candidate.getNumExtensions() == 0;
for (int i = 0; i < candidate.getNumExtensions(); ++i) {
TExtensionBehavior behavior = getExtensionBehavior(candidate.getExtensions()[i]);
if (behavior == EBhEnable || behavior == EBhRequire)
enabled = true;
}
return enabled;
};
const TFunction* incumbent = viableCandidates.front();
for (auto it = viableCandidates.begin() + 1; it != viableCandidates.end(); ++it) {
const TFunction& candidate = *(*it);
@ -492,7 +512,7 @@ const TFunction* TParseContextBase::selectFunction(
// In the case of default parameters, it may have an identical initial set, which is
// also ambiguous
if (betterParam(*incumbent, candidate) || equivalentParams(*incumbent, candidate))
if ((betterParam(*incumbent, candidate) || equivalentParams(*incumbent, candidate)) && enabled(candidate))
tie = true;
}

File diff suppressed because it is too large Load diff

View file

@ -115,7 +115,7 @@ public:
virtual void setLimits(const TBuiltInResource&) = 0;
void checkIndex(const TSourceLoc&, const TType&, int& index);
void checkIndex(const TSourceLoc&, const TType&, int64_t& index);
EShLanguage getLanguage() const { return language; }
void setScanContext(TScanContext* c) { scanContext = c; }
@ -381,10 +381,11 @@ public:
void rValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*) override;
void constantValueCheck(TIntermTyped* node, const char* token);
void integerCheck(const TIntermTyped* node, const char* token);
void arrayIndexCheck(const TIntermTyped* node, const char* token);
void globalCheck(const TSourceLoc&, const char* token);
bool constructorError(const TSourceLoc&, TIntermNode*, TFunction&, TOperator, TType&);
bool constructorTextureSamplerError(const TSourceLoc&, const TFunction&);
void arraySizeCheck(const TSourceLoc&, TIntermTyped* expr, TArraySize&, const char *sizeType, const bool allowZero = false);
void arraySizeCheck(const TSourceLoc&, TIntermTyped* expr, TArraySize&, const char *sizeType, const bool isTypeParameter = false);
bool arrayQualifierError(const TSourceLoc&, const TQualifier&);
bool arrayError(const TSourceLoc&, const TType&);
void arraySizeRequiredCheck(const TSourceLoc&, const TArraySizes&);
@ -397,6 +398,8 @@ public:
void samplerCheck(const TSourceLoc&, const TType&, const TString& identifier, TIntermTyped* initializer);
void atomicUintCheck(const TSourceLoc&, const TType&, const TString& identifier);
void accStructCheck(const TSourceLoc & loc, const TType & type, const TString & identifier);
void hitObjectEXTCheck(const TSourceLoc& loc, const TType& type, const TString& identifier);
void hitObjectNVCheck(const TSourceLoc & loc, const TType & type, const TString & identifier);
void transparentOpaqueCheck(const TSourceLoc&, const TType&, const TString& identifier);
void memberQualifierCheck(glslang::TPublicType&);
void globalQualifierFixCheck(const TSourceLoc&, TQualifier&, bool isMemberCheck = false, const TPublicType* publicType = nullptr);
@ -406,7 +409,7 @@ public:
void setDefaultPrecision(const TSourceLoc&, TPublicType&, TPrecisionQualifier);
int computeSamplerTypeIndex(TSampler&);
TPrecisionQualifier getDefaultPrecision(TPublicType&);
void precisionQualifierCheck(const TSourceLoc&, TBasicType, TQualifier&, bool isCoopMat);
void precisionQualifierCheck(const TSourceLoc&, TBasicType, TQualifier&, bool hasTypeParameter);
void parameterTypeCheck(const TSourceLoc&, TStorageQualifier qualifier, const TType& type);
bool containsFieldWithBasicType(const TType& type ,TBasicType basicType);
TSymbol* redeclareBuiltinVariable(const TSourceLoc&, const TString&, const TQualifier&, const TShaderQualifiers&);
@ -424,7 +427,7 @@ public:
void inductiveLoopCheck(const TSourceLoc&, TIntermNode* init, TIntermLoop* loop);
void arrayLimitCheck(const TSourceLoc&, const TString&, int size);
void limitCheck(const TSourceLoc&, int value, const char* limit, const char* feature);
void coopMatTypeParametersCheck(const TSourceLoc&, const TPublicType&);
void typeParametersCheck(const TSourceLoc&, const TPublicType&);
void inductiveLoopBodyCheck(TIntermNode*, long long loopIndexId, TSymbolTable&);
void constantIndexExpressionCheck(TIntermNode*);
@ -449,8 +452,11 @@ public:
TIntermTyped* addConstructor(const TSourceLoc&, TIntermNode*, const TType&);
TIntermTyped* constructAggregate(TIntermNode*, const TType&, int, const TSourceLoc&);
TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermTyped*, const TSourceLoc&, bool subset);
void makeVariadic(TFunction *F, const TSourceLoc &loc);
TParameter getParamWithDefault(const TPublicType& ty, TString* identifier, TIntermTyped* initializer,
const TSourceLoc& loc);
void inheritMemoryQualifiers(const TQualifier& from, TQualifier& to);
void declareBlock(const TSourceLoc&, TTypeList& typeList, const TString* instanceName = nullptr, TArraySizes* arraySizes = nullptr);
TIntermNode* declareBlock(const TSourceLoc&, TTypeList& typeList, const TString* instanceName = nullptr, TArraySizes* arraySizes = nullptr);
void blockStorageRemap(const TSourceLoc&, const TString*, TQualifier&);
void blockStageIoCheck(const TSourceLoc&, const TQualifier&);
void blockQualifierCheck(const TSourceLoc&, const TQualifier&, bool instanceName);
@ -508,6 +514,8 @@ protected:
TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable);
TIntermTyped* convertInitializerList(const TSourceLoc&, const TType&, TIntermTyped* initializer);
void finish() override;
void handleCoopMat2FunctionCall(const TSourceLoc& loc, const TFunction* fnCandidate, TIntermTyped* result, TIntermNode* arguments);
void handleVector2CoopMatConversionCall(const TSourceLoc& loc, const TFunction* fnCandidate, TIntermTyped* &result, TIntermNode* arguments);
virtual const char* getGlobalUniformBlockName() const override;
virtual void finalizeGlobalUniformBlockLayout(TVariable&) override;

View file

@ -35,14 +35,21 @@
#include "../Include/Common.h"
#include "../Include/PoolAlloc.h"
// Mostly here for target that do not support threads such as WASI.
#ifdef DISABLE_THREAD_SUPPORT
#define THREAD_LOCAL
#else
#define THREAD_LOCAL thread_local
#endif
namespace glslang {
namespace {
thread_local TPoolAllocator* threadPoolAllocator = nullptr;
THREAD_LOCAL TPoolAllocator* threadPoolAllocator = nullptr;
TPoolAllocator* GetDefaultThreadPoolAllocator()
{
thread_local TPoolAllocator defaultAllocator;
THREAD_LOCAL TPoolAllocator defaultAllocator;
return &defaultAllocator;
}
} // anonymous namespace

View file

@ -43,7 +43,7 @@ namespace glslang {
// Code to recursively delete the intermediate tree.
//
struct TRemoveTraverser : TIntermTraverser {
TRemoveTraverser() : TIntermTraverser(false, false, true, false) {}
TRemoveTraverser() : TIntermTraverser(false, false, true, false, true) {}
virtual void visitSymbol(TIntermSymbol* node)
{
@ -103,6 +103,12 @@ struct TRemoveTraverser : TIntermTraverser {
return true;
}
virtual bool visitVariableDecl(TVisit /* visit */, TIntermVariableDecl* decl)
{
delete decl;
return true;
}
};
//

File diff suppressed because it is too large Load diff

View file

@ -53,7 +53,7 @@ public:
explicit TScanContext(TParseContextBase& pc) :
parseContext(pc),
afterType(false), afterStruct(false),
field(false), afterBuffer(false) { }
field(false), afterBuffer(false), inDeclaratorList(false), afterDeclarator(false), angleBracketDepth(0), squareBracketDepth(0), parenDepth(0) { }
virtual ~TScanContext() { }
static void fillInKeywordMap();
@ -82,6 +82,11 @@ protected:
bool afterStruct; // true if we've recognized the STRUCT keyword, so can only be looking for an identifier
bool field; // true if we're on a field, right after a '.'
bool afterBuffer; // true if we've recognized the BUFFER keyword
bool inDeclaratorList; // true if we detected we're in a declarator list like "float a, b;"
bool afterDeclarator; // true if we just saw an identifier after a type (potential declarator)
int angleBracketDepth; // track nesting level of < > to detect template parameters
int squareBracketDepth; // track nesting level of [ ] to detect array expressions
int parenDepth; // track nesting level of ( ) to detect function parameters
TSourceLoc loc;
TParserToken* parserToken;
TPpToken* ppToken;

View file

@ -82,7 +82,10 @@ namespace { // anonymous namespace for file-local functions and symbols
int NumberOfClients = 0;
// global initialization lock
#ifndef DISABLE_THREAD_SUPPORT
std::mutex init_lock;
#endif
using namespace glslang;
@ -294,18 +297,21 @@ int CommonIndex(EProfile profile, EShLanguage language)
//
// To initialize per-stage shared tables, with the common table already complete.
//
void InitializeStageSymbolTable(TBuiltInParseables& builtInParseables, int version, EProfile profile, const SpvVersion& spvVersion,
bool InitializeStageSymbolTable(TBuiltInParseables& builtInParseables, int version, EProfile profile, const SpvVersion& spvVersion,
EShLanguage language, EShSource source, TInfoSink& infoSink, TSymbolTable** commonTable,
TSymbolTable** symbolTables)
{
(*symbolTables[language]).adoptLevels(*commonTable[CommonIndex(profile, language)]);
InitializeSymbolTable(builtInParseables.getStageString(language), version, profile, spvVersion, language, source,
infoSink, *symbolTables[language]);
if (!InitializeSymbolTable(builtInParseables.getStageString(language), version, profile, spvVersion, language, source,
infoSink, *symbolTables[language]))
return false;
builtInParseables.identifyBuiltIns(version, profile, spvVersion, language, *symbolTables[language]);
if (profile == EEsProfile && version >= 300)
(*symbolTables[language]).setNoBuiltInRedeclarations();
if (version == 110)
(*symbolTables[language]).setSeparateNameSpaces();
return true;
}
//
@ -314,6 +320,7 @@ void InitializeStageSymbolTable(TBuiltInParseables& builtInParseables, int versi
//
bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable, TSymbolTable** symbolTables, int version, EProfile profile, const SpvVersion& spvVersion, EShSource source)
{
bool success = true;
std::unique_ptr<TBuiltInParseables> builtInParseables(CreateBuiltInParseables(infoSink, source));
if (builtInParseables == nullptr)
@ -322,70 +329,70 @@ bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable, TS
builtInParseables->initialize(version, profile, spvVersion);
// do the common tables
InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangVertex, source,
success &= InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangVertex, source,
infoSink, *commonTable[EPcGeneral]);
if (profile == EEsProfile)
InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangFragment, source,
success &= InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangFragment, source,
infoSink, *commonTable[EPcFragment]);
// do the per-stage tables
// always have vertex and fragment
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangVertex, source,
success &= InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangVertex, source,
infoSink, commonTable, symbolTables);
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangFragment, source,
success &= InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangFragment, source,
infoSink, commonTable, symbolTables);
// check for tessellation
if ((profile != EEsProfile && version >= 150) ||
(profile == EEsProfile && version >= 310)) {
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTessControl, source,
success &= InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTessControl, source,
infoSink, commonTable, symbolTables);
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTessEvaluation, source,
success &= InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTessEvaluation, source,
infoSink, commonTable, symbolTables);
}
// check for geometry
if ((profile != EEsProfile && version >= 150) ||
(profile == EEsProfile && version >= 310))
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangGeometry, source,
success &= InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangGeometry, source,
infoSink, commonTable, symbolTables);
// check for compute
if ((profile != EEsProfile && version >= 420) ||
(profile == EEsProfile && version >= 310))
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangCompute, source,
success &= InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangCompute, source,
infoSink, commonTable, symbolTables);
// check for ray tracing stages
if (profile != EEsProfile && version >= 450) {
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangRayGen, source,
success &= InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangRayGen, source,
infoSink, commonTable, symbolTables);
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangIntersect, source,
success &= InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangIntersect, source,
infoSink, commonTable, symbolTables);
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangAnyHit, source,
success &= InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangAnyHit, source,
infoSink, commonTable, symbolTables);
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangClosestHit, source,
success &= InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangClosestHit, source,
infoSink, commonTable, symbolTables);
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangMiss, source,
success &= InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangMiss, source,
infoSink, commonTable, symbolTables);
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangCallable, source,
success &= InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangCallable, source,
infoSink, commonTable, symbolTables);
}
// check for mesh
if ((profile != EEsProfile && version >= 450) ||
(profile == EEsProfile && version >= 320))
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangMesh, source,
success &= InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangMesh, source,
infoSink, commonTable, symbolTables);
// check for task
if ((profile != EEsProfile && version >= 450) ||
(profile == EEsProfile && version >= 320))
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTask, source,
success &= InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTask, source,
infoSink, commonTable, symbolTables);
return true;
return success;
}
bool AddContextSpecificSymbols(const TBuiltInResource* resources, TInfoSink& infoSink, TSymbolTable& symbolTable, int version,
@ -397,7 +404,8 @@ bool AddContextSpecificSymbols(const TBuiltInResource* resources, TInfoSink& inf
return false;
builtInParseables->initialize(*resources, version, profile, spvVersion, language);
InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, language, source, infoSink, symbolTable);
if (!InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, language, source, infoSink, symbolTable))
return false;
builtInParseables->identifyBuiltIns(version, profile, spvVersion, language, symbolTable, *resources);
return true;
@ -415,20 +423,24 @@ bool AddContextSpecificSymbols(const TBuiltInResource* resources, TInfoSink& inf
// This only gets done the first time any thread needs a particular symbol table
// (lazy evaluation).
//
void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& spvVersion, EShSource source)
bool SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& spvVersion, EShSource source)
{
TInfoSink infoSink;
bool success;
// Make sure only one thread tries to do this at a time
#ifndef DISABLE_THREAD_SUPPORT
const std::lock_guard<std::mutex> lock(init_lock);
#endif
// See if it's already been done for this version/profile combination
int versionIndex = MapVersionToIndex(version);
int spvVersionIndex = MapSpvVersionToIndex(spvVersion);
int profileIndex = MapProfileToIndex(profile);
int sourceIndex = MapSourceToIndex(source);
if (CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][EPcGeneral])
return;
if (CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][EPcGeneral]) {
return true;
}
// Switch to a new pool
TPoolAllocator& previousAllocator = GetThreadPoolAllocator();
@ -444,7 +456,10 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp
stageTables[stage] = new TSymbolTable;
// Generate the local symbol tables using the new pool
InitializeSymbolTables(infoSink, commonTable, stageTables, version, profile, spvVersion, source);
if (!InitializeSymbolTables(infoSink, commonTable, stageTables, version, profile, spvVersion, source)) {
success = false;
goto cleanup;
}
// Switch to the process-global pool
SetThreadPoolAllocator(PerProcessGPA);
@ -466,7 +481,9 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp
SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->readOnly();
}
}
success = true;
cleanup:
// Clean up the local tables before deleting the pool they used.
for (int precClass = 0; precClass < EPcCount; ++precClass)
delete commonTable[precClass];
@ -475,6 +492,8 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp
delete builtInPoolAllocator;
SetThreadPoolAllocator(&previousAllocator);
return success;
}
// Function to Print all builtins
@ -788,7 +807,7 @@ bool ProcessDeferred(
// set version/profile to defaultVersion/defaultProfile regardless of the #version
// directive in the source code
bool forceDefaultVersionAndProfile,
int overrideVersion, // overrides version specified by #verison or default version
int overrideVersion, // overrides version specified by #version or default version
bool forwardCompatible, // give errors for use of deprecated features
EShMessages messages, // warnings/errors/AST; things to print out
TIntermediate& intermediate, // returned tree, etc.
@ -910,7 +929,9 @@ bool ProcessDeferred(
intermediate.addSourceText(strings[numPre + s], lengths[numPre + s]);
}
}
SetupBuiltinSymbolTable(version, profile, spvVersion, source);
if (!SetupBuiltinSymbolTable(version, profile, spvVersion, source)) {
return false;
}
TSymbolTable* cachedTable = SharedSymbolTables[MapVersionToIndex(version)]
[MapSpvVersionToIndex(spvVersion)]
@ -1311,17 +1332,14 @@ bool CompileDeferred(
//
int ShInitialize()
{
#ifndef DISABLE_THREAD_SUPPORT
const std::lock_guard<std::mutex> lock(init_lock);
#endif
++NumberOfClients;
if (PerProcessGPA == nullptr)
PerProcessGPA = new TPoolAllocator();
glslang::TScanContext::fillInKeywordMap();
#ifdef ENABLE_HLSL
glslang::HlslScanContext::fillInKeywordMap();
#endif
return 1;
}
@ -1371,7 +1389,9 @@ void ShDestruct(ShHandle handle)
//
int ShFinalize()
{
#ifndef DISABLE_THREAD_SUPPORT
const std::lock_guard<std::mutex> lock(init_lock);
#endif
--NumberOfClients;
assert(NumberOfClients >= 0);
if (NumberOfClients > 0)
@ -1408,11 +1428,6 @@ int ShFinalize()
PerProcessGPA = nullptr;
}
glslang::TScanContext::deleteKeywordMap();
#ifdef ENABLE_HLSL
glslang::HlslScanContext::deleteKeywordMap();
#endif
return 1;
}
@ -1717,6 +1732,10 @@ public:
virtual bool compile(TIntermNode*, int = 0, EProfile = ENoProfile) { return true; }
};
TIoMapper* GetGlslIoMapper() {
return static_cast<TIoMapper*>(new TGlslIoMapper());
}
TShader::TShader(EShLanguage s)
: stage(s), lengths(nullptr), stringNames(nullptr), preamble(""), overrideVersion(0)
{
@ -1849,6 +1868,9 @@ void TShader::setGlobalUniformBinding(unsigned int binding) { intermediate->setG
void TShader::setAtomicCounterBlockName(const char* name) { intermediate->setAtomicCounterBlockName(name); }
void TShader::setAtomicCounterBlockSet(unsigned int set) { intermediate->setAtomicCounterBlockSet(set); }
void TShader::addSourceText(const char* text, size_t len) { intermediate->addSourceText(text, len); }
void TShader::setSourceFile(const char* file) { intermediate->setSourceFile(file); }
#ifdef ENABLE_HLSL
// See comment above TDefaultHlslIoMapper in iomapper.cpp:
void TShader::setHlslIoMapping(bool hlslIoMap) { intermediate->setHlslIoMapping(hlslIoMap); }
@ -1957,6 +1979,14 @@ bool TProgram::link(EShMessages messages)
error = true;
}
if (messages & EShMsgAST) {
for (int s = 0; s < EShLangCount; ++s) {
if (intermediate[s] == nullptr)
continue;
intermediate[s]->output(*infoSink, true);
}
}
return ! error;
}
@ -2022,9 +2052,6 @@ bool TProgram::linkStage(EShLanguage stage, EShMessages messages)
}
intermediate[stage]->finalCheck(*infoSink, (messages & EShMsgKeepUncalled) != 0);
if (messages & EShMsgAST)
intermediate[stage]->output(*infoSink, true);
return intermediate[stage]->getNumErrors() == 0;
}
@ -2033,7 +2060,7 @@ bool TProgram::linkStage(EShLanguage stage, EShMessages messages)
//
// Return true if no errors.
//
bool TProgram::crossStageCheck(EShMessages) {
bool TProgram::crossStageCheck(EShMessages messages) {
// make temporary intermediates to hold the linkage symbols for each linking interface
// while we do the checks
@ -2048,9 +2075,27 @@ bool TProgram::crossStageCheck(EShMessages) {
activeStages.push_back(intermediate[s]);
}
class TFinalLinkTraverser : public TIntermTraverser {
public:
TFinalLinkTraverser() { }
virtual ~TFinalLinkTraverser() { }
virtual void visitSymbol(TIntermSymbol* symbol)
{
// Implicitly size arrays.
// If an unsized array is left as unsized, it effectively
// becomes run-time sized.
symbol->getWritableType().adoptImplicitArraySizes(false);
}
} finalLinkTraverser;
// no extra linking if there is only one stage
if (! (activeStages.size() > 1))
if (! (activeStages.size() > 1)) {
if (activeStages.size() == 1 && activeStages[0]->getTreeRoot()) {
activeStages[0]->getTreeRoot()->traverse(&finalLinkTraverser);
}
return true;
}
// setup temporary tree to hold unfirom objects from different stages
TIntermediate* firstIntermediate = activeStages.front();
@ -2072,6 +2117,12 @@ bool TProgram::crossStageCheck(EShMessages) {
}
error |= uniforms.getNumErrors() != 0;
// update implicit array sizes across shader stages
for (unsigned int i = 0; i < activeStages.size(); ++i) {
activeStages[i]->mergeImplicitArraySizes(*infoSink, uniforms);
activeStages[i]->getTreeRoot()->traverse(&finalLinkTraverser);
}
// copy final definition of global block back into each stage
for (unsigned int i = 0; i < activeStages.size(); ++i) {
// We only want to merge into already existing global uniform blocks.
@ -2084,8 +2135,15 @@ bool TProgram::crossStageCheck(EShMessages) {
// compare cross stage symbols for each stage boundary
for (unsigned int i = 1; i < activeStages.size(); ++i) {
activeStages[i - 1]->checkStageIO(*infoSink, *activeStages[i]);
error |= (activeStages[i - 1]->getNumErrors() != 0);
activeStages[i - 1]->checkStageIO(*infoSink, *activeStages[i], messages);
error |= (activeStages[i - 1]->getNumErrors() != 0 || activeStages[i]->getNumErrors() != 0);
}
// if requested, optimize cross stage IO
if (messages & EShMsgLinkTimeOptimization) {
for (unsigned int i = 1; i < activeStages.size(); ++i) {
activeStages[i - 1]->optimizeStageIO(*infoSink, *activeStages[i]);
}
}
return !error;
@ -2105,11 +2163,15 @@ const char* TProgram::getInfoDebugLog()
// Reflection implementation.
//
unsigned int TObjectReflection::layoutLocation() const { return type->getQualifier().layoutLocation; }
bool TProgram::buildReflection(int opts)
{
if (! linked || reflection != nullptr)
return false;
SetThreadPoolAllocator(pool);
int firstStage = EShLangVertex, lastStage = EShLangFragment;
if (opts & EShReflectionIntermediateIO) {
@ -2138,6 +2200,7 @@ bool TProgram::buildReflection(int opts)
}
unsigned TProgram::getLocalSize(int dim) const { return reflection->getLocalSize(dim); }
unsigned TProgram::getTileShadingRateQCOM(int dim) const { return reflection->getTileShadingRateQCOM(dim); }
int TProgram::getReflectionIndex(const char* name) const { return reflection->getIndex(name); }
int TProgram::getReflectionPipeIOIndex(const char* name, const bool inOrOut) const
{ return reflection->getPipeIOIndex(name, inOrOut); }
@ -2158,6 +2221,12 @@ int TProgram::getNumAtomicCounters() const { return r
const TObjectReflection& TProgram::getAtomicCounter(int index) const { return reflection->getAtomicCounter(index); }
void TProgram::dumpReflection() { if (reflection != nullptr) reflection->dump(); }
TIoMapResolver* TProgram::getGlslIoResolver(EShLanguage stage) {
auto *intermediate = getIntermediate(stage);
if (!intermediate)
return NULL;
return static_cast<TIoMapResolver*>(new TDefaultGlslIoResolver(*intermediate));
}
//
// I/O mapping implementation.
//
@ -2165,6 +2234,9 @@ bool TProgram::mapIO(TIoMapResolver* pResolver, TIoMapper* pIoMapper)
{
if (! linked)
return false;
SetThreadPoolAllocator(pool);
TIoMapper* ioMapper = nullptr;
TIoMapper defaultIOMapper;
if (pIoMapper == nullptr)

View file

@ -55,11 +55,16 @@ namespace glslang {
//
void TType::buildMangledName(TString& mangledName) const
{
if (isMatrix())
if (isTensorARM())
mangledName += 'T';
else if (isMatrix())
mangledName += 'm';
else if (isVector())
mangledName += 'v';
if (isCoopVecNV())
mangledName += "coopvec";
switch (basicType) {
case EbtFloat: mangledName += 'f'; break;
case EbtInt: mangledName += 'i'; break;
@ -67,6 +72,9 @@ void TType::buildMangledName(TString& mangledName) const
case EbtBool: mangledName += 'b'; break;
case EbtDouble: mangledName += 'd'; break;
case EbtFloat16: mangledName += "f16"; break;
case EbtBFloat16: mangledName += "bf16"; break;
case EbtFloatE5M2: mangledName += "fe5m2"; break;
case EbtFloatE4M3: mangledName += "fe4m3"; break;
case EbtInt8: mangledName += "i8"; break;
case EbtUint8: mangledName += "u8"; break;
case EbtInt16: mangledName += "i16"; break;
@ -78,6 +86,9 @@ void TType::buildMangledName(TString& mangledName) const
case EbtRayQuery: mangledName += "rq"; break;
case EbtSpirvType: mangledName += "spv-t"; break;
case EbtHitObjectNV: mangledName += "ho"; break;
case EbtHitObjectEXT: mangledName += "ho"; break;
case EbtTensorLayoutNV: mangledName += "tl"; break;
case EbtTensorViewNV: mangledName += "tv"; break;
case EbtSampler:
switch (sampler.type) {
case EbtFloat16: mangledName += "f16"; break;
@ -161,6 +172,23 @@ void TType::buildMangledName(TString& mangledName) const
mangledName += static_cast<char>('0' + getMatrixRows());
}
if (typeParameters) {
const int maxSize = 11;
char buf[maxSize];
for (int i = 0; i < typeParameters->arraySizes->getNumDims(); ++i) {
if (typeParameters->arraySizes->getDimNode(i)) {
if (typeParameters->arraySizes->getDimNode(i)->getAsSymbolNode())
snprintf(buf, maxSize, "s%lld", typeParameters->arraySizes->getDimNode(i)->getAsSymbolNode()->getId());
else
snprintf(buf, maxSize, "s%p", typeParameters->arraySizes->getDimNode(i));
} else
snprintf(buf, maxSize, "%d", typeParameters->arraySizes->getDimSize(i));
mangledName += '<';
mangledName += buf;
mangledName += '>';
}
}
if (arraySizes) {
const int maxSize = 11;
char buf[maxSize];
@ -169,7 +197,7 @@ void TType::buildMangledName(TString& mangledName) const
if (arraySizes->getDimNode(i)->getAsSymbolNode())
snprintf(buf, maxSize, "s%lld", arraySizes->getDimNode(i)->getAsSymbolNode()->getId());
else
snprintf(buf, maxSize, "s%p", arraySizes->getDimNode(i));
snprintf(buf, maxSize, "s%p", (void*)(arraySizes->getDimNode(i)));
} else
snprintf(buf, maxSize, "%d", arraySizes->getDimSize(i));
mangledName += '[';
@ -319,6 +347,24 @@ void TSymbolTableLevel::setFunctionExtensions(const char* name, int num, const c
}
}
// Call the callback function to determine the required extensions
void TSymbolTableLevel::setFunctionExtensionsCallback(const char* name, std::function<std::vector<const char *>(const char *)> const &func)
{
tLevel::const_iterator candidate = level.lower_bound(name);
while (candidate != level.end()) {
const TString& candidateName = (*candidate).first;
TString::size_type parenAt = candidateName.find_first_of('(');
if (parenAt != candidateName.npos && candidateName.compare(0, parenAt, name) == 0) {
TSymbol* symbol = candidate->second;
auto exts = func(candidateName.c_str());
symbol->setExtensions(exts.size(), exts.data());
} else
break;
++candidate;
}
}
// Make a single function require an extension(s). i.e., this will only set the extensions for the symbol that matches 'name' exactly.
// This is different from setFunctionExtensions, which uses std::map::lower_bound to effectively set all symbols that start with 'name'.
// Should only be used for a version/profile that actually needs the extension(s).
@ -344,6 +390,7 @@ void TSymbolTableLevel::readOnly()
TSymbol::TSymbol(const TSymbol& copyOf)
{
name = NewPoolTString(copyOf.name->c_str());
mangledName = NewPoolTString(copyOf.mangledName->c_str());
uniqueId = copyOf.uniqueId;
writable = true;
}
@ -397,6 +444,7 @@ TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf)
defined = copyOf.defined;
prototyped = copyOf.prototyped;
implicitThis = copyOf.implicitThis;
variadic = copyOf.variadic;
illegalImplicitThis = copyOf.illegalImplicitThis;
defaultParamCount = copyOf.defaultParamCount;
spirvInst = copyOf.spirvInst;

View file

@ -69,6 +69,9 @@
#include "../Include/intermediate.h"
#include "../Include/InfoSink.h"
#include <functional>
#include <unordered_map>
namespace glslang {
//
@ -84,7 +87,8 @@ typedef TVector<const char*> TExtensionList;
class TSymbol {
public:
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
explicit TSymbol(const TString *n) : name(n), uniqueId(0), extensions(nullptr), writable(true) { }
explicit TSymbol(const TString *n, const TString *mn) : name(n), mangledName(mn), uniqueId(0), extensions(nullptr), writable(true) { }
explicit TSymbol(const TString *n) : TSymbol(n, n) { }
virtual TSymbol* clone() const = 0;
virtual ~TSymbol() { } // rely on all symbol owned memory coming from the pool
@ -96,7 +100,7 @@ public:
newName.append(*name);
changeName(NewPoolTString(newName.c_str()));
}
virtual const TString& getMangledName() const { return getName(); }
virtual const TString& getMangledName() const { return *mangledName; }
virtual TFunction* getAsFunction() { return nullptr; }
virtual const TFunction* getAsFunction() const { return nullptr; }
virtual TVariable* getAsVariable() { return nullptr; }
@ -128,6 +132,7 @@ protected:
TSymbol& operator=(const TSymbol&);
const TString *name;
const TString *mangledName;
unsigned long long uniqueId; // For cross-scope comparing during code generation
// For tracking what extensions must be present
@ -154,7 +159,9 @@ protected:
class TVariable : public TSymbol {
public:
TVariable(const TString *name, const TType& t, bool uT = false )
: TSymbol(name),
: TVariable(name, name, t, uT) {}
TVariable(const TString *name, const TString *mangledName, const TType& t, bool uT = false )
: TSymbol(name, mangledName),
userType(uT),
constSubtree(nullptr),
memberExtensions(nullptr),
@ -228,6 +235,13 @@ struct TParameter {
name = nullptr;
type = param.type->clone();
defaultValue = param.defaultValue;
if (defaultValue) {
// The defaultValue of a builtin is created in a TPoolAllocator that no longer exists
// when parsing the user program, so make a deep copy.
if (const auto *constUnion = defaultValue->getAsConstantUnion()) {
defaultValue = new TIntermConstantUnion(*constUnion->getConstArray().clone(), constUnion->getType());
}
}
return *this;
}
TBuiltInVariable getDeclaredBuiltIn() const { return type->getQualifier().declaredBuiltIn; }
@ -241,12 +255,12 @@ public:
explicit TFunction(TOperator o) :
TSymbol(nullptr),
op(o),
defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), defaultParamCount(0) { }
defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), variadic(false), defaultParamCount(0) { }
TFunction(const TString *name, const TType& retType, TOperator tOp = EOpNull) :
TSymbol(name),
mangledName(*name + '('),
op(tOp),
defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), defaultParamCount(0),
defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), variadic(false), defaultParamCount(0),
linkType(ELinkNone)
{
returnType.shallowCopy(retType);
@ -264,6 +278,7 @@ public:
virtual void addParameter(TParameter& p)
{
assert(writable);
assert(!variadic && "cannot add more parameters if function is marked variadic");
parameters.push_back(p);
p.type->appendMangledName(mangledName);
@ -306,6 +321,13 @@ public:
virtual bool hasImplicitThis() const { return implicitThis; }
virtual void setIllegalImplicitThis() { assert(writable); illegalImplicitThis = true; }
virtual bool hasIllegalImplicitThis() const { return illegalImplicitThis; }
virtual void setVariadic() {
assert(writable);
assert(!variadic && "function was already marked variadic");
variadic = true;
mangledName += 'z';
}
virtual bool isVariadic() const { return variadic; }
// Return total number of parameters
virtual int getParamCount() const { return static_cast<int>(parameters.size()); }
@ -348,6 +370,7 @@ protected:
// even if it finds member variables in the symbol table.
// This is important for a static member function that has member variables in scope,
// but is not allowed to use them, or see hidden symbols instead.
bool variadic;
int defaultParamCount;
TSpirvInstruction spirvInst; // SPIR-V instruction qualifiers
@ -483,6 +506,11 @@ public:
retargetedSymbols.push_back({from, to});
}
void collectRetargetedSymbols(std::unordered_multimap<std::string, std::string> &out) const {
for (const auto &[fromName, toName] : retargetedSymbols)
out.insert({std::string{toName}, std::string{fromName}});
}
TSymbol* find(const TString& name) const
{
tLevel::const_iterator it = level.find(name);
@ -576,6 +604,7 @@ public:
void relateToOperator(const char* name, TOperator op);
void setFunctionExtensions(const char* name, int num, const char* const extensions[]);
void setFunctionExtensionsCallback(const char* name, std::function<std::vector<const char *>(const char *)> const &func);
void setSingleFunctionExtensions(const char* name, int num, const char* const extensions[]);
void dump(TInfoSink& infoSink, bool complete = false) const;
TSymbolTableLevel* clone() const;
@ -639,9 +668,10 @@ public:
//
protected:
static const uint32_t LevelFlagBitOffset = 56;
static const int globalLevel = 3;
static constexpr int builtinLevel = 2;
static constexpr int globalLevel = 3;
static bool isSharedLevel(int level) { return level <= 1; } // exclude all per-compile levels
static bool isBuiltInLevel(int level) { return level <= 2; } // exclude user globals
static bool isBuiltInLevel(int level) { return level <= builtinLevel; } // exclude user globals
static bool isGlobalLevel(int level) { return level <= globalLevel; } // include user globals
public:
bool isEmpty() { return table.size() == 0; }
@ -806,6 +836,13 @@ public:
table[level]->retargetSymbol(from, to);
}
std::unordered_multimap<std::string, std::string> collectBuiltinAlias() {
std::unordered_multimap<std::string, std::string> allRetargets;
for (int level = 0; level <= std::min(currentLevel(), builtinLevel); ++level)
table[level]->collectRetargetedSymbols(allRetargets);
return allRetargets;
}
// Find of a symbol that returns how many layers deep of nested
// structures-with-member-functions ('this' scopes) deep the symbol was
@ -878,6 +915,12 @@ public:
table[level]->setFunctionExtensions(name, num, extensions);
}
void setFunctionExtensionsCallback(const char* name, std::function<std::vector<const char *>(const char *)> const &func)
{
for (unsigned int level = 0; level < table.size(); ++level)
table[level]->setFunctionExtensionsCallback(name, func);
}
void setSingleFunctionExtensions(const char* name, int num, const char* const extensions[])
{
for (unsigned int level = 0; level < table.size(); ++level)

View file

@ -165,7 +165,8 @@ void TParseVersions::initializeExtensionBehavior()
const extensionData exts[] = { {E_GL_EXT_ray_tracing, EShTargetSpv_1_4},
{E_GL_NV_ray_tracing_motion_blur, EShTargetSpv_1_4},
{E_GL_EXT_mesh_shader, EShTargetSpv_1_4}
{E_GL_EXT_mesh_shader, EShTargetSpv_1_4},
{E_GL_NV_cooperative_matrix2, EShTargetSpv_1_6}
};
for (size_t ii = 0; ii < sizeof(exts) / sizeof(exts[0]); ii++) {
@ -187,7 +188,7 @@ void TParseVersions::initializeExtensionBehavior()
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_gpu_shader5] = EBhDisable;
extensionBehavior[E_GL_ARB_separate_shader_objects] = EBhDisable;
extensionBehavior[E_GL_ARB_compute_shader] = EBhDisable;
extensionBehavior[E_GL_ARB_tessellation_shader] = EBhDisable;
@ -224,9 +225,11 @@ void TParseVersions::initializeExtensionBehavior()
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_NV_gpu_shader5] = EBhDisable;
extensionBehavior[E_GL_ARB_draw_instanced] = EBhDisable;
extensionBehavior[E_GL_ARB_bindless_texture] = EBhDisable;
extensionBehavior[E_GL_ARB_fragment_coord_conventions] = EBhDisable;
extensionBehavior[E_GL_ARB_conservative_depth] = EBhDisable;
extensionBehavior[E_GL_KHR_shader_subgroup_basic] = EBhDisable;
@ -265,8 +268,10 @@ void TParseVersions::initializeExtensionBehavior()
extensionBehavior[E_GL_EXT_expect_assume] = EBhDisable;
extensionBehavior[E_GL_EXT_control_flow_attributes2] = EBhDisable;
extensionBehavior[E_GL_EXT_spec_constant_composites] = EBhDisable;
extensionBehavior[E_GL_KHR_cooperative_matrix] = EBhDisable;
extensionBehavior[E_GL_NV_cooperative_vector] = EBhDisable;
// #line and #include
extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive] = EBhDisable;
@ -309,13 +314,19 @@ void TParseVersions::initializeExtensionBehavior()
extensionBehavior[E_GL_NV_shader_invocation_reorder] = EBhDisable;
extensionBehavior[E_GL_NV_displacement_micromap] = EBhDisable;
extensionBehavior[E_GL_NV_shader_atomic_fp16_vector] = EBhDisable;
extensionBehavior[E_GL_NV_cooperative_matrix2] = EBhDisable;
extensionBehavior[E_GL_NV_cluster_acceleration_structure] = EBhDisable;
extensionBehavior[E_GL_NV_linear_swept_spheres] = EBhDisable;
// ARM
extensionBehavior[E_GL_ARM_shader_core_builtins] = EBhDisable;
extensionBehavior[E_GL_ARM_tensors] = EBhDisable;
// QCOM
extensionBehavior[E_GL_QCOM_image_processing] = EBhDisable;
extensionBehavior[E_GL_QCOM_image_processing2] = EBhDisable;
extensionBehavior[E_GL_QCOM_tile_shading] = EBhDisable;
extensionBehavior[E_GL_QCOM_cooperative_matrix_conversion] = EBhDisable;
// AEP
extensionBehavior[E_GL_ANDROID_extension_pack_es31a] = EBhDisable;
@ -370,6 +381,14 @@ void TParseVersions::initializeExtensionBehavior()
extensionBehavior[E_GL_EXT_texture_shadow_lod] = EBhDisable;
extensionBehavior[E_GL_EXT_draw_instanced] = EBhDisable;
extensionBehavior[E_GL_EXT_texture_array] = EBhDisable;
extensionBehavior[E_GL_EXT_texture_offset_non_const] = EBhDisable;
extensionBehavior[E_GL_EXT_nontemporal_keyword] = EBhDisable;
extensionBehavior[E_GL_EXT_bfloat16] = EBhDisable;
extensionBehavior[E_GL_EXT_float_e4m3] = EBhDisable;
extensionBehavior[E_GL_EXT_float_e5m2] = EBhDisable;
extensionBehavior[E_GL_EXT_uniform_buffer_unsized_array] = EBhDisable;
extensionBehavior[E_GL_EXT_shader_64bit_indexing] = EBhDisable;
extensionBehavior[E_GL_EXT_conservative_depth] = EBhDisable;
// OVR extensions
extensionBehavior[E_GL_OVR_multiview] = EBhDisable;
@ -393,6 +412,10 @@ void TParseVersions::initializeExtensionBehavior()
extensionBehavior[E_GL_EXT_shader_atomic_float] = EBhDisable;
extensionBehavior[E_GL_EXT_shader_atomic_float2] = EBhDisable;
extensionBehavior[E_GL_EXT_integer_dot_product] = EBhDisable;
extensionBehavior[E_GL_EXT_shader_invocation_reorder] = EBhDisable;
// Record extensions not for spv.
spvUnsupportedExt.push_back(E_GL_ARB_bindless_texture);
}
@ -414,6 +437,7 @@ void TParseVersions::getPreamble(std::string& preamble)
"#define GL_EXT_shader_texture_lod 1\n"
"#define GL_EXT_shadow_samplers 1\n"
"#define GL_EXT_fragment_shading_rate 1\n"
"#define GL_EXT_conservative_depth 1\n"
// AEP
"#define GL_ANDROID_extension_pack_es31a 1\n"
@ -448,6 +472,8 @@ void TParseVersions::getPreamble(std::string& preamble)
"#define GL_QCOM_image_processing 1\n"
"#define GL_QCOM_image_processing2 1\n"
"#define GL_QCOM_tile_shading 1\n"
"#define GL_QCOM_cooperative_matrix_conversion 1\n"
;
if (version >= 300) {
@ -498,8 +524,10 @@ void TParseVersions::getPreamble(std::string& preamble)
"#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_NV_gpu_shader5 1\n"
"#define GL_ARB_draw_instanced 1\n"
"#define GL_ARB_fragment_coord_conventions 1\n"
"#define GL_ARB_conservative_depth 1\n"
"#define GL_EXT_shader_non_constant_global_initializers 1\n"
"#define GL_EXT_shader_image_load_formatted 1\n"
@ -519,6 +547,7 @@ void TParseVersions::getPreamble(std::string& preamble)
"#define GL_EXT_fragment_shading_rate 1\n"
"#define GL_EXT_shared_memory_block 1\n"
"#define GL_EXT_shader_integer_mix 1\n"
"#define GL_EXT_spec_constant_composites 1\n"
// GL_KHR_shader_subgroup
"#define GL_KHR_shader_subgroup_basic 1\n"
@ -572,9 +601,12 @@ void TParseVersions::getPreamble(std::string& preamble)
"#define GL_NV_cooperative_matrix 1\n"
"#define GL_NV_integer_cooperative_matrix 1\n"
"#define GL_NV_shader_invocation_reorder 1\n"
"#define GL_NV_cooperative_matrix2 1\n"
"#define GL_QCOM_image_processing 1\n"
"#define GL_QCOM_image_processing2 1\n"
"#define GL_QCOM_tile_shading 1\n"
"#define GL_QCOM_cooperative_matrix_conversion 1\n"
"#define GL_EXT_shader_explicit_arithmetic_types 1\n"
"#define GL_EXT_shader_explicit_arithmetic_types_int8 1\n"
@ -598,6 +630,15 @@ void TParseVersions::getPreamble(std::string& preamble)
"#define GL_EXT_texture_array 1\n"
"#define GL_EXT_control_flow_attributes2 1\n"
"#define GL_EXT_integer_dot_product 1\n"
"#define GL_EXT_bfloat16 1\n"
"#define GL_EXT_float_e5m2 1\n"
"#define GL_EXT_float_e4m3 1\n"
"#define GL_EXT_uniform_buffer_unsized_array 1\n"
"#define GL_EXT_shader_64bit_indexing 1\n"
"#define GL_EXT_shader_invocation_reorder 1\n"
;
if (spvVersion.spv == 0) {
@ -630,6 +671,11 @@ void TParseVersions::getPreamble(std::string& preamble)
;
}
if ((!isEsProfile() && version >= 130) ||
(isEsProfile() && version >= 300)) {
preamble += "#define GL_EXT_texture_offset_non_const 1\n";
}
if (version >= 300 /* both ES and non-ES */) {
preamble +=
"#define GL_OVR_multiview 1\n"
@ -773,7 +819,7 @@ void TParseVersions::profileRequires(const TSourceLoc& loc, int profileMask, int
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);
infoSink.info.message(EPrefixWarning, ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), loc, messages & EShMsgAbsolutePath, messages & EShMsgDisplayErrorColumn);
[[fallthrough]];
case EBhRequire:
case EBhEnable:
@ -811,7 +857,8 @@ void TParseVersions::checkDeprecated(const TSourceLoc& loc, int profileMask, int
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);
String(depVersion) + "; may be removed in future release").c_str(),
loc, messages & EShMsgAbsolutePath, messages & EShMsgDisplayErrorColumn);
}
}
}
@ -848,11 +895,14 @@ bool TParseVersions::checkExtensionsRequested(const TSourceLoc& loc, int numExte
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);
infoSink.info.message(EPrefixWarning, "The following extension must be enabled to use this feature:", loc,
messages & EShMsgAbsolutePath, messages & EShMsgDisplayErrorColumn);
behavior = EBhWarn;
}
if (behavior == EBhWarn) {
infoSink.info.message(EPrefixWarning, ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), loc);
infoSink.info.message(EPrefixWarning,
("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(),
loc, messages & EShMsgAbsolutePath, messages & EShMsgDisplayErrorColumn);
warned = true;
}
}
@ -1015,6 +1065,8 @@ void TParseVersions::updateExtensionBehavior(int line, const char* extension, co
updateExtensionBehavior(line, "GL_EXT_buffer_reference", behaviorString);
else if (strcmp(extension, "GL_NV_integer_cooperative_matrix") == 0)
updateExtensionBehavior(line, "GL_NV_cooperative_matrix", behaviorString);
else if (strcmp(extension, "GL_NV_cooperative_matrix2") == 0)
updateExtensionBehavior(line, "GL_KHR_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);
@ -1050,6 +1102,9 @@ void TParseVersions::updateExtensionBehavior(int line, const char* extension, co
intermediate.updateNumericFeature(TNumericFeatures::gpu_shader_int16, on);
else if (strcmp(extension, "GL_AMD_gpu_shader_half_float") == 0)
intermediate.updateNumericFeature(TNumericFeatures::gpu_shader_half_float, on);
else if (strcmp(extension, "GL_NV_gpu_shader5") == 0) {
intermediate.updateNumericFeature(TNumericFeatures::nv_gpu_shader5_types, on);
}
}
void TParseVersions::updateExtensionBehavior(const char* extension, TExtensionBehavior behavior)
@ -1177,6 +1232,7 @@ bool TParseVersions::float16Arithmetic()
const char* const extensions[] = {
E_GL_AMD_gpu_shader_half_float,
E_GL_EXT_shader_explicit_arithmetic_types,
E_GL_NV_gpu_shader5,
E_GL_EXT_shader_explicit_arithmetic_types_float16};
return extensionsTurnedOn(sizeof(extensions)/sizeof(extensions[0]), extensions);
}
@ -1186,6 +1242,7 @@ bool TParseVersions::int16Arithmetic()
const char* const extensions[] = {
E_GL_AMD_gpu_shader_int16,
E_GL_EXT_shader_explicit_arithmetic_types,
E_GL_NV_gpu_shader5,
E_GL_EXT_shader_explicit_arithmetic_types_int16};
return extensionsTurnedOn(sizeof(extensions)/sizeof(extensions[0]), extensions);
}
@ -1194,6 +1251,7 @@ bool TParseVersions::int8Arithmetic()
{
const char* const extensions[] = {
E_GL_EXT_shader_explicit_arithmetic_types,
E_GL_NV_gpu_shader5,
E_GL_EXT_shader_explicit_arithmetic_types_int8};
return extensionsTurnedOn(sizeof(extensions)/sizeof(extensions[0]), extensions);
}
@ -1208,6 +1266,7 @@ void TParseVersions::requireFloat16Arithmetic(const TSourceLoc& loc, const char*
const char* const extensions[] = {
E_GL_AMD_gpu_shader_half_float,
E_GL_EXT_shader_explicit_arithmetic_types,
E_GL_NV_gpu_shader5,
E_GL_EXT_shader_explicit_arithmetic_types_float16};
requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, combined.c_str());
}
@ -1222,6 +1281,7 @@ void TParseVersions::requireInt16Arithmetic(const TSourceLoc& loc, const char* o
const char* const extensions[] = {
E_GL_AMD_gpu_shader_int16,
E_GL_EXT_shader_explicit_arithmetic_types,
E_GL_NV_gpu_shader5,
E_GL_EXT_shader_explicit_arithmetic_types_int16};
requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, combined.c_str());
}
@ -1235,6 +1295,7 @@ void TParseVersions::requireInt8Arithmetic(const TSourceLoc& loc, const char* op
const char* const extensions[] = {
E_GL_EXT_shader_explicit_arithmetic_types,
E_GL_NV_gpu_shader5,
E_GL_EXT_shader_explicit_arithmetic_types_int8};
requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, combined.c_str());
}
@ -1246,18 +1307,50 @@ void TParseVersions::float16ScalarVectorCheck(const TSourceLoc& loc, const char*
E_GL_AMD_gpu_shader_half_float,
E_GL_EXT_shader_16bit_storage,
E_GL_EXT_shader_explicit_arithmetic_types,
E_GL_NV_gpu_shader5,
E_GL_EXT_shader_explicit_arithmetic_types_float16};
requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op);
}
}
void TParseVersions::bfloat16ScalarVectorCheck(const TSourceLoc& loc, const char* op, bool builtIn)
{
if (!builtIn) {
const char* const extensions[] = {
E_GL_EXT_bfloat16,
};
requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op);
}
}
void TParseVersions::floate5m2ScalarVectorCheck(const TSourceLoc& loc, const char* op, bool builtIn)
{
if (!builtIn) {
const char* const extensions[] = {
E_GL_EXT_float_e5m2,
};
requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op);
}
}
void TParseVersions::floate4m3ScalarVectorCheck(const TSourceLoc& loc, const char* op, bool builtIn)
{
if (!builtIn) {
const char* const extensions[] = {
E_GL_EXT_float_e4m3,
};
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,
const char* const extensions[] = {E_GL_EXT_shader_explicit_arithmetic_types,
E_GL_NV_gpu_shader5,
E_GL_EXT_shader_explicit_arithmetic_types_float32};
requireExtensions(loc, 2, extensions, op);
requireExtensions(loc, sizeof(extensions) / sizeof(extensions[0]), extensions, op);
}
}
@ -1265,11 +1358,15 @@ void TParseVersions::explicitFloat32Check(const TSourceLoc& loc, const char* op,
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,
const char* const extensions[] = {E_GL_EXT_shader_explicit_arithmetic_types,
E_GL_NV_gpu_shader5,
E_GL_EXT_shader_explicit_arithmetic_types_float64};
requireExtensions(loc, 2, extensions, op);
requireExtensions(loc, sizeof(extensions) / sizeof(extensions[0]), extensions, op);
requireProfile(loc, ECoreProfile | ECompatibilityProfile, op);
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 400, nullptr, op);
if(extensionTurnedOn(E_GL_ARB_gpu_shader_fp64) && extensionTurnedOn(E_GL_NV_gpu_shader5))
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 150, nullptr, op);
else
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 400, nullptr, op);
}
}
@ -1312,6 +1409,7 @@ void TParseVersions::int16ScalarVectorCheck(const TSourceLoc& loc, const char* o
E_GL_AMD_gpu_shader_int16,
E_GL_EXT_shader_16bit_storage,
E_GL_EXT_shader_explicit_arithmetic_types,
E_GL_NV_gpu_shader5,
E_GL_EXT_shader_explicit_arithmetic_types_int16};
requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op);
}
@ -1323,6 +1421,7 @@ void TParseVersions::int8ScalarVectorCheck(const TSourceLoc& loc, const char* op
const char* const extensions[] = {
E_GL_EXT_shader_8bit_storage,
E_GL_EXT_shader_explicit_arithmetic_types,
E_GL_NV_gpu_shader5,
E_GL_EXT_shader_explicit_arithmetic_types_int8};
requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op);
}
@ -1332,9 +1431,10 @@ void TParseVersions::int8ScalarVectorCheck(const TSourceLoc& loc, const char* op
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,
const char* const extensions[] = {E_GL_EXT_shader_explicit_arithmetic_types,
E_GL_NV_gpu_shader5,
E_GL_EXT_shader_explicit_arithmetic_types_int32};
requireExtensions(loc, 2, extensions, op);
requireExtensions(loc, sizeof(extensions) / sizeof(extensions[0]), extensions, op);
}
}
@ -1342,11 +1442,15 @@ void TParseVersions::explicitInt32Check(const TSourceLoc& loc, const char* op, b
void TParseVersions::int64Check(const TSourceLoc& loc, const char* op, bool builtIn)
{
if (! builtIn) {
const char* const extensions[3] = {E_GL_ARB_gpu_shader_int64,
const char* const extensions[] = {E_GL_ARB_gpu_shader_int64,
E_GL_EXT_shader_explicit_arithmetic_types,
E_GL_NV_gpu_shader5,
E_GL_EXT_shader_explicit_arithmetic_types_int64};
requireExtensions(loc, 3, extensions, op);
requireExtensions(loc, sizeof(extensions) / sizeof(extensions[0]), extensions, op);
requireProfile(loc, ECoreProfile | ECompatibilityProfile, op);
if (extensionTurnedOn(E_GL_NV_gpu_shader5))
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 150, nullptr, op);
else
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 400, nullptr, op);
}
}
@ -1375,6 +1479,46 @@ void TParseVersions::coopmatCheck(const TSourceLoc& loc, const char* op, bool bu
}
}
void TParseVersions::coopmatConverisonCheckQCOM(const TSourceLoc& loc, const char* op, bool builtIn)
{
if (!builtIn) {
const char* const extensions[] = {E_GL_KHR_cooperative_matrix};
requireExtensions(loc, sizeof(extensions) / sizeof(extensions[0]), extensions, op);
}
}
void TParseVersions::tensorLayoutViewCheck(const TSourceLoc& loc, const char* op, bool builtIn)
{
if (!builtIn) {
const char* const extensions[] = {E_GL_NV_cooperative_matrix2};
requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op);
}
}
void TParseVersions::coopvecCheck(const TSourceLoc& loc, const char* op, bool builtIn)
{
if (!builtIn) {
const char* const extensions[] = {E_GL_NV_cooperative_vector};
requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op);
}
}
void TParseVersions::intattachmentCheck(const TSourceLoc& loc, const char* op, bool builtIn)
{
if (!builtIn) {
const char* const extensions[] = {E_GL_QCOM_tile_shading};
requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op);
}
}
void TParseVersions::tensorCheckARM(const TSourceLoc& loc, const char* op, bool builtIn)
{
if (!builtIn) {
const char* const extensions[] = {E_GL_ARM_tensors};
requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op);
}
}
// Call for any operation removed because SPIR-V is in use.
void TParseVersions::spvRemoved(const TSourceLoc& loc, const char* op)
{

View file

@ -4,6 +4,7 @@
// Copyright (C) 2017, 2022-2024 Arm Limited.
// Copyright (C) 2015-2018 Google, Inc.
// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
// Modifications Copyright (C) 2024 Valve Corporation.
//
// All rights reserved.
//
@ -164,6 +165,7 @@ const char* const E_GL_ARB_vertex_attrib_64bit = "GL_ARB_vertex_attrib_
const char* const E_GL_ARB_draw_instanced = "GL_ARB_draw_instanced";
const char* const E_GL_ARB_fragment_coord_conventions = "GL_ARB_fragment_coord_conventions";
const char* const E_GL_ARB_bindless_texture = "GL_ARB_bindless_texture";
const char* const E_GL_ARB_conservative_depth = "GL_ARB_conservative_depth";
const char* const E_GL_KHR_shader_subgroup_basic = "GL_KHR_shader_subgroup_basic";
const char* const E_GL_KHR_shader_subgroup_vote = "GL_KHR_shader_subgroup_vote";
@ -222,6 +224,11 @@ const char* const E_GL_EXT_texture_array = "GL_EXT_texture_ar
const char* const E_GL_EXT_maximal_reconvergence = "GL_EXT_maximal_reconvergence";
const char* const E_GL_EXT_expect_assume = "GL_EXT_expect_assume";
const char* const E_GL_EXT_control_flow_attributes2 = "GL_EXT_control_flow_attributes2";
const char* const E_GL_EXT_spec_constant_composites = "GL_EXT_spec_constant_composites";
const char* const E_GL_EXT_texture_offset_non_const = "GL_EXT_texture_offset_non_const";
const char* const E_GL_EXT_nontemporal_keyword = "GL_EXT_nontemporal_keyword";
const char* const E_GL_EXT_uniform_buffer_unsized_array = "GL_EXT_uniform_buffer_unsized_array";
const char* const E_GL_EXT_conservative_depth = "GL_EXT_conservative_depth";
// Arrays of extensions for the above viewportEXTs duplications
@ -281,9 +288,15 @@ const char* const E_GL_NV_shader_invocation_reorder = "GL_NV_shader_
const char* const E_GL_EXT_ray_tracing_position_fetch = "GL_EXT_ray_tracing_position_fetch";
const char* const E_GL_NV_displacement_micromap = "GL_NV_displacement_micromap";
const char* const E_GL_NV_shader_atomic_fp16_vector = "GL_NV_shader_atomic_fp16_vector";
const char* const E_GL_NV_cooperative_matrix2 = "GL_NV_cooperative_matrix2";
const char* const E_GL_NV_cooperative_vector = "GL_NV_cooperative_vector";
const char* const E_GL_NV_cluster_acceleration_structure = "GL_NV_cluster_acceleration_structure";
const char* const E_GL_NV_linear_swept_spheres = "GL_NV_linear_swept_spheres";
const char* const E_GL_NV_gpu_shader5 = "GL_NV_gpu_shader5";
// ARM
const char* const E_GL_ARM_shader_core_builtins = "GL_ARM_shader_core_builtins";
const char* const E_GL_ARM_tensors = "GL_ARM_tensors";
// Arrays of extensions for the above viewportEXTs duplications
@ -293,6 +306,8 @@ const int Num_viewportEXTs = sizeof(viewportEXTs) / sizeof(viewportEXTs[0]);
const char* const E_GL_QCOM_image_processing = "GL_QCOM_image_processing";
const char* const E_GL_QCOM_image_processing2 = "GL_QCOM_image_processing2";
const char* const E_GL_QCOM_tile_shading = "GL_QCOM_tile_shading";
const char* const E_GL_QCOM_cooperative_matrix_conversion = "GL_QCOM_cooperative_matrix_conversion";
// AEP
const char* const E_GL_ANDROID_extension_pack_es31a = "GL_ANDROID_extension_pack_es31a";
@ -346,6 +361,16 @@ const char* const E_GL_EXT_shader_tile_image = "GL_EXT_shader_tile_image";
const char* const E_GL_EXT_texture_shadow_lod = "GL_EXT_texture_shadow_lod";
const char* const E_GL_EXT_integer_dot_product = "GL_EXT_integer_dot_product";
const char* const E_GL_EXT_bfloat16 = "GL_EXT_bfloat16";
const char* const E_GL_EXT_float_e5m2 = "GL_EXT_float_e5m2";
const char* const E_GL_EXT_float_e4m3 = "GL_EXT_float_e4m3";
const char* const E_GL_EXT_shader_64bit_indexing = "GL_EXT_shader_64bit_indexing";
const char* const E_GL_EXT_shader_invocation_reorder = "GL_EXT_shader_invocation_reorder";
// Arrays of extensions for the above AEP duplications
const char* const AEP_geometry_shader[] = { E_GL_EXT_geometry_shader, E_GL_OES_geometry_shader };
@ -357,6 +382,9 @@ const int Num_AEP_geometry_point_size = sizeof(AEP_geometry_point_size)/sizeof(A
const char* const AEP_gpu_shader5[] = { E_GL_EXT_gpu_shader5, E_GL_OES_gpu_shader5 };
const int Num_AEP_gpu_shader5 = sizeof(AEP_gpu_shader5)/sizeof(AEP_gpu_shader5[0]);
const char* const AEP_core_gpu_shader5[] = { E_GL_ARB_gpu_shader5, E_GL_NV_gpu_shader5};
const int Num_AEP_core_gpu_shader5 = sizeof(AEP_core_gpu_shader5)/sizeof(AEP_core_gpu_shader5[0]);
const char* const AEP_primitive_bounding_box[] = { E_GL_EXT_primitive_bounding_box, E_GL_OES_primitive_bounding_box };
const int Num_AEP_primitive_bounding_box = sizeof(AEP_primitive_bounding_box)/sizeof(AEP_primitive_bounding_box[0]);

View file

@ -146,7 +146,7 @@ extern int yylex(YYSTYPE*, TParseContext&);
%token <lex> UTEXTURE2D UTEXTURE3D UTEXTURECUBE UTEXTURE2DARRAY
%token <lex> ATTRIBUTE VARYING
%token <lex> FLOAT16_T FLOAT32_T DOUBLE FLOAT64_T
%token <lex> FLOATE5M2_T FLOATE4M3_T BFLOAT16_T FLOAT16_T FLOAT32_T DOUBLE FLOAT64_T
%token <lex> INT64_T UINT64_T INT32_T UINT32_T INT16_T UINT16_T INT8_T UINT8_T
%token <lex> I64VEC2 I64VEC3 I64VEC4
%token <lex> U64VEC2 U64VEC3 U64VEC4
@ -157,6 +157,9 @@ extern int yylex(YYSTYPE*, TParseContext&);
%token <lex> I8VEC2 I8VEC3 I8VEC4
%token <lex> U8VEC2 U8VEC3 U8VEC4
%token <lex> DVEC2 DVEC3 DVEC4 DMAT2 DMAT3 DMAT4
%token <lex> BF16VEC2 BF16VEC3 BF16VEC4
%token <lex> FE5M2VEC2 FE5M2VEC3 FE5M2VEC4
%token <lex> FE4M3VEC2 FE4M3VEC3 FE4M3VEC4
%token <lex> F16VEC2 F16VEC3 F16VEC4 F16MAT2 F16MAT3 F16MAT4
%token <lex> F32VEC2 F32VEC3 F32VEC4 F32MAT2 F32MAT3 F32MAT4
%token <lex> F64VEC2 F64VEC3 F64VEC4 F64MAT2 F64MAT3 F64MAT4
@ -178,7 +181,10 @@ extern int yylex(YYSTYPE*, TParseContext&);
%token <lex> RAYQUERYEXT
%token <lex> FCOOPMATNV ICOOPMATNV UCOOPMATNV
%token <lex> COOPMAT
%token <lex> HITOBJECTNV HITOBJECTATTRNV
%token <lex> COOPVECNV
%token <lex> HITOBJECTNV HITOBJECTATTRNV HITOBJECTEXT HITOBJECTATTREXT
%token <lex> TENSORLAYOUTNV TENSORVIEWNV
%token <lex> TENSORARM
// combined image/sampler
%token <lex> SAMPLERCUBEARRAY SAMPLERCUBEARRAYSHADOW
@ -275,11 +281,11 @@ extern int yylex(YYSTYPE*, TParseContext&);
%token <lex> DOUBLECONSTANT INT16CONSTANT UINT16CONSTANT FLOAT16CONSTANT INT32CONSTANT UINT32CONSTANT
%token <lex> INT64CONSTANT UINT64CONSTANT
%token <lex> SUBROUTINE DEMOTE
%token <lex> SUBROUTINE DEMOTE FUNCTION
%token <lex> PAYLOADNV PAYLOADINNV HITATTRNV CALLDATANV CALLDATAINNV
%token <lex> PAYLOADEXT PAYLOADINEXT HITATTREXT CALLDATAEXT CALLDATAINEXT
%token <lex> PATCH SAMPLE NONUNIFORM
%token <lex> COHERENT VOLATILE RESTRICT READONLY WRITEONLY DEVICECOHERENT QUEUEFAMILYCOHERENT WORKGROUPCOHERENT
%token <lex> COHERENT VOLATILE RESTRICT READONLY WRITEONLY NONTEMPORAL DEVICECOHERENT QUEUEFAMILYCOHERENT WORKGROUPCOHERENT
%token <lex> SUBGROUPCOHERENT NONPRIVATE SHADERCALLCOHERENT
%token <lex> NOPERSPECTIVE EXPLICITINTERPAMD PERVERTEXEXT PERVERTEXNV PERPRIMITIVENV PERVIEWNV PERTASKNV PERPRIMITIVEEXT TASKPAYLOADWORKGROUPEXT
%token <lex> PRECISE
@ -292,7 +298,8 @@ extern int yylex(YYSTYPE*, TParseContext&);
%type <interm.intermTypedNode> conditional_expression constant_expression
%type <interm.intermTypedNode> logical_or_expression logical_xor_expression logical_and_expression
%type <interm.intermTypedNode> shift_expression and_expression exclusive_or_expression inclusive_or_expression
%type <interm.intermTypedNode> function_call initializer condition conditionopt
%type <interm.intermTypedNode> function_call initializer
%type <interm.intermNode> condition conditionopt
%type <interm.intermNode> translation_unit function_definition
%type <interm.intermNode> statement simple_statement
@ -445,7 +452,7 @@ postfix_expression
integer_expression
: expression {
parseContext.integerCheck($1, "[]");
parseContext.arrayIndexCheck($1, "[]");
$$ = $1;
}
;
@ -549,7 +556,7 @@ function_identifier
TIntermMethod* method = $1->getAsMethodNode();
if (method) {
$$.function = new TFunction(&method->getMethodName(), TType(EbtInt), EOpArrayLength);
$$.function = new TFunction(&method->getMethodName(), method->getType(), EOpArrayLength);
$$.intermNode = method->getObject();
} else {
TIntermSymbol* symbol = $1->getAsSymbolNode();
@ -906,31 +913,22 @@ declaration
$$ = 0;
}
| block_structure SEMICOLON {
parseContext.declareBlock($1.loc, *$1.typeList);
$$ = 0;
$$ = parseContext.declareBlock($1.loc, *$1.typeList);
}
| block_structure IDENTIFIER SEMICOLON {
parseContext.declareBlock($1.loc, *$1.typeList, $2.string);
$$ = 0;
$$ = parseContext.declareBlock($1.loc, *$1.typeList, $2.string);
}
| block_structure IDENTIFIER array_specifier SEMICOLON {
parseContext.declareBlock($1.loc, *$1.typeList, $2.string, $3.arraySizes);
$$ = 0;
$$ = parseContext.declareBlock($1.loc, *$1.typeList, $2.string, $3.arraySizes);
}
| type_qualifier SEMICOLON {
parseContext.globalQualifierFixCheck($1.loc, $1.qualifier);
parseContext.updateStandaloneQualifierDefaults($1.loc, $1);
$$ = 0;
}
| type_qualifier IDENTIFIER SEMICOLON {
| type_qualifier identifier_list SEMICOLON {
parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers);
parseContext.addQualifierToExisting($1.loc, $1.qualifier, *$2.string);
$$ = 0;
}
| type_qualifier IDENTIFIER identifier_list SEMICOLON {
parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers);
$3->push_back($2.string);
parseContext.addQualifierToExisting($1.loc, $1.qualifier, *$3);
parseContext.addQualifierToExisting($1.loc, $1.qualifier, *$2);
$$ = 0;
}
;
@ -947,9 +945,9 @@ block_structure
}
identifier_list
: COMMA IDENTIFIER {
: IDENTIFIER {
$$ = new TIdentifierList;
$$->push_back($2.string);
$$->push_back($1.string);
}
| identifier_list COMMA IDENTIFIER {
$$ = $1;
@ -1034,6 +1032,10 @@ function_header_with_parameters
parseContext.vkRelaxedRemapFunctionParameter($1, $3.param);
}
}
| function_header_with_parameters COMMA DOT DOT DOT {
$$ = $1;
parseContext.makeVariadic($1, $3.loc);
}
;
function_header
@ -1094,6 +1096,11 @@ parameter_declarator
$$.loc = $2.loc;
$$.param = param;
}
| type_specifier IDENTIFIER EQUAL initializer {
TParameter param = parseContext.getParamWithDefault($1, $2.string, $4, $3.loc);
$$.loc = $2.loc;
$$.param = param;
}
;
parameter_declaration
@ -1104,7 +1111,7 @@ parameter_declaration
$$ = $2;
if ($1.qualifier.precision != EpqNone)
$$.param.type->getQualifier().precision = $1.qualifier.precision;
parseContext.precisionQualifierCheck($$.loc, $$.param.type->getBasicType(), $$.param.type->getQualifier(), $$.param.type->isCoopMat());
parseContext.precisionQualifierCheck($$.loc, $$.param.type->getBasicType(), $$.param.type->getQualifier(), $$.param.type->hasTypeParameter());
parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers);
parseContext.parameterTypeCheck($2.loc, $1.qualifier.storage, *$$.param.type);
@ -1116,7 +1123,7 @@ parameter_declaration
parseContext.parameterTypeCheck($1.loc, EvqIn, *$1.param.type);
parseContext.paramCheckFixStorage($1.loc, EvqTemporary, *$$.param.type);
parseContext.precisionQualifierCheck($$.loc, $$.param.type->getBasicType(), $$.param.type->getQualifier(), $$.param.type->isCoopMat());
parseContext.precisionQualifierCheck($$.loc, $$.param.type->getBasicType(), $$.param.type->getQualifier(), $$.param.type->hasTypeParameter());
}
//
// Without name
@ -1125,7 +1132,7 @@ parameter_declaration
$$ = $2;
if ($1.qualifier.precision != EpqNone)
$$.param.type->getQualifier().precision = $1.qualifier.precision;
parseContext.precisionQualifierCheck($1.loc, $$.param.type->getBasicType(), $$.param.type->getQualifier(), $$.param.type->isCoopMat());
parseContext.precisionQualifierCheck($1.loc, $$.param.type->getBasicType(), $$.param.type->getQualifier(), $$.param.type->hasTypeParameter());
parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers);
parseContext.parameterTypeCheck($2.loc, $1.qualifier.storage, *$$.param.type);
@ -1136,7 +1143,7 @@ parameter_declaration
parseContext.parameterTypeCheck($1.loc, EvqIn, *$1.param.type);
parseContext.paramCheckFixStorage($1.loc, EvqTemporary, *$$.param.type);
parseContext.precisionQualifierCheck($$.loc, $$.param.type->getBasicType(), $$.param.type->getQualifier(), $$.param.type->isCoopMat());
parseContext.precisionQualifierCheck($$.loc, $$.param.type->getBasicType(), $$.param.type->getQualifier(), $$.param.type->hasTypeParameter());
}
;
@ -1155,21 +1162,23 @@ init_declarator_list
}
| init_declarator_list COMMA IDENTIFIER {
$$ = $1;
parseContext.declareVariable($3.loc, *$3.string, $1.type);
TIntermNode* declNode = parseContext.declareVariable($3.loc, *$3.string, $1.type);
$$.intermNode = parseContext.intermediate.growAggregate($1.intermNode, declNode, $3.loc);
}
| init_declarator_list COMMA IDENTIFIER array_specifier {
$$ = $1;
parseContext.declareVariable($3.loc, *$3.string, $1.type, $4.arraySizes);
TIntermNode* declNode = parseContext.declareVariable($3.loc, *$3.string, $1.type, $4.arraySizes);
$$.intermNode = parseContext.intermediate.growAggregate($1.intermNode, declNode, $3.loc);
}
| init_declarator_list COMMA IDENTIFIER array_specifier EQUAL initializer {
$$.type = $1.type;
TIntermNode* initNode = parseContext.declareVariable($3.loc, *$3.string, $1.type, $4.arraySizes, $6);
$$.intermNode = parseContext.intermediate.growAggregate($1.intermNode, initNode, $5.loc);
TIntermNode* declNode = parseContext.declareVariable($3.loc, *$3.string, $1.type, $4.arraySizes, $6);
$$.intermNode = parseContext.intermediate.growAggregate($1.intermNode, declNode, $5.loc);
}
| init_declarator_list COMMA IDENTIFIER EQUAL initializer {
$$.type = $1.type;
TIntermNode* initNode = parseContext.declareVariable($3.loc, *$3.string, $1.type, 0, $5);
$$.intermNode = parseContext.intermediate.growAggregate($1.intermNode, initNode, $4.loc);
TIntermNode* declNode = parseContext.declareVariable($3.loc, *$3.string, $1.type, 0, $5);
$$.intermNode = parseContext.intermediate.growAggregate($1.intermNode, declNode, $4.loc);
}
;
@ -1181,23 +1190,24 @@ single_declaration
}
| fully_specified_type IDENTIFIER {
$$.type = $1;
$$.intermNode = 0;
parseContext.declareVariable($2.loc, *$2.string, $1);
TIntermNode* declNode = parseContext.declareVariable($2.loc, *$2.string, $1);
$$.intermNode = parseContext.intermediate.growAggregate(nullptr, declNode, $2.loc);
}
| fully_specified_type IDENTIFIER array_specifier {
$$.type = $1;
$$.intermNode = 0;
parseContext.declareVariable($2.loc, *$2.string, $1, $3.arraySizes);
TIntermNode* declNode = parseContext.declareVariable($2.loc, *$2.string, $1, $3.arraySizes);
$$.intermNode = parseContext.intermediate.growAggregate(nullptr, declNode, $2.loc);
}
| fully_specified_type IDENTIFIER array_specifier EQUAL initializer {
$$.type = $1;
TIntermNode* initNode = parseContext.declareVariable($2.loc, *$2.string, $1, $3.arraySizes, $5);
$$.intermNode = parseContext.intermediate.growAggregate(0, initNode, $4.loc);
TIntermNode* declNode = parseContext.declareVariable($2.loc, *$2.string, $1, $3.arraySizes, $5);
$$.intermNode = parseContext.intermediate.growAggregate(nullptr, declNode, $2.loc);
}
| fully_specified_type IDENTIFIER EQUAL initializer {
$$.type = $1;
TIntermNode* initNode = parseContext.declareVariable($2.loc, *$2.string, $1, 0, $4);
$$.intermNode = parseContext.intermediate.growAggregate(0, initNode, $3.loc);
TIntermNode* declNode = parseContext.declareVariable($2.loc, *$2.string, $1, 0, $4);
$$.intermNode = parseContext.intermediate.growAggregate(nullptr, declNode, $2.loc);
}
// Grammar Note: No 'enum', or 'typedef'.
@ -1211,7 +1221,7 @@ fully_specified_type
parseContext.profileRequires($1.loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type");
parseContext.profileRequires($1.loc, EEsProfile, 300, 0, "arrayed type");
}
parseContext.precisionQualifierCheck($$.loc, $$.basicType, $$.qualifier, $$.isCoopmat());
parseContext.precisionQualifierCheck($$.loc, $$.basicType, $$.qualifier, $$.hasTypeParameter());
}
| type_qualifier type_specifier {
parseContext.globalQualifierFixCheck($1.loc, $1.qualifier, false, &$2);
@ -1228,7 +1238,7 @@ fully_specified_type
parseContext.checkNoShaderLayouts($2.loc, $1.shaderQualifiers);
$2.shaderQualifiers.merge($1.shaderQualifiers);
parseContext.mergeQualifiers($2.loc, $2.qualifier, $1.qualifier, true);
parseContext.precisionQualifierCheck($2.loc, $2.basicType, $2.qualifier, $2.isCoopmat());
parseContext.precisionQualifierCheck($2.loc, $2.basicType, $2.qualifier, $2.hasTypeParameter());
$$ = $2;
@ -1528,14 +1538,22 @@ storage_qualifier
$$.init($1.loc);
$$.qualifier.storage = EvqHitAttr;
}
| HITOBJECTATTRNV {
| HITOBJECTATTRNV {
parseContext.globalCheck($1.loc, "hitAttributeNV");
parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangRayGenMask | EShLangClosestHitMask
| EShLangMissMask), "hitObjectAttributeNV");
parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_NV_shader_invocation_reorder, "hitObjectAttributeNV");
$$.init($1.loc);
$$.qualifier.storage = EvqHitObjectAttrNV;
}
}
| HITOBJECTATTREXT {
parseContext.globalCheck($1.loc, "hitAttributeEXT");
parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangRayGenMask | EShLangClosestHitMask
| EShLangMissMask), "hitObjectAttributeEXT");
parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_EXT_shader_invocation_reorder, "hitObjectAttributeEXT");
$$.init($1.loc);
$$.qualifier.storage = EvqHitObjectAttrEXT;
}
| HITATTREXT {
parseContext.globalCheck($1.loc, "hitAttributeEXT");
parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangIntersectMask | EShLangClosestHitMask
@ -1656,6 +1674,10 @@ storage_qualifier
$$.init($1.loc);
$$.qualifier.writeonly = true;
}
| NONTEMPORAL {
$$.init($1.loc);
$$.qualifier.nontemporal = true;
}
| SUBROUTINE {
parseContext.spvRemoved($1.loc, "subroutine");
parseContext.globalCheck($1.loc, "subroutine");
@ -1700,7 +1722,7 @@ type_specifier
$$ = $1;
$$.qualifier.precision = parseContext.getDefaultPrecision($$);
$$.typeParameters = $2;
parseContext.coopMatTypeParametersCheck($1.loc, $$);
parseContext.typeParametersCheck($1.loc, $$);
}
| type_specifier_nonarray type_parameter_specifier_opt array_specifier {
@ -1709,7 +1731,7 @@ type_specifier
$$.qualifier.precision = parseContext.getDefaultPrecision($$);
$$.typeParameters = $2;
$$.arraySizes = $3.arraySizes;
parseContext.coopMatTypeParametersCheck($1.loc, $$);
parseContext.typeParametersCheck($1.loc, $$);
}
;
@ -1931,6 +1953,21 @@ type_specifier_nonarray
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtDouble;
}
| BFLOAT16_T {
parseContext.bfloat16ScalarVectorCheck($1.loc, "bfloat16_t", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtBFloat16;
}
| FLOATE5M2_T {
parseContext.floate5m2ScalarVectorCheck($1.loc, "floate5m2_t", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloatE5M2;
}
| FLOATE4M3_T {
parseContext.floate4m3ScalarVectorCheck($1.loc, "floate4m3_t", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloatE4M3;
}
| FLOAT16_T {
parseContext.float16ScalarVectorCheck($1.loc, "float16_t", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
@ -2010,6 +2047,60 @@ type_specifier_nonarray
$$.basicType = EbtDouble;
$$.setVector(4);
}
| BF16VEC2 {
parseContext.bfloat16ScalarVectorCheck($1.loc, "half float vector", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtBFloat16;
$$.setVector(2);
}
| BF16VEC3 {
parseContext.bfloat16ScalarVectorCheck($1.loc, "half float vector", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtBFloat16;
$$.setVector(3);
}
| BF16VEC4 {
parseContext.bfloat16ScalarVectorCheck($1.loc, "half float vector", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtBFloat16;
$$.setVector(4);
}
| FE5M2VEC2 {
parseContext.floate5m2ScalarVectorCheck($1.loc, "fe5m2 vector", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloatE5M2;
$$.setVector(2);
}
| FE5M2VEC3 {
parseContext.floate5m2ScalarVectorCheck($1.loc, "fe5m2 vector", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloatE5M2;
$$.setVector(3);
}
| FE5M2VEC4 {
parseContext.floate5m2ScalarVectorCheck($1.loc, "fe5m2 vector", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloatE5M2;
$$.setVector(4);
}
| FE4M3VEC2 {
parseContext.floate4m3ScalarVectorCheck($1.loc, "fe4m3 vector", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloatE4M3;
$$.setVector(2);
}
| FE4M3VEC3 {
parseContext.floate4m3ScalarVectorCheck($1.loc, "fe4m3 vector", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloatE4M3;
$$.setVector(3);
}
| FE4M3VEC4 {
parseContext.floate4m3ScalarVectorCheck($1.loc, "fe4m3 vector", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloatE4M3;
$$.setVector(4);
}
| F16VEC2 {
parseContext.float16ScalarVectorCheck($1.loc, "half float vector", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
@ -3535,14 +3626,44 @@ type_specifier_nonarray
$$.coopmatNV = false;
$$.coopmatKHR = true;
}
| TENSORLAYOUTNV {
parseContext.tensorLayoutViewCheck($1.loc, "tensorLayoutNV", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtTensorLayoutNV;
}
| TENSORVIEWNV {
parseContext.tensorLayoutViewCheck($1.loc, "tensorViewNV", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtTensorViewNV;
}
| FUNCTION {
$$.init($1.loc);
$$.basicType = EbtFunction;
}
| COOPVECNV {
parseContext.coopvecCheck($1.loc, "coopvecNV", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtCoopvecNV;
$$.coopvecNV = true;
}
| TENSORARM {
parseContext.tensorCheckARM($1.loc, "tensorARM", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.tensorRankARM = 1; // placeholder value
$$.basicType = EbtTensorARM;
}
| spirv_type_specifier {
parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V type specifier");
$$ = $1;
}
| HITOBJECTNV {
| HITOBJECTNV {
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtHitObjectNV;
}
}
| HITOBJECTEXT {
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtHitObjectEXT;
}
| struct_specifier {
$$ = $1;
$$.qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
@ -3636,7 +3757,7 @@ struct_declaration
$$ = $2;
parseContext.voidErrorCheck($1.loc, (*$2)[0].type->getFieldName(), $1.basicType);
parseContext.precisionQualifierCheck($1.loc, $1.basicType, $1.qualifier, $1.isCoopmat());
parseContext.precisionQualifierCheck($1.loc, $1.basicType, $1.qualifier, $1.hasTypeParameter());
for (unsigned int i = 0; i < $$->size(); ++i) {
TType type($1);
@ -3660,7 +3781,7 @@ struct_declaration
parseContext.memberQualifierCheck($1);
parseContext.voidErrorCheck($2.loc, (*$3)[0].type->getFieldName(), $2.basicType);
parseContext.mergeQualifiers($2.loc, $2.qualifier, $1.qualifier, true);
parseContext.precisionQualifierCheck($2.loc, $2.basicType, $2.qualifier, $2.isCoopmat());
parseContext.precisionQualifierCheck($2.loc, $2.basicType, $2.qualifier, $2.hasTypeParameter());
for (unsigned int i = 0; i < $$->size(); ++i) {
TType type($2);
@ -3773,8 +3894,10 @@ compound_statement
--parseContext.statementNestingLevel;
}
RIGHT_BRACE {
if ($3 && $3->getAsAggregate())
if ($3 && $3->getAsAggregate()) {
$3->getAsAggregate()->setOperator(parseContext.intermediate.getDebugInfo() ? EOpScope : EOpSequence);
$3->getAsAggregate()->setEndLoc($5.loc);
}
$$ = $3;
}
;
@ -3810,8 +3933,10 @@ compound_statement_no_new_scope
$$ = 0;
}
| LEFT_BRACE statement_list RIGHT_BRACE {
if ($2 && $2->getAsAggregate())
if ($2 && $2->getAsAggregate()) {
$2->getAsAggregate()->setOperator(EOpSequence);
$2->getAsAggregate()->setEndLoc($3.loc);
}
$$ = $2;
}
;
@ -3878,11 +4003,7 @@ condition
parseContext.boolCheck($2.loc, $1);
TType type($1);
TIntermNode* initNode = parseContext.declareVariable($2.loc, *$2.string, $1, 0, $4);
if (initNode)
$$ = initNode->getAsTyped();
else
$$ = 0;
$$ = parseContext.declareVariable($2.loc, *$2.string, $1, 0, $4);
}
;
@ -3972,6 +4093,10 @@ iteration_statement_nonattributed
condition RIGHT_PAREN statement_no_new_scope {
parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
$$ = parseContext.intermediate.addLoop($6, $4, 0, true, $1.loc);
if (parseContext.intermediate.getDebugInfo()) {
$$ = parseContext.intermediate.makeAggregate($$, $1.loc);
$$->getAsAggregate()->setOperator(EOpScope);
}
--parseContext.loopNestingLevel;
--parseContext.statementNestingLevel;
--parseContext.controlFlowNestingLevel;
@ -3989,6 +4114,10 @@ iteration_statement_nonattributed
parseContext.boolCheck($8.loc, $6);
$$ = parseContext.intermediate.addLoop($3, $6, 0, false, $4.loc);
if (parseContext.intermediate.getDebugInfo()) {
$$ = parseContext.intermediate.makeAggregate($$, $4.loc);
$$->getAsAggregate()->setOperator(EOpScope);
}
parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
--parseContext.loopNestingLevel;
--parseContext.statementNestingLevel;
@ -4007,7 +4136,7 @@ iteration_statement_nonattributed
if (! parseContext.limits.nonInductiveForLoops)
parseContext.inductiveLoopCheck($1.loc, $4, forLoop);
$$ = parseContext.intermediate.growAggregate($$, forLoop, $1.loc);
$$->getAsAggregate()->setOperator(EOpSequence);
$$->getAsAggregate()->setOperator(parseContext.intermediate.getDebugInfo() ? EOpScope : EOpSequence);
--parseContext.loopNestingLevel;
--parseContext.statementNestingLevel;
--parseContext.controlFlowNestingLevel;

File diff suppressed because it is too large Load diff

View file

@ -114,408 +114,428 @@ extern int yydebug;
UTEXTURE2DARRAY = 315, /* UTEXTURE2DARRAY */
ATTRIBUTE = 316, /* ATTRIBUTE */
VARYING = 317, /* VARYING */
FLOAT16_T = 318, /* FLOAT16_T */
FLOAT32_T = 319, /* FLOAT32_T */
DOUBLE = 320, /* DOUBLE */
FLOAT64_T = 321, /* FLOAT64_T */
INT64_T = 322, /* INT64_T */
UINT64_T = 323, /* UINT64_T */
INT32_T = 324, /* INT32_T */
UINT32_T = 325, /* UINT32_T */
INT16_T = 326, /* INT16_T */
UINT16_T = 327, /* UINT16_T */
INT8_T = 328, /* INT8_T */
UINT8_T = 329, /* UINT8_T */
I64VEC2 = 330, /* I64VEC2 */
I64VEC3 = 331, /* I64VEC3 */
I64VEC4 = 332, /* I64VEC4 */
U64VEC2 = 333, /* U64VEC2 */
U64VEC3 = 334, /* U64VEC3 */
U64VEC4 = 335, /* U64VEC4 */
I32VEC2 = 336, /* I32VEC2 */
I32VEC3 = 337, /* I32VEC3 */
I32VEC4 = 338, /* I32VEC4 */
U32VEC2 = 339, /* U32VEC2 */
U32VEC3 = 340, /* U32VEC3 */
U32VEC4 = 341, /* U32VEC4 */
I16VEC2 = 342, /* I16VEC2 */
I16VEC3 = 343, /* I16VEC3 */
I16VEC4 = 344, /* I16VEC4 */
U16VEC2 = 345, /* U16VEC2 */
U16VEC3 = 346, /* U16VEC3 */
U16VEC4 = 347, /* U16VEC4 */
I8VEC2 = 348, /* I8VEC2 */
I8VEC3 = 349, /* I8VEC3 */
I8VEC4 = 350, /* I8VEC4 */
U8VEC2 = 351, /* U8VEC2 */
U8VEC3 = 352, /* U8VEC3 */
U8VEC4 = 353, /* U8VEC4 */
DVEC2 = 354, /* DVEC2 */
DVEC3 = 355, /* DVEC3 */
DVEC4 = 356, /* DVEC4 */
DMAT2 = 357, /* DMAT2 */
DMAT3 = 358, /* DMAT3 */
DMAT4 = 359, /* DMAT4 */
F16VEC2 = 360, /* F16VEC2 */
F16VEC3 = 361, /* F16VEC3 */
F16VEC4 = 362, /* F16VEC4 */
F16MAT2 = 363, /* F16MAT2 */
F16MAT3 = 364, /* F16MAT3 */
F16MAT4 = 365, /* F16MAT4 */
F32VEC2 = 366, /* F32VEC2 */
F32VEC3 = 367, /* F32VEC3 */
F32VEC4 = 368, /* F32VEC4 */
F32MAT2 = 369, /* F32MAT2 */
F32MAT3 = 370, /* F32MAT3 */
F32MAT4 = 371, /* F32MAT4 */
F64VEC2 = 372, /* F64VEC2 */
F64VEC3 = 373, /* F64VEC3 */
F64VEC4 = 374, /* F64VEC4 */
F64MAT2 = 375, /* F64MAT2 */
F64MAT3 = 376, /* F64MAT3 */
F64MAT4 = 377, /* F64MAT4 */
DMAT2X2 = 378, /* DMAT2X2 */
DMAT2X3 = 379, /* DMAT2X3 */
DMAT2X4 = 380, /* DMAT2X4 */
DMAT3X2 = 381, /* DMAT3X2 */
DMAT3X3 = 382, /* DMAT3X3 */
DMAT3X4 = 383, /* DMAT3X4 */
DMAT4X2 = 384, /* DMAT4X2 */
DMAT4X3 = 385, /* DMAT4X3 */
DMAT4X4 = 386, /* DMAT4X4 */
F16MAT2X2 = 387, /* F16MAT2X2 */
F16MAT2X3 = 388, /* F16MAT2X3 */
F16MAT2X4 = 389, /* F16MAT2X4 */
F16MAT3X2 = 390, /* F16MAT3X2 */
F16MAT3X3 = 391, /* F16MAT3X3 */
F16MAT3X4 = 392, /* F16MAT3X4 */
F16MAT4X2 = 393, /* F16MAT4X2 */
F16MAT4X3 = 394, /* F16MAT4X3 */
F16MAT4X4 = 395, /* F16MAT4X4 */
F32MAT2X2 = 396, /* F32MAT2X2 */
F32MAT2X3 = 397, /* F32MAT2X3 */
F32MAT2X4 = 398, /* F32MAT2X4 */
F32MAT3X2 = 399, /* F32MAT3X2 */
F32MAT3X3 = 400, /* F32MAT3X3 */
F32MAT3X4 = 401, /* F32MAT3X4 */
F32MAT4X2 = 402, /* F32MAT4X2 */
F32MAT4X3 = 403, /* F32MAT4X3 */
F32MAT4X4 = 404, /* F32MAT4X4 */
F64MAT2X2 = 405, /* F64MAT2X2 */
F64MAT2X3 = 406, /* F64MAT2X3 */
F64MAT2X4 = 407, /* F64MAT2X4 */
F64MAT3X2 = 408, /* F64MAT3X2 */
F64MAT3X3 = 409, /* F64MAT3X3 */
F64MAT3X4 = 410, /* F64MAT3X4 */
F64MAT4X2 = 411, /* F64MAT4X2 */
F64MAT4X3 = 412, /* F64MAT4X3 */
F64MAT4X4 = 413, /* F64MAT4X4 */
ATOMIC_UINT = 414, /* ATOMIC_UINT */
ACCSTRUCTNV = 415, /* ACCSTRUCTNV */
ACCSTRUCTEXT = 416, /* ACCSTRUCTEXT */
RAYQUERYEXT = 417, /* RAYQUERYEXT */
FCOOPMATNV = 418, /* FCOOPMATNV */
ICOOPMATNV = 419, /* ICOOPMATNV */
UCOOPMATNV = 420, /* UCOOPMATNV */
COOPMAT = 421, /* COOPMAT */
HITOBJECTNV = 422, /* HITOBJECTNV */
HITOBJECTATTRNV = 423, /* HITOBJECTATTRNV */
SAMPLERCUBEARRAY = 424, /* SAMPLERCUBEARRAY */
SAMPLERCUBEARRAYSHADOW = 425, /* SAMPLERCUBEARRAYSHADOW */
ISAMPLERCUBEARRAY = 426, /* ISAMPLERCUBEARRAY */
USAMPLERCUBEARRAY = 427, /* USAMPLERCUBEARRAY */
SAMPLER1D = 428, /* SAMPLER1D */
SAMPLER1DARRAY = 429, /* SAMPLER1DARRAY */
SAMPLER1DARRAYSHADOW = 430, /* SAMPLER1DARRAYSHADOW */
ISAMPLER1D = 431, /* ISAMPLER1D */
SAMPLER1DSHADOW = 432, /* SAMPLER1DSHADOW */
SAMPLER2DRECT = 433, /* SAMPLER2DRECT */
SAMPLER2DRECTSHADOW = 434, /* SAMPLER2DRECTSHADOW */
ISAMPLER2DRECT = 435, /* ISAMPLER2DRECT */
USAMPLER2DRECT = 436, /* USAMPLER2DRECT */
SAMPLERBUFFER = 437, /* SAMPLERBUFFER */
ISAMPLERBUFFER = 438, /* ISAMPLERBUFFER */
USAMPLERBUFFER = 439, /* USAMPLERBUFFER */
SAMPLER2DMS = 440, /* SAMPLER2DMS */
ISAMPLER2DMS = 441, /* ISAMPLER2DMS */
USAMPLER2DMS = 442, /* USAMPLER2DMS */
SAMPLER2DMSARRAY = 443, /* SAMPLER2DMSARRAY */
ISAMPLER2DMSARRAY = 444, /* ISAMPLER2DMSARRAY */
USAMPLER2DMSARRAY = 445, /* USAMPLER2DMSARRAY */
SAMPLEREXTERNALOES = 446, /* SAMPLEREXTERNALOES */
SAMPLEREXTERNAL2DY2YEXT = 447, /* SAMPLEREXTERNAL2DY2YEXT */
ISAMPLER1DARRAY = 448, /* ISAMPLER1DARRAY */
USAMPLER1D = 449, /* USAMPLER1D */
USAMPLER1DARRAY = 450, /* USAMPLER1DARRAY */
F16SAMPLER1D = 451, /* F16SAMPLER1D */
F16SAMPLER2D = 452, /* F16SAMPLER2D */
F16SAMPLER3D = 453, /* F16SAMPLER3D */
F16SAMPLER2DRECT = 454, /* F16SAMPLER2DRECT */
F16SAMPLERCUBE = 455, /* F16SAMPLERCUBE */
F16SAMPLER1DARRAY = 456, /* F16SAMPLER1DARRAY */
F16SAMPLER2DARRAY = 457, /* F16SAMPLER2DARRAY */
F16SAMPLERCUBEARRAY = 458, /* F16SAMPLERCUBEARRAY */
F16SAMPLERBUFFER = 459, /* F16SAMPLERBUFFER */
F16SAMPLER2DMS = 460, /* F16SAMPLER2DMS */
F16SAMPLER2DMSARRAY = 461, /* F16SAMPLER2DMSARRAY */
F16SAMPLER1DSHADOW = 462, /* F16SAMPLER1DSHADOW */
F16SAMPLER2DSHADOW = 463, /* F16SAMPLER2DSHADOW */
F16SAMPLER1DARRAYSHADOW = 464, /* F16SAMPLER1DARRAYSHADOW */
F16SAMPLER2DARRAYSHADOW = 465, /* F16SAMPLER2DARRAYSHADOW */
F16SAMPLER2DRECTSHADOW = 466, /* F16SAMPLER2DRECTSHADOW */
F16SAMPLERCUBESHADOW = 467, /* F16SAMPLERCUBESHADOW */
F16SAMPLERCUBEARRAYSHADOW = 468, /* F16SAMPLERCUBEARRAYSHADOW */
IMAGE1D = 469, /* IMAGE1D */
IIMAGE1D = 470, /* IIMAGE1D */
UIMAGE1D = 471, /* UIMAGE1D */
IMAGE2D = 472, /* IMAGE2D */
IIMAGE2D = 473, /* IIMAGE2D */
UIMAGE2D = 474, /* UIMAGE2D */
IMAGE3D = 475, /* IMAGE3D */
IIMAGE3D = 476, /* IIMAGE3D */
UIMAGE3D = 477, /* UIMAGE3D */
IMAGE2DRECT = 478, /* IMAGE2DRECT */
IIMAGE2DRECT = 479, /* IIMAGE2DRECT */
UIMAGE2DRECT = 480, /* UIMAGE2DRECT */
IMAGECUBE = 481, /* IMAGECUBE */
IIMAGECUBE = 482, /* IIMAGECUBE */
UIMAGECUBE = 483, /* UIMAGECUBE */
IMAGEBUFFER = 484, /* IMAGEBUFFER */
IIMAGEBUFFER = 485, /* IIMAGEBUFFER */
UIMAGEBUFFER = 486, /* UIMAGEBUFFER */
IMAGE1DARRAY = 487, /* IMAGE1DARRAY */
IIMAGE1DARRAY = 488, /* IIMAGE1DARRAY */
UIMAGE1DARRAY = 489, /* UIMAGE1DARRAY */
IMAGE2DARRAY = 490, /* IMAGE2DARRAY */
IIMAGE2DARRAY = 491, /* IIMAGE2DARRAY */
UIMAGE2DARRAY = 492, /* UIMAGE2DARRAY */
IMAGECUBEARRAY = 493, /* IMAGECUBEARRAY */
IIMAGECUBEARRAY = 494, /* IIMAGECUBEARRAY */
UIMAGECUBEARRAY = 495, /* UIMAGECUBEARRAY */
IMAGE2DMS = 496, /* IMAGE2DMS */
IIMAGE2DMS = 497, /* IIMAGE2DMS */
UIMAGE2DMS = 498, /* UIMAGE2DMS */
IMAGE2DMSARRAY = 499, /* IMAGE2DMSARRAY */
IIMAGE2DMSARRAY = 500, /* IIMAGE2DMSARRAY */
UIMAGE2DMSARRAY = 501, /* UIMAGE2DMSARRAY */
F16IMAGE1D = 502, /* F16IMAGE1D */
F16IMAGE2D = 503, /* F16IMAGE2D */
F16IMAGE3D = 504, /* F16IMAGE3D */
F16IMAGE2DRECT = 505, /* F16IMAGE2DRECT */
F16IMAGECUBE = 506, /* F16IMAGECUBE */
F16IMAGE1DARRAY = 507, /* F16IMAGE1DARRAY */
F16IMAGE2DARRAY = 508, /* F16IMAGE2DARRAY */
F16IMAGECUBEARRAY = 509, /* F16IMAGECUBEARRAY */
F16IMAGEBUFFER = 510, /* F16IMAGEBUFFER */
F16IMAGE2DMS = 511, /* F16IMAGE2DMS */
F16IMAGE2DMSARRAY = 512, /* F16IMAGE2DMSARRAY */
I64IMAGE1D = 513, /* I64IMAGE1D */
U64IMAGE1D = 514, /* U64IMAGE1D */
I64IMAGE2D = 515, /* I64IMAGE2D */
U64IMAGE2D = 516, /* U64IMAGE2D */
I64IMAGE3D = 517, /* I64IMAGE3D */
U64IMAGE3D = 518, /* U64IMAGE3D */
I64IMAGE2DRECT = 519, /* I64IMAGE2DRECT */
U64IMAGE2DRECT = 520, /* U64IMAGE2DRECT */
I64IMAGECUBE = 521, /* I64IMAGECUBE */
U64IMAGECUBE = 522, /* U64IMAGECUBE */
I64IMAGEBUFFER = 523, /* I64IMAGEBUFFER */
U64IMAGEBUFFER = 524, /* U64IMAGEBUFFER */
I64IMAGE1DARRAY = 525, /* I64IMAGE1DARRAY */
U64IMAGE1DARRAY = 526, /* U64IMAGE1DARRAY */
I64IMAGE2DARRAY = 527, /* I64IMAGE2DARRAY */
U64IMAGE2DARRAY = 528, /* U64IMAGE2DARRAY */
I64IMAGECUBEARRAY = 529, /* I64IMAGECUBEARRAY */
U64IMAGECUBEARRAY = 530, /* U64IMAGECUBEARRAY */
I64IMAGE2DMS = 531, /* I64IMAGE2DMS */
U64IMAGE2DMS = 532, /* U64IMAGE2DMS */
I64IMAGE2DMSARRAY = 533, /* I64IMAGE2DMSARRAY */
U64IMAGE2DMSARRAY = 534, /* U64IMAGE2DMSARRAY */
TEXTURECUBEARRAY = 535, /* TEXTURECUBEARRAY */
ITEXTURECUBEARRAY = 536, /* ITEXTURECUBEARRAY */
UTEXTURECUBEARRAY = 537, /* UTEXTURECUBEARRAY */
TEXTURE1D = 538, /* TEXTURE1D */
ITEXTURE1D = 539, /* ITEXTURE1D */
UTEXTURE1D = 540, /* UTEXTURE1D */
TEXTURE1DARRAY = 541, /* TEXTURE1DARRAY */
ITEXTURE1DARRAY = 542, /* ITEXTURE1DARRAY */
UTEXTURE1DARRAY = 543, /* UTEXTURE1DARRAY */
TEXTURE2DRECT = 544, /* TEXTURE2DRECT */
ITEXTURE2DRECT = 545, /* ITEXTURE2DRECT */
UTEXTURE2DRECT = 546, /* UTEXTURE2DRECT */
TEXTUREBUFFER = 547, /* TEXTUREBUFFER */
ITEXTUREBUFFER = 548, /* ITEXTUREBUFFER */
UTEXTUREBUFFER = 549, /* UTEXTUREBUFFER */
TEXTURE2DMS = 550, /* TEXTURE2DMS */
ITEXTURE2DMS = 551, /* ITEXTURE2DMS */
UTEXTURE2DMS = 552, /* UTEXTURE2DMS */
TEXTURE2DMSARRAY = 553, /* TEXTURE2DMSARRAY */
ITEXTURE2DMSARRAY = 554, /* ITEXTURE2DMSARRAY */
UTEXTURE2DMSARRAY = 555, /* UTEXTURE2DMSARRAY */
F16TEXTURE1D = 556, /* F16TEXTURE1D */
F16TEXTURE2D = 557, /* F16TEXTURE2D */
F16TEXTURE3D = 558, /* F16TEXTURE3D */
F16TEXTURE2DRECT = 559, /* F16TEXTURE2DRECT */
F16TEXTURECUBE = 560, /* F16TEXTURECUBE */
F16TEXTURE1DARRAY = 561, /* F16TEXTURE1DARRAY */
F16TEXTURE2DARRAY = 562, /* F16TEXTURE2DARRAY */
F16TEXTURECUBEARRAY = 563, /* F16TEXTURECUBEARRAY */
F16TEXTUREBUFFER = 564, /* F16TEXTUREBUFFER */
F16TEXTURE2DMS = 565, /* F16TEXTURE2DMS */
F16TEXTURE2DMSARRAY = 566, /* F16TEXTURE2DMSARRAY */
SUBPASSINPUT = 567, /* SUBPASSINPUT */
SUBPASSINPUTMS = 568, /* SUBPASSINPUTMS */
ISUBPASSINPUT = 569, /* ISUBPASSINPUT */
ISUBPASSINPUTMS = 570, /* ISUBPASSINPUTMS */
USUBPASSINPUT = 571, /* USUBPASSINPUT */
USUBPASSINPUTMS = 572, /* USUBPASSINPUTMS */
F16SUBPASSINPUT = 573, /* F16SUBPASSINPUT */
F16SUBPASSINPUTMS = 574, /* F16SUBPASSINPUTMS */
SPIRV_INSTRUCTION = 575, /* SPIRV_INSTRUCTION */
SPIRV_EXECUTION_MODE = 576, /* SPIRV_EXECUTION_MODE */
SPIRV_EXECUTION_MODE_ID = 577, /* SPIRV_EXECUTION_MODE_ID */
SPIRV_DECORATE = 578, /* SPIRV_DECORATE */
SPIRV_DECORATE_ID = 579, /* SPIRV_DECORATE_ID */
SPIRV_DECORATE_STRING = 580, /* SPIRV_DECORATE_STRING */
SPIRV_TYPE = 581, /* SPIRV_TYPE */
SPIRV_STORAGE_CLASS = 582, /* SPIRV_STORAGE_CLASS */
SPIRV_BY_REFERENCE = 583, /* SPIRV_BY_REFERENCE */
SPIRV_LITERAL = 584, /* SPIRV_LITERAL */
ATTACHMENTEXT = 585, /* ATTACHMENTEXT */
IATTACHMENTEXT = 586, /* IATTACHMENTEXT */
UATTACHMENTEXT = 587, /* UATTACHMENTEXT */
LEFT_OP = 588, /* LEFT_OP */
RIGHT_OP = 589, /* RIGHT_OP */
INC_OP = 590, /* INC_OP */
DEC_OP = 591, /* DEC_OP */
LE_OP = 592, /* LE_OP */
GE_OP = 593, /* GE_OP */
EQ_OP = 594, /* EQ_OP */
NE_OP = 595, /* NE_OP */
AND_OP = 596, /* AND_OP */
OR_OP = 597, /* OR_OP */
XOR_OP = 598, /* XOR_OP */
MUL_ASSIGN = 599, /* MUL_ASSIGN */
DIV_ASSIGN = 600, /* DIV_ASSIGN */
ADD_ASSIGN = 601, /* ADD_ASSIGN */
MOD_ASSIGN = 602, /* MOD_ASSIGN */
LEFT_ASSIGN = 603, /* LEFT_ASSIGN */
RIGHT_ASSIGN = 604, /* RIGHT_ASSIGN */
AND_ASSIGN = 605, /* AND_ASSIGN */
XOR_ASSIGN = 606, /* XOR_ASSIGN */
OR_ASSIGN = 607, /* OR_ASSIGN */
SUB_ASSIGN = 608, /* SUB_ASSIGN */
STRING_LITERAL = 609, /* STRING_LITERAL */
LEFT_PAREN = 610, /* LEFT_PAREN */
RIGHT_PAREN = 611, /* RIGHT_PAREN */
LEFT_BRACKET = 612, /* LEFT_BRACKET */
RIGHT_BRACKET = 613, /* RIGHT_BRACKET */
LEFT_BRACE = 614, /* LEFT_BRACE */
RIGHT_BRACE = 615, /* RIGHT_BRACE */
DOT = 616, /* DOT */
COMMA = 617, /* COMMA */
COLON = 618, /* COLON */
EQUAL = 619, /* EQUAL */
SEMICOLON = 620, /* SEMICOLON */
BANG = 621, /* BANG */
DASH = 622, /* DASH */
TILDE = 623, /* TILDE */
PLUS = 624, /* PLUS */
STAR = 625, /* STAR */
SLASH = 626, /* SLASH */
PERCENT = 627, /* PERCENT */
LEFT_ANGLE = 628, /* LEFT_ANGLE */
RIGHT_ANGLE = 629, /* RIGHT_ANGLE */
VERTICAL_BAR = 630, /* VERTICAL_BAR */
CARET = 631, /* CARET */
AMPERSAND = 632, /* AMPERSAND */
QUESTION = 633, /* QUESTION */
INVARIANT = 634, /* INVARIANT */
HIGH_PRECISION = 635, /* HIGH_PRECISION */
MEDIUM_PRECISION = 636, /* MEDIUM_PRECISION */
LOW_PRECISION = 637, /* LOW_PRECISION */
PRECISION = 638, /* PRECISION */
PACKED = 639, /* PACKED */
RESOURCE = 640, /* RESOURCE */
SUPERP = 641, /* SUPERP */
FLOATCONSTANT = 642, /* FLOATCONSTANT */
INTCONSTANT = 643, /* INTCONSTANT */
UINTCONSTANT = 644, /* UINTCONSTANT */
BOOLCONSTANT = 645, /* BOOLCONSTANT */
IDENTIFIER = 646, /* IDENTIFIER */
TYPE_NAME = 647, /* TYPE_NAME */
CENTROID = 648, /* CENTROID */
IN = 649, /* IN */
OUT = 650, /* OUT */
INOUT = 651, /* INOUT */
STRUCT = 652, /* STRUCT */
VOID = 653, /* VOID */
WHILE = 654, /* WHILE */
BREAK = 655, /* BREAK */
CONTINUE = 656, /* CONTINUE */
DO = 657, /* DO */
ELSE = 658, /* ELSE */
FOR = 659, /* FOR */
IF = 660, /* IF */
DISCARD = 661, /* DISCARD */
RETURN = 662, /* RETURN */
SWITCH = 663, /* SWITCH */
CASE = 664, /* CASE */
DEFAULT = 665, /* DEFAULT */
TERMINATE_INVOCATION = 666, /* TERMINATE_INVOCATION */
TERMINATE_RAY = 667, /* TERMINATE_RAY */
IGNORE_INTERSECTION = 668, /* IGNORE_INTERSECTION */
UNIFORM = 669, /* UNIFORM */
SHARED = 670, /* SHARED */
BUFFER = 671, /* BUFFER */
TILEIMAGEEXT = 672, /* TILEIMAGEEXT */
FLAT = 673, /* FLAT */
SMOOTH = 674, /* SMOOTH */
LAYOUT = 675, /* LAYOUT */
DOUBLECONSTANT = 676, /* DOUBLECONSTANT */
INT16CONSTANT = 677, /* INT16CONSTANT */
UINT16CONSTANT = 678, /* UINT16CONSTANT */
FLOAT16CONSTANT = 679, /* FLOAT16CONSTANT */
INT32CONSTANT = 680, /* INT32CONSTANT */
UINT32CONSTANT = 681, /* UINT32CONSTANT */
INT64CONSTANT = 682, /* INT64CONSTANT */
UINT64CONSTANT = 683, /* UINT64CONSTANT */
SUBROUTINE = 684, /* SUBROUTINE */
DEMOTE = 685, /* DEMOTE */
PAYLOADNV = 686, /* PAYLOADNV */
PAYLOADINNV = 687, /* PAYLOADINNV */
HITATTRNV = 688, /* HITATTRNV */
CALLDATANV = 689, /* CALLDATANV */
CALLDATAINNV = 690, /* CALLDATAINNV */
PAYLOADEXT = 691, /* PAYLOADEXT */
PAYLOADINEXT = 692, /* PAYLOADINEXT */
HITATTREXT = 693, /* HITATTREXT */
CALLDATAEXT = 694, /* CALLDATAEXT */
CALLDATAINEXT = 695, /* CALLDATAINEXT */
PATCH = 696, /* PATCH */
SAMPLE = 697, /* SAMPLE */
NONUNIFORM = 698, /* NONUNIFORM */
COHERENT = 699, /* COHERENT */
VOLATILE = 700, /* VOLATILE */
RESTRICT = 701, /* RESTRICT */
READONLY = 702, /* READONLY */
WRITEONLY = 703, /* WRITEONLY */
DEVICECOHERENT = 704, /* DEVICECOHERENT */
QUEUEFAMILYCOHERENT = 705, /* QUEUEFAMILYCOHERENT */
WORKGROUPCOHERENT = 706, /* WORKGROUPCOHERENT */
SUBGROUPCOHERENT = 707, /* SUBGROUPCOHERENT */
NONPRIVATE = 708, /* NONPRIVATE */
SHADERCALLCOHERENT = 709, /* SHADERCALLCOHERENT */
NOPERSPECTIVE = 710, /* NOPERSPECTIVE */
EXPLICITINTERPAMD = 711, /* EXPLICITINTERPAMD */
PERVERTEXEXT = 712, /* PERVERTEXEXT */
PERVERTEXNV = 713, /* PERVERTEXNV */
PERPRIMITIVENV = 714, /* PERPRIMITIVENV */
PERVIEWNV = 715, /* PERVIEWNV */
PERTASKNV = 716, /* PERTASKNV */
PERPRIMITIVEEXT = 717, /* PERPRIMITIVEEXT */
TASKPAYLOADWORKGROUPEXT = 718, /* TASKPAYLOADWORKGROUPEXT */
PRECISE = 719 /* PRECISE */
FLOATE5M2_T = 318, /* FLOATE5M2_T */
FLOATE4M3_T = 319, /* FLOATE4M3_T */
BFLOAT16_T = 320, /* BFLOAT16_T */
FLOAT16_T = 321, /* FLOAT16_T */
FLOAT32_T = 322, /* FLOAT32_T */
DOUBLE = 323, /* DOUBLE */
FLOAT64_T = 324, /* FLOAT64_T */
INT64_T = 325, /* INT64_T */
UINT64_T = 326, /* UINT64_T */
INT32_T = 327, /* INT32_T */
UINT32_T = 328, /* UINT32_T */
INT16_T = 329, /* INT16_T */
UINT16_T = 330, /* UINT16_T */
INT8_T = 331, /* INT8_T */
UINT8_T = 332, /* UINT8_T */
I64VEC2 = 333, /* I64VEC2 */
I64VEC3 = 334, /* I64VEC3 */
I64VEC4 = 335, /* I64VEC4 */
U64VEC2 = 336, /* U64VEC2 */
U64VEC3 = 337, /* U64VEC3 */
U64VEC4 = 338, /* U64VEC4 */
I32VEC2 = 339, /* I32VEC2 */
I32VEC3 = 340, /* I32VEC3 */
I32VEC4 = 341, /* I32VEC4 */
U32VEC2 = 342, /* U32VEC2 */
U32VEC3 = 343, /* U32VEC3 */
U32VEC4 = 344, /* U32VEC4 */
I16VEC2 = 345, /* I16VEC2 */
I16VEC3 = 346, /* I16VEC3 */
I16VEC4 = 347, /* I16VEC4 */
U16VEC2 = 348, /* U16VEC2 */
U16VEC3 = 349, /* U16VEC3 */
U16VEC4 = 350, /* U16VEC4 */
I8VEC2 = 351, /* I8VEC2 */
I8VEC3 = 352, /* I8VEC3 */
I8VEC4 = 353, /* I8VEC4 */
U8VEC2 = 354, /* U8VEC2 */
U8VEC3 = 355, /* U8VEC3 */
U8VEC4 = 356, /* U8VEC4 */
DVEC2 = 357, /* DVEC2 */
DVEC3 = 358, /* DVEC3 */
DVEC4 = 359, /* DVEC4 */
DMAT2 = 360, /* DMAT2 */
DMAT3 = 361, /* DMAT3 */
DMAT4 = 362, /* DMAT4 */
BF16VEC2 = 363, /* BF16VEC2 */
BF16VEC3 = 364, /* BF16VEC3 */
BF16VEC4 = 365, /* BF16VEC4 */
FE5M2VEC2 = 366, /* FE5M2VEC2 */
FE5M2VEC3 = 367, /* FE5M2VEC3 */
FE5M2VEC4 = 368, /* FE5M2VEC4 */
FE4M3VEC2 = 369, /* FE4M3VEC2 */
FE4M3VEC3 = 370, /* FE4M3VEC3 */
FE4M3VEC4 = 371, /* FE4M3VEC4 */
F16VEC2 = 372, /* F16VEC2 */
F16VEC3 = 373, /* F16VEC3 */
F16VEC4 = 374, /* F16VEC4 */
F16MAT2 = 375, /* F16MAT2 */
F16MAT3 = 376, /* F16MAT3 */
F16MAT4 = 377, /* F16MAT4 */
F32VEC2 = 378, /* F32VEC2 */
F32VEC3 = 379, /* F32VEC3 */
F32VEC4 = 380, /* F32VEC4 */
F32MAT2 = 381, /* F32MAT2 */
F32MAT3 = 382, /* F32MAT3 */
F32MAT4 = 383, /* F32MAT4 */
F64VEC2 = 384, /* F64VEC2 */
F64VEC3 = 385, /* F64VEC3 */
F64VEC4 = 386, /* F64VEC4 */
F64MAT2 = 387, /* F64MAT2 */
F64MAT3 = 388, /* F64MAT3 */
F64MAT4 = 389, /* F64MAT4 */
DMAT2X2 = 390, /* DMAT2X2 */
DMAT2X3 = 391, /* DMAT2X3 */
DMAT2X4 = 392, /* DMAT2X4 */
DMAT3X2 = 393, /* DMAT3X2 */
DMAT3X3 = 394, /* DMAT3X3 */
DMAT3X4 = 395, /* DMAT3X4 */
DMAT4X2 = 396, /* DMAT4X2 */
DMAT4X3 = 397, /* DMAT4X3 */
DMAT4X4 = 398, /* DMAT4X4 */
F16MAT2X2 = 399, /* F16MAT2X2 */
F16MAT2X3 = 400, /* F16MAT2X3 */
F16MAT2X4 = 401, /* F16MAT2X4 */
F16MAT3X2 = 402, /* F16MAT3X2 */
F16MAT3X3 = 403, /* F16MAT3X3 */
F16MAT3X4 = 404, /* F16MAT3X4 */
F16MAT4X2 = 405, /* F16MAT4X2 */
F16MAT4X3 = 406, /* F16MAT4X3 */
F16MAT4X4 = 407, /* F16MAT4X4 */
F32MAT2X2 = 408, /* F32MAT2X2 */
F32MAT2X3 = 409, /* F32MAT2X3 */
F32MAT2X4 = 410, /* F32MAT2X4 */
F32MAT3X2 = 411, /* F32MAT3X2 */
F32MAT3X3 = 412, /* F32MAT3X3 */
F32MAT3X4 = 413, /* F32MAT3X4 */
F32MAT4X2 = 414, /* F32MAT4X2 */
F32MAT4X3 = 415, /* F32MAT4X3 */
F32MAT4X4 = 416, /* F32MAT4X4 */
F64MAT2X2 = 417, /* F64MAT2X2 */
F64MAT2X3 = 418, /* F64MAT2X3 */
F64MAT2X4 = 419, /* F64MAT2X4 */
F64MAT3X2 = 420, /* F64MAT3X2 */
F64MAT3X3 = 421, /* F64MAT3X3 */
F64MAT3X4 = 422, /* F64MAT3X4 */
F64MAT4X2 = 423, /* F64MAT4X2 */
F64MAT4X3 = 424, /* F64MAT4X3 */
F64MAT4X4 = 425, /* F64MAT4X4 */
ATOMIC_UINT = 426, /* ATOMIC_UINT */
ACCSTRUCTNV = 427, /* ACCSTRUCTNV */
ACCSTRUCTEXT = 428, /* ACCSTRUCTEXT */
RAYQUERYEXT = 429, /* RAYQUERYEXT */
FCOOPMATNV = 430, /* FCOOPMATNV */
ICOOPMATNV = 431, /* ICOOPMATNV */
UCOOPMATNV = 432, /* UCOOPMATNV */
COOPMAT = 433, /* COOPMAT */
COOPVECNV = 434, /* COOPVECNV */
HITOBJECTNV = 435, /* HITOBJECTNV */
HITOBJECTATTRNV = 436, /* HITOBJECTATTRNV */
HITOBJECTEXT = 437, /* HITOBJECTEXT */
HITOBJECTATTREXT = 438, /* HITOBJECTATTREXT */
TENSORLAYOUTNV = 439, /* TENSORLAYOUTNV */
TENSORVIEWNV = 440, /* TENSORVIEWNV */
TENSORARM = 441, /* TENSORARM */
SAMPLERCUBEARRAY = 442, /* SAMPLERCUBEARRAY */
SAMPLERCUBEARRAYSHADOW = 443, /* SAMPLERCUBEARRAYSHADOW */
ISAMPLERCUBEARRAY = 444, /* ISAMPLERCUBEARRAY */
USAMPLERCUBEARRAY = 445, /* USAMPLERCUBEARRAY */
SAMPLER1D = 446, /* SAMPLER1D */
SAMPLER1DARRAY = 447, /* SAMPLER1DARRAY */
SAMPLER1DARRAYSHADOW = 448, /* SAMPLER1DARRAYSHADOW */
ISAMPLER1D = 449, /* ISAMPLER1D */
SAMPLER1DSHADOW = 450, /* SAMPLER1DSHADOW */
SAMPLER2DRECT = 451, /* SAMPLER2DRECT */
SAMPLER2DRECTSHADOW = 452, /* SAMPLER2DRECTSHADOW */
ISAMPLER2DRECT = 453, /* ISAMPLER2DRECT */
USAMPLER2DRECT = 454, /* USAMPLER2DRECT */
SAMPLERBUFFER = 455, /* SAMPLERBUFFER */
ISAMPLERBUFFER = 456, /* ISAMPLERBUFFER */
USAMPLERBUFFER = 457, /* USAMPLERBUFFER */
SAMPLER2DMS = 458, /* SAMPLER2DMS */
ISAMPLER2DMS = 459, /* ISAMPLER2DMS */
USAMPLER2DMS = 460, /* USAMPLER2DMS */
SAMPLER2DMSARRAY = 461, /* SAMPLER2DMSARRAY */
ISAMPLER2DMSARRAY = 462, /* ISAMPLER2DMSARRAY */
USAMPLER2DMSARRAY = 463, /* USAMPLER2DMSARRAY */
SAMPLEREXTERNALOES = 464, /* SAMPLEREXTERNALOES */
SAMPLEREXTERNAL2DY2YEXT = 465, /* SAMPLEREXTERNAL2DY2YEXT */
ISAMPLER1DARRAY = 466, /* ISAMPLER1DARRAY */
USAMPLER1D = 467, /* USAMPLER1D */
USAMPLER1DARRAY = 468, /* USAMPLER1DARRAY */
F16SAMPLER1D = 469, /* F16SAMPLER1D */
F16SAMPLER2D = 470, /* F16SAMPLER2D */
F16SAMPLER3D = 471, /* F16SAMPLER3D */
F16SAMPLER2DRECT = 472, /* F16SAMPLER2DRECT */
F16SAMPLERCUBE = 473, /* F16SAMPLERCUBE */
F16SAMPLER1DARRAY = 474, /* F16SAMPLER1DARRAY */
F16SAMPLER2DARRAY = 475, /* F16SAMPLER2DARRAY */
F16SAMPLERCUBEARRAY = 476, /* F16SAMPLERCUBEARRAY */
F16SAMPLERBUFFER = 477, /* F16SAMPLERBUFFER */
F16SAMPLER2DMS = 478, /* F16SAMPLER2DMS */
F16SAMPLER2DMSARRAY = 479, /* F16SAMPLER2DMSARRAY */
F16SAMPLER1DSHADOW = 480, /* F16SAMPLER1DSHADOW */
F16SAMPLER2DSHADOW = 481, /* F16SAMPLER2DSHADOW */
F16SAMPLER1DARRAYSHADOW = 482, /* F16SAMPLER1DARRAYSHADOW */
F16SAMPLER2DARRAYSHADOW = 483, /* F16SAMPLER2DARRAYSHADOW */
F16SAMPLER2DRECTSHADOW = 484, /* F16SAMPLER2DRECTSHADOW */
F16SAMPLERCUBESHADOW = 485, /* F16SAMPLERCUBESHADOW */
F16SAMPLERCUBEARRAYSHADOW = 486, /* F16SAMPLERCUBEARRAYSHADOW */
IMAGE1D = 487, /* IMAGE1D */
IIMAGE1D = 488, /* IIMAGE1D */
UIMAGE1D = 489, /* UIMAGE1D */
IMAGE2D = 490, /* IMAGE2D */
IIMAGE2D = 491, /* IIMAGE2D */
UIMAGE2D = 492, /* UIMAGE2D */
IMAGE3D = 493, /* IMAGE3D */
IIMAGE3D = 494, /* IIMAGE3D */
UIMAGE3D = 495, /* UIMAGE3D */
IMAGE2DRECT = 496, /* IMAGE2DRECT */
IIMAGE2DRECT = 497, /* IIMAGE2DRECT */
UIMAGE2DRECT = 498, /* UIMAGE2DRECT */
IMAGECUBE = 499, /* IMAGECUBE */
IIMAGECUBE = 500, /* IIMAGECUBE */
UIMAGECUBE = 501, /* UIMAGECUBE */
IMAGEBUFFER = 502, /* IMAGEBUFFER */
IIMAGEBUFFER = 503, /* IIMAGEBUFFER */
UIMAGEBUFFER = 504, /* UIMAGEBUFFER */
IMAGE1DARRAY = 505, /* IMAGE1DARRAY */
IIMAGE1DARRAY = 506, /* IIMAGE1DARRAY */
UIMAGE1DARRAY = 507, /* UIMAGE1DARRAY */
IMAGE2DARRAY = 508, /* IMAGE2DARRAY */
IIMAGE2DARRAY = 509, /* IIMAGE2DARRAY */
UIMAGE2DARRAY = 510, /* UIMAGE2DARRAY */
IMAGECUBEARRAY = 511, /* IMAGECUBEARRAY */
IIMAGECUBEARRAY = 512, /* IIMAGECUBEARRAY */
UIMAGECUBEARRAY = 513, /* UIMAGECUBEARRAY */
IMAGE2DMS = 514, /* IMAGE2DMS */
IIMAGE2DMS = 515, /* IIMAGE2DMS */
UIMAGE2DMS = 516, /* UIMAGE2DMS */
IMAGE2DMSARRAY = 517, /* IMAGE2DMSARRAY */
IIMAGE2DMSARRAY = 518, /* IIMAGE2DMSARRAY */
UIMAGE2DMSARRAY = 519, /* UIMAGE2DMSARRAY */
F16IMAGE1D = 520, /* F16IMAGE1D */
F16IMAGE2D = 521, /* F16IMAGE2D */
F16IMAGE3D = 522, /* F16IMAGE3D */
F16IMAGE2DRECT = 523, /* F16IMAGE2DRECT */
F16IMAGECUBE = 524, /* F16IMAGECUBE */
F16IMAGE1DARRAY = 525, /* F16IMAGE1DARRAY */
F16IMAGE2DARRAY = 526, /* F16IMAGE2DARRAY */
F16IMAGECUBEARRAY = 527, /* F16IMAGECUBEARRAY */
F16IMAGEBUFFER = 528, /* F16IMAGEBUFFER */
F16IMAGE2DMS = 529, /* F16IMAGE2DMS */
F16IMAGE2DMSARRAY = 530, /* F16IMAGE2DMSARRAY */
I64IMAGE1D = 531, /* I64IMAGE1D */
U64IMAGE1D = 532, /* U64IMAGE1D */
I64IMAGE2D = 533, /* I64IMAGE2D */
U64IMAGE2D = 534, /* U64IMAGE2D */
I64IMAGE3D = 535, /* I64IMAGE3D */
U64IMAGE3D = 536, /* U64IMAGE3D */
I64IMAGE2DRECT = 537, /* I64IMAGE2DRECT */
U64IMAGE2DRECT = 538, /* U64IMAGE2DRECT */
I64IMAGECUBE = 539, /* I64IMAGECUBE */
U64IMAGECUBE = 540, /* U64IMAGECUBE */
I64IMAGEBUFFER = 541, /* I64IMAGEBUFFER */
U64IMAGEBUFFER = 542, /* U64IMAGEBUFFER */
I64IMAGE1DARRAY = 543, /* I64IMAGE1DARRAY */
U64IMAGE1DARRAY = 544, /* U64IMAGE1DARRAY */
I64IMAGE2DARRAY = 545, /* I64IMAGE2DARRAY */
U64IMAGE2DARRAY = 546, /* U64IMAGE2DARRAY */
I64IMAGECUBEARRAY = 547, /* I64IMAGECUBEARRAY */
U64IMAGECUBEARRAY = 548, /* U64IMAGECUBEARRAY */
I64IMAGE2DMS = 549, /* I64IMAGE2DMS */
U64IMAGE2DMS = 550, /* U64IMAGE2DMS */
I64IMAGE2DMSARRAY = 551, /* I64IMAGE2DMSARRAY */
U64IMAGE2DMSARRAY = 552, /* U64IMAGE2DMSARRAY */
TEXTURECUBEARRAY = 553, /* TEXTURECUBEARRAY */
ITEXTURECUBEARRAY = 554, /* ITEXTURECUBEARRAY */
UTEXTURECUBEARRAY = 555, /* UTEXTURECUBEARRAY */
TEXTURE1D = 556, /* TEXTURE1D */
ITEXTURE1D = 557, /* ITEXTURE1D */
UTEXTURE1D = 558, /* UTEXTURE1D */
TEXTURE1DARRAY = 559, /* TEXTURE1DARRAY */
ITEXTURE1DARRAY = 560, /* ITEXTURE1DARRAY */
UTEXTURE1DARRAY = 561, /* UTEXTURE1DARRAY */
TEXTURE2DRECT = 562, /* TEXTURE2DRECT */
ITEXTURE2DRECT = 563, /* ITEXTURE2DRECT */
UTEXTURE2DRECT = 564, /* UTEXTURE2DRECT */
TEXTUREBUFFER = 565, /* TEXTUREBUFFER */
ITEXTUREBUFFER = 566, /* ITEXTUREBUFFER */
UTEXTUREBUFFER = 567, /* UTEXTUREBUFFER */
TEXTURE2DMS = 568, /* TEXTURE2DMS */
ITEXTURE2DMS = 569, /* ITEXTURE2DMS */
UTEXTURE2DMS = 570, /* UTEXTURE2DMS */
TEXTURE2DMSARRAY = 571, /* TEXTURE2DMSARRAY */
ITEXTURE2DMSARRAY = 572, /* ITEXTURE2DMSARRAY */
UTEXTURE2DMSARRAY = 573, /* UTEXTURE2DMSARRAY */
F16TEXTURE1D = 574, /* F16TEXTURE1D */
F16TEXTURE2D = 575, /* F16TEXTURE2D */
F16TEXTURE3D = 576, /* F16TEXTURE3D */
F16TEXTURE2DRECT = 577, /* F16TEXTURE2DRECT */
F16TEXTURECUBE = 578, /* F16TEXTURECUBE */
F16TEXTURE1DARRAY = 579, /* F16TEXTURE1DARRAY */
F16TEXTURE2DARRAY = 580, /* F16TEXTURE2DARRAY */
F16TEXTURECUBEARRAY = 581, /* F16TEXTURECUBEARRAY */
F16TEXTUREBUFFER = 582, /* F16TEXTUREBUFFER */
F16TEXTURE2DMS = 583, /* F16TEXTURE2DMS */
F16TEXTURE2DMSARRAY = 584, /* F16TEXTURE2DMSARRAY */
SUBPASSINPUT = 585, /* SUBPASSINPUT */
SUBPASSINPUTMS = 586, /* SUBPASSINPUTMS */
ISUBPASSINPUT = 587, /* ISUBPASSINPUT */
ISUBPASSINPUTMS = 588, /* ISUBPASSINPUTMS */
USUBPASSINPUT = 589, /* USUBPASSINPUT */
USUBPASSINPUTMS = 590, /* USUBPASSINPUTMS */
F16SUBPASSINPUT = 591, /* F16SUBPASSINPUT */
F16SUBPASSINPUTMS = 592, /* F16SUBPASSINPUTMS */
SPIRV_INSTRUCTION = 593, /* SPIRV_INSTRUCTION */
SPIRV_EXECUTION_MODE = 594, /* SPIRV_EXECUTION_MODE */
SPIRV_EXECUTION_MODE_ID = 595, /* SPIRV_EXECUTION_MODE_ID */
SPIRV_DECORATE = 596, /* SPIRV_DECORATE */
SPIRV_DECORATE_ID = 597, /* SPIRV_DECORATE_ID */
SPIRV_DECORATE_STRING = 598, /* SPIRV_DECORATE_STRING */
SPIRV_TYPE = 599, /* SPIRV_TYPE */
SPIRV_STORAGE_CLASS = 600, /* SPIRV_STORAGE_CLASS */
SPIRV_BY_REFERENCE = 601, /* SPIRV_BY_REFERENCE */
SPIRV_LITERAL = 602, /* SPIRV_LITERAL */
ATTACHMENTEXT = 603, /* ATTACHMENTEXT */
IATTACHMENTEXT = 604, /* IATTACHMENTEXT */
UATTACHMENTEXT = 605, /* UATTACHMENTEXT */
LEFT_OP = 606, /* LEFT_OP */
RIGHT_OP = 607, /* RIGHT_OP */
INC_OP = 608, /* INC_OP */
DEC_OP = 609, /* DEC_OP */
LE_OP = 610, /* LE_OP */
GE_OP = 611, /* GE_OP */
EQ_OP = 612, /* EQ_OP */
NE_OP = 613, /* NE_OP */
AND_OP = 614, /* AND_OP */
OR_OP = 615, /* OR_OP */
XOR_OP = 616, /* XOR_OP */
MUL_ASSIGN = 617, /* MUL_ASSIGN */
DIV_ASSIGN = 618, /* DIV_ASSIGN */
ADD_ASSIGN = 619, /* ADD_ASSIGN */
MOD_ASSIGN = 620, /* MOD_ASSIGN */
LEFT_ASSIGN = 621, /* LEFT_ASSIGN */
RIGHT_ASSIGN = 622, /* RIGHT_ASSIGN */
AND_ASSIGN = 623, /* AND_ASSIGN */
XOR_ASSIGN = 624, /* XOR_ASSIGN */
OR_ASSIGN = 625, /* OR_ASSIGN */
SUB_ASSIGN = 626, /* SUB_ASSIGN */
STRING_LITERAL = 627, /* STRING_LITERAL */
LEFT_PAREN = 628, /* LEFT_PAREN */
RIGHT_PAREN = 629, /* RIGHT_PAREN */
LEFT_BRACKET = 630, /* LEFT_BRACKET */
RIGHT_BRACKET = 631, /* RIGHT_BRACKET */
LEFT_BRACE = 632, /* LEFT_BRACE */
RIGHT_BRACE = 633, /* RIGHT_BRACE */
DOT = 634, /* DOT */
COMMA = 635, /* COMMA */
COLON = 636, /* COLON */
EQUAL = 637, /* EQUAL */
SEMICOLON = 638, /* SEMICOLON */
BANG = 639, /* BANG */
DASH = 640, /* DASH */
TILDE = 641, /* TILDE */
PLUS = 642, /* PLUS */
STAR = 643, /* STAR */
SLASH = 644, /* SLASH */
PERCENT = 645, /* PERCENT */
LEFT_ANGLE = 646, /* LEFT_ANGLE */
RIGHT_ANGLE = 647, /* RIGHT_ANGLE */
VERTICAL_BAR = 648, /* VERTICAL_BAR */
CARET = 649, /* CARET */
AMPERSAND = 650, /* AMPERSAND */
QUESTION = 651, /* QUESTION */
INVARIANT = 652, /* INVARIANT */
HIGH_PRECISION = 653, /* HIGH_PRECISION */
MEDIUM_PRECISION = 654, /* MEDIUM_PRECISION */
LOW_PRECISION = 655, /* LOW_PRECISION */
PRECISION = 656, /* PRECISION */
PACKED = 657, /* PACKED */
RESOURCE = 658, /* RESOURCE */
SUPERP = 659, /* SUPERP */
FLOATCONSTANT = 660, /* FLOATCONSTANT */
INTCONSTANT = 661, /* INTCONSTANT */
UINTCONSTANT = 662, /* UINTCONSTANT */
BOOLCONSTANT = 663, /* BOOLCONSTANT */
IDENTIFIER = 664, /* IDENTIFIER */
TYPE_NAME = 665, /* TYPE_NAME */
CENTROID = 666, /* CENTROID */
IN = 667, /* IN */
OUT = 668, /* OUT */
INOUT = 669, /* INOUT */
STRUCT = 670, /* STRUCT */
VOID = 671, /* VOID */
WHILE = 672, /* WHILE */
BREAK = 673, /* BREAK */
CONTINUE = 674, /* CONTINUE */
DO = 675, /* DO */
ELSE = 676, /* ELSE */
FOR = 677, /* FOR */
IF = 678, /* IF */
DISCARD = 679, /* DISCARD */
RETURN = 680, /* RETURN */
SWITCH = 681, /* SWITCH */
CASE = 682, /* CASE */
DEFAULT = 683, /* DEFAULT */
TERMINATE_INVOCATION = 684, /* TERMINATE_INVOCATION */
TERMINATE_RAY = 685, /* TERMINATE_RAY */
IGNORE_INTERSECTION = 686, /* IGNORE_INTERSECTION */
UNIFORM = 687, /* UNIFORM */
SHARED = 688, /* SHARED */
BUFFER = 689, /* BUFFER */
TILEIMAGEEXT = 690, /* TILEIMAGEEXT */
FLAT = 691, /* FLAT */
SMOOTH = 692, /* SMOOTH */
LAYOUT = 693, /* LAYOUT */
DOUBLECONSTANT = 694, /* DOUBLECONSTANT */
INT16CONSTANT = 695, /* INT16CONSTANT */
UINT16CONSTANT = 696, /* UINT16CONSTANT */
FLOAT16CONSTANT = 697, /* FLOAT16CONSTANT */
INT32CONSTANT = 698, /* INT32CONSTANT */
UINT32CONSTANT = 699, /* UINT32CONSTANT */
INT64CONSTANT = 700, /* INT64CONSTANT */
UINT64CONSTANT = 701, /* UINT64CONSTANT */
SUBROUTINE = 702, /* SUBROUTINE */
DEMOTE = 703, /* DEMOTE */
FUNCTION = 704, /* FUNCTION */
PAYLOADNV = 705, /* PAYLOADNV */
PAYLOADINNV = 706, /* PAYLOADINNV */
HITATTRNV = 707, /* HITATTRNV */
CALLDATANV = 708, /* CALLDATANV */
CALLDATAINNV = 709, /* CALLDATAINNV */
PAYLOADEXT = 710, /* PAYLOADEXT */
PAYLOADINEXT = 711, /* PAYLOADINEXT */
HITATTREXT = 712, /* HITATTREXT */
CALLDATAEXT = 713, /* CALLDATAEXT */
CALLDATAINEXT = 714, /* CALLDATAINEXT */
PATCH = 715, /* PATCH */
SAMPLE = 716, /* SAMPLE */
NONUNIFORM = 717, /* NONUNIFORM */
COHERENT = 718, /* COHERENT */
VOLATILE = 719, /* VOLATILE */
RESTRICT = 720, /* RESTRICT */
READONLY = 721, /* READONLY */
WRITEONLY = 722, /* WRITEONLY */
NONTEMPORAL = 723, /* NONTEMPORAL */
DEVICECOHERENT = 724, /* DEVICECOHERENT */
QUEUEFAMILYCOHERENT = 725, /* QUEUEFAMILYCOHERENT */
WORKGROUPCOHERENT = 726, /* WORKGROUPCOHERENT */
SUBGROUPCOHERENT = 727, /* SUBGROUPCOHERENT */
NONPRIVATE = 728, /* NONPRIVATE */
SHADERCALLCOHERENT = 729, /* SHADERCALLCOHERENT */
NOPERSPECTIVE = 730, /* NOPERSPECTIVE */
EXPLICITINTERPAMD = 731, /* EXPLICITINTERPAMD */
PERVERTEXEXT = 732, /* PERVERTEXEXT */
PERVERTEXNV = 733, /* PERVERTEXNV */
PERPRIMITIVENV = 734, /* PERPRIMITIVENV */
PERVIEWNV = 735, /* PERVIEWNV */
PERTASKNV = 736, /* PERTASKNV */
PERPRIMITIVEEXT = 737, /* PERPRIMITIVEEXT */
TASKPAYLOADWORKGROUPEXT = 738, /* TASKPAYLOADWORKGROUPEXT */
PRECISE = 739 /* PRECISE */
};
typedef enum yytokentype yytoken_kind_t;
#endif
@ -563,7 +583,7 @@ union YYSTYPE
glslang::TTypeParameters* typeParameters;
} interm;
#line 567 "MachineIndependent/glslang_tab.cpp.h"
#line 587 "MachineIndependent/glslang_tab.cpp.h"
};
typedef union YYSTYPE YYSTYPE;

View file

@ -81,6 +81,7 @@ public:
virtual bool visitLoop(TVisit, TIntermLoop* node);
virtual bool visitBranch(TVisit, TIntermBranch* node);
virtual bool visitSwitch(TVisit, TIntermSwitch* node);
virtual bool visitVariableDecl(TVisit, TIntermVariableDecl* node);
TInfoSink& infoSink;
protected:
@ -204,6 +205,13 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
OutputTreeText(out, node, depth);
if (IsOpNumericConv(node->getAsOperator()->getOp())) {
out.debug << "Convert " << TType::getBasicString(node->getOperand()->getType().getBasicType()) << " to " << TType::getBasicString(node->getType().getBasicType());
out.debug << " (" << node->getCompleteString() << ")";
out.debug << "\n";
return true;
}
switch (node->getOp()) {
case EOpNegative: out.debug << "Negate value"; break;
case EOpVectorLogicalNot:
@ -216,192 +224,6 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
case EOpPreDecrement: out.debug << "Pre-Decrement"; break;
case EOpCopyObject: out.debug << "copy object"; break;
// * -> bool
case EOpConvInt8ToBool: out.debug << "Convert int8_t to bool"; break;
case EOpConvUint8ToBool: out.debug << "Convert uint8_t to bool"; break;
case EOpConvInt16ToBool: out.debug << "Convert int16_t to bool"; break;
case EOpConvUint16ToBool: out.debug << "Convert uint16_t to bool";break;
case EOpConvIntToBool: out.debug << "Convert int to bool"; break;
case EOpConvUintToBool: out.debug << "Convert uint to bool"; break;
case EOpConvInt64ToBool: out.debug << "Convert int64 to bool"; break;
case EOpConvUint64ToBool: out.debug << "Convert uint64 to bool"; break;
case EOpConvFloat16ToBool: out.debug << "Convert float16_t to bool"; break;
case EOpConvFloatToBool: out.debug << "Convert float to bool"; break;
case EOpConvDoubleToBool: out.debug << "Convert double to bool"; break;
// bool -> *
case EOpConvBoolToInt8: out.debug << "Convert bool to int8_t"; break;
case EOpConvBoolToUint8: out.debug << "Convert bool to uint8_t"; break;
case EOpConvBoolToInt16: out.debug << "Convert bool to in16t_t"; break;
case EOpConvBoolToUint16: out.debug << "Convert bool to uint16_t";break;
case EOpConvBoolToInt: out.debug << "Convert bool to int" ; break;
case EOpConvBoolToUint: out.debug << "Convert bool to uint"; break;
case EOpConvBoolToInt64: out.debug << "Convert bool to int64"; break;
case EOpConvBoolToUint64: out.debug << "Convert bool to uint64";break;
case EOpConvBoolToFloat16: out.debug << "Convert bool to float16_t"; break;
case EOpConvBoolToFloat: out.debug << "Convert bool to float"; break;
case EOpConvBoolToDouble: out.debug << "Convert bool to double"; break;
// int8_t -> (u)int*
case EOpConvInt8ToInt16: out.debug << "Convert int8_t to int16_t";break;
case EOpConvInt8ToInt: out.debug << "Convert int8_t to int"; break;
case EOpConvInt8ToInt64: out.debug << "Convert int8_t to int64"; break;
case EOpConvInt8ToUint8: out.debug << "Convert int8_t to uint8_t";break;
case EOpConvInt8ToUint16: out.debug << "Convert int8_t to uint16_t";break;
case EOpConvInt8ToUint: out.debug << "Convert int8_t to uint"; break;
case EOpConvInt8ToUint64: out.debug << "Convert int8_t to uint64"; break;
// uint8_t -> (u)int*
case EOpConvUint8ToInt8: out.debug << "Convert uint8_t to int8_t";break;
case EOpConvUint8ToInt16: out.debug << "Convert uint8_t to int16_t";break;
case EOpConvUint8ToInt: out.debug << "Convert uint8_t to int"; break;
case EOpConvUint8ToInt64: out.debug << "Convert uint8_t to int64"; break;
case EOpConvUint8ToUint16: out.debug << "Convert uint8_t to uint16_t";break;
case EOpConvUint8ToUint: out.debug << "Convert uint8_t to uint"; break;
case EOpConvUint8ToUint64: out.debug << "Convert uint8_t to uint64"; break;
// int8_t -> float*
case EOpConvInt8ToFloat16: out.debug << "Convert int8_t to float16_t";break;
case EOpConvInt8ToFloat: out.debug << "Convert int8_t to float"; break;
case EOpConvInt8ToDouble: out.debug << "Convert int8_t to double"; break;
// uint8_t -> float*
case EOpConvUint8ToFloat16: out.debug << "Convert uint8_t to float16_t";break;
case EOpConvUint8ToFloat: out.debug << "Convert uint8_t to float"; break;
case EOpConvUint8ToDouble: out.debug << "Convert uint8_t to double"; break;
// int16_t -> (u)int*
case EOpConvInt16ToInt8: out.debug << "Convert int16_t to int8_t";break;
case EOpConvInt16ToInt: out.debug << "Convert int16_t to int"; break;
case EOpConvInt16ToInt64: out.debug << "Convert int16_t to int64"; break;
case EOpConvInt16ToUint8: out.debug << "Convert int16_t to uint8_t";break;
case EOpConvInt16ToUint16: out.debug << "Convert int16_t to uint16_t";break;
case EOpConvInt16ToUint: out.debug << "Convert int16_t to uint"; break;
case EOpConvInt16ToUint64: out.debug << "Convert int16_t to uint64"; break;
// int16_t -> float*
case EOpConvInt16ToFloat16: out.debug << "Convert int16_t to float16_t";break;
case EOpConvInt16ToFloat: out.debug << "Convert int16_t to float"; break;
case EOpConvInt16ToDouble: out.debug << "Convert int16_t to double"; break;
// uint16_t -> (u)int*
case EOpConvUint16ToInt8: out.debug << "Convert uint16_t to int8_t";break;
case EOpConvUint16ToInt16: out.debug << "Convert uint16_t to int16_t";break;
case EOpConvUint16ToInt: out.debug << "Convert uint16_t to int"; break;
case EOpConvUint16ToInt64: out.debug << "Convert uint16_t to int64"; break;
case EOpConvUint16ToUint8: out.debug << "Convert uint16_t to uint8_t";break;
case EOpConvUint16ToUint: out.debug << "Convert uint16_t to uint"; break;
case EOpConvUint16ToUint64: out.debug << "Convert uint16_t to uint64"; break;
// uint16_t -> float*
case EOpConvUint16ToFloat16: out.debug << "Convert uint16_t to float16_t";break;
case EOpConvUint16ToFloat: out.debug << "Convert uint16_t to float"; break;
case EOpConvUint16ToDouble: out.debug << "Convert uint16_t to double"; break;
// int32_t -> (u)int*
case EOpConvIntToInt8: out.debug << "Convert int to int8_t";break;
case EOpConvIntToInt16: out.debug << "Convert int to int16_t";break;
case EOpConvIntToInt64: out.debug << "Convert int to int64"; break;
case EOpConvIntToUint8: out.debug << "Convert int to uint8_t";break;
case EOpConvIntToUint16: out.debug << "Convert int to uint16_t";break;
case EOpConvIntToUint: out.debug << "Convert int to uint"; break;
case EOpConvIntToUint64: out.debug << "Convert int to uint64"; break;
// int32_t -> float*
case EOpConvIntToFloat16: out.debug << "Convert int to float16_t";break;
case EOpConvIntToFloat: out.debug << "Convert int to float"; break;
case EOpConvIntToDouble: out.debug << "Convert int to double"; break;
// uint32_t -> (u)int*
case EOpConvUintToInt8: out.debug << "Convert uint to int8_t";break;
case EOpConvUintToInt16: out.debug << "Convert uint to int16_t";break;
case EOpConvUintToInt: out.debug << "Convert uint to int";break;
case EOpConvUintToInt64: out.debug << "Convert uint to int64"; break;
case EOpConvUintToUint8: out.debug << "Convert uint to uint8_t";break;
case EOpConvUintToUint16: out.debug << "Convert uint to uint16_t";break;
case EOpConvUintToUint64: out.debug << "Convert uint to uint64"; break;
// uint32_t -> float*
case EOpConvUintToFloat16: out.debug << "Convert uint to float16_t";break;
case EOpConvUintToFloat: out.debug << "Convert uint to float"; break;
case EOpConvUintToDouble: out.debug << "Convert uint to double"; break;
// int64 -> (u)int*
case EOpConvInt64ToInt8: out.debug << "Convert int64 to int8_t"; break;
case EOpConvInt64ToInt16: out.debug << "Convert int64 to int16_t"; break;
case EOpConvInt64ToInt: out.debug << "Convert int64 to int"; break;
case EOpConvInt64ToUint8: out.debug << "Convert int64 to uint8_t";break;
case EOpConvInt64ToUint16: out.debug << "Convert int64 to uint16_t";break;
case EOpConvInt64ToUint: out.debug << "Convert int64 to uint"; break;
case EOpConvInt64ToUint64: out.debug << "Convert int64 to uint64"; break;
// int64 -> float*
case EOpConvInt64ToFloat16: out.debug << "Convert int64 to float16_t";break;
case EOpConvInt64ToFloat: out.debug << "Convert int64 to float"; break;
case EOpConvInt64ToDouble: out.debug << "Convert int64 to double"; break;
// uint64 -> (u)int*
case EOpConvUint64ToInt8: out.debug << "Convert uint64 to int8_t";break;
case EOpConvUint64ToInt16: out.debug << "Convert uint64 to int16_t";break;
case EOpConvUint64ToInt: out.debug << "Convert uint64 to int"; break;
case EOpConvUint64ToInt64: out.debug << "Convert uint64 to int64"; break;
case EOpConvUint64ToUint8: out.debug << "Convert uint64 to uint8_t";break;
case EOpConvUint64ToUint16: out.debug << "Convert uint64 to uint16"; break;
case EOpConvUint64ToUint: out.debug << "Convert uint64 to uint"; break;
// uint64 -> float*
case EOpConvUint64ToFloat16: out.debug << "Convert uint64 to float16_t";break;
case EOpConvUint64ToFloat: out.debug << "Convert uint64 to float"; break;
case EOpConvUint64ToDouble: out.debug << "Convert uint64 to double"; break;
// float16_t -> int*
case EOpConvFloat16ToInt8: out.debug << "Convert float16_t to int8_t"; break;
case EOpConvFloat16ToInt16: out.debug << "Convert float16_t to int16_t"; break;
case EOpConvFloat16ToInt: out.debug << "Convert float16_t to int"; break;
case EOpConvFloat16ToInt64: out.debug << "Convert float16_t to int64"; break;
// float16_t -> uint*
case EOpConvFloat16ToUint8: out.debug << "Convert float16_t to uint8_t"; break;
case EOpConvFloat16ToUint16: out.debug << "Convert float16_t to uint16_t"; break;
case EOpConvFloat16ToUint: out.debug << "Convert float16_t to uint"; break;
case EOpConvFloat16ToUint64: out.debug << "Convert float16_t to uint64"; break;
// float16_t -> float*
case EOpConvFloat16ToFloat: out.debug << "Convert float16_t to float"; break;
case EOpConvFloat16ToDouble: out.debug << "Convert float16_t to double"; break;
// float32 -> float*
case EOpConvFloatToFloat16: out.debug << "Convert float to float16_t"; break;
case EOpConvFloatToDouble: out.debug << "Convert float to double"; break;
// float32_t -> int*
case EOpConvFloatToInt8: out.debug << "Convert float to int8_t"; break;
case EOpConvFloatToInt16: out.debug << "Convert float to int16_t"; break;
case EOpConvFloatToInt: out.debug << "Convert float to int"; break;
case EOpConvFloatToInt64: out.debug << "Convert float to int64"; break;
// float32_t -> uint*
case EOpConvFloatToUint8: out.debug << "Convert float to uint8_t"; break;
case EOpConvFloatToUint16: out.debug << "Convert float to uint16_t"; break;
case EOpConvFloatToUint: out.debug << "Convert float to uint"; break;
case EOpConvFloatToUint64: out.debug << "Convert float to uint64"; break;
// double -> float*
case EOpConvDoubleToFloat16: out.debug << "Convert double to float16_t"; break;
case EOpConvDoubleToFloat: out.debug << "Convert double to float"; break;
// double -> int*
case EOpConvDoubleToInt8: out.debug << "Convert double to int8_t"; break;
case EOpConvDoubleToInt16: out.debug << "Convert double to int16_t"; break;
case EOpConvDoubleToInt: out.debug << "Convert double to int"; break;
case EOpConvDoubleToInt64: out.debug << "Convert double to int64"; break;
// float32_t -> uint*
case EOpConvDoubleToUint8: out.debug << "Convert double to uint8_t"; break;
case EOpConvDoubleToUint16: out.debug << "Convert double to uint16_t"; break;
case EOpConvDoubleToUint: out.debug << "Convert double to uint"; break;
case EOpConvDoubleToUint64: out.debug << "Convert double to uint64"; break;
case EOpConvUint64ToPtr: out.debug << "Convert uint64_t to pointer"; break;
case EOpConvPtrToUint64: out.debug << "Convert pointer to uint64_t"; break;
@ -673,6 +495,17 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
case EOpSpirvInst: out.debug << "spirv_instruction"; break;
case EOpCreateTensorLayoutNV: out.debug << "createTensorLayoutNV"; break;
case EOpTensorLayoutSetBlockSizeNV: out.debug << "setTensorLayoutBlockSizeNV"; break;
case EOpTensorLayoutSetDimensionNV: out.debug << "setTensorLayoutDimensionNV"; break;
case EOpTensorLayoutSetStrideNV: out.debug << "setTensorLayoutStrideNV"; break;
case EOpTensorLayoutSliceNV: out.debug << "sliceTensorLayoutNV"; break;
case EOpTensorLayoutSetClampValueNV: out.debug << "setTensorLayoutClampValueNV"; break;
case EOpCreateTensorViewNV: out.debug << "createTensorViewNV"; break;
case EOpTensorViewSetDimensionNV: out.debug << "setTensorViewDimensionsNV"; break;
case EOpTensorViewSetStrideNV: out.debug << "setTensorViewStrideNV"; break;
case EOpTensorViewSetClipNV: out.debug << "setTensorViewClipNV"; break;
default: out.debug.message(EPrefixError, "Bad unary op");
}
@ -793,6 +626,18 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node
case EOpConstructBMat4x2: out.debug << "Construct bmat4x2"; break;
case EOpConstructBMat4x3: out.debug << "Construct bmat4x3"; break;
case EOpConstructBMat4x4: out.debug << "Construct bmat4"; break;
case EOpConstructBFloat16: out.debug << "Construct bfloat16_t"; break;
case EOpConstructBF16Vec2: out.debug << "Construct bf16vec2"; break;
case EOpConstructBF16Vec3: out.debug << "Construct bf16vec3"; break;
case EOpConstructBF16Vec4: out.debug << "Construct bf16vec4"; break;
case EOpConstructFloatE5M2: out.debug << "Construct floate5m2_t"; break;
case EOpConstructFloatE5M2Vec2: out.debug << "Construct fe5m2vec2"; break;
case EOpConstructFloatE5M2Vec3: out.debug << "Construct fe5m2vec3"; break;
case EOpConstructFloatE5M2Vec4: out.debug << "Construct fe5m2vec4"; break;
case EOpConstructFloatE4M3: out.debug << "Construct floate4m3_t"; break;
case EOpConstructFloatE4M3Vec2: out.debug << "Construct fe4m3vec2"; break;
case EOpConstructFloatE4M3Vec3: out.debug << "Construct fe4m3vec3"; break;
case EOpConstructFloatE4M3Vec4: out.debug << "Construct fe4m3vec4"; break;
case EOpConstructFloat16: out.debug << "Construct float16_t"; break;
case EOpConstructF16Vec2: out.debug << "Construct f16vec2"; break;
case EOpConstructF16Vec3: out.debug << "Construct f16vec3"; break;
@ -811,8 +656,14 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node
case EOpConstructReference: out.debug << "Construct reference"; break;
case EOpConstructCooperativeMatrixNV: out.debug << "Construct cooperative matrix NV"; break;
case EOpConstructCooperativeMatrixKHR: out.debug << "Construct cooperative matrix KHR"; break;
case EOpConstructCooperativeVectorNV: out.debug << "Construct cooperative vector NV"; break;
case EOpConstructAccStruct: out.debug << "Construct acceleration structure"; break;
case EOpBitCastArrayQCOM: out.debug << "Bitcast To Array QCOM"; break;
case EOpExtractSubArrayQCOM: out.debug << "Extract Subarray QCOM"; break;
case EOpCompositeConstructCoopMatQCOM: out.debug << "Construct Cooperative Matrix QCOM"; break;
case EOpCompositeExtractCoopMatQCOM: out.debug << "Extract Cooperative Matrix QCOM"; break;
case EOpLessThan: out.debug << "Compare Less Than"; break;
case EOpGreaterThan: out.debug << "Compare Greater Than"; break;
case EOpLessThanEqual: out.debug << "Compare Less Than or Equal"; break;
@ -835,6 +686,9 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node
case EOpDistance: out.debug << "distance"; break;
case EOpDot: out.debug << "dot-product"; break;
case EOpDotPackedEXT: out.debug << "dot-product-packed";break;
case EOpDotAccSatEXT: out.debug << "dot-product-accumulate-saturate";break;
case EOpDotPackedAccSatEXT: out.debug << "dot-product-packed-accumulate-saturate";break;
case EOpCross: out.debug << "cross-product"; break;
case EOpFaceForward: out.debug << "face-forward"; break;
case EOpReflect: out.debug << "reflect"; break;
@ -1107,13 +961,37 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node
case EOpRayQueryGetIntersectionObjectToWorld: out.debug << "rayQueryGetIntersectionObjectToWorldEXT"; break;
case EOpRayQueryGetIntersectionWorldToObject: out.debug << "rayQueryGetIntersectionWorldToObjectEXT"; break;
case EOpRayQueryGetIntersectionTriangleVertexPositionsEXT: out.debug << "rayQueryGetIntersectionTriangleVertexPositionsEXT"; break;
case EOpRayQueryGetIntersectionClusterIdNV: out.debug << "rayQueryGetIntersectionClusterIdNV"; break;
case EOpRayQueryGetIntersectionSpherePositionNV: out.debug << "rayQueryGetIntersectionSpherePositionNV"; break;
case EOpRayQueryGetIntersectionSphereRadiusNV: out.debug << "rayQueryGetIntersectionSphereRadiusNV"; break;
case EOpRayQueryGetIntersectionLSSHitValueNV: out.debug << "rayQueryGetIntersectionLSSHitValueNV"; break;
case EOpRayQueryGetIntersectionLSSPositionsNV: out.debug << "rayQueryGetIntersectionLSSPositionsNV"; break;
case EOpRayQueryGetIntersectionLSSRadiiNV: out.debug << "rayQueryGetIntersectionLSSRadiiNV"; break;
case EOpRayQueryIsSphereHitNV: out.debug << "rayQueryIsSphereHitNV"; break;
case EOpRayQueryIsLSSHitNV: out.debug << "rayQueryIsLSSHitNV"; break;
case EOpCooperativeMatrixLoad: out.debug << "Load cooperative matrix KHR"; break;
case EOpCooperativeMatrixStore: out.debug << "Store cooperative matrix KHR"; break;
case EOpCooperativeMatrixMulAdd: out.debug << "MulAdd cooperative matrices KHR"; break;
case EOpCooperativeMatrixLoadNV: out.debug << "Load cooperative matrix NV"; break;
case EOpCooperativeMatrixStoreNV: out.debug << "Store cooperative matrix NV"; break;
case EOpCooperativeMatrixLoadTensorNV: out.debug << "Load cooperative matrix tensor NV"; break;
case EOpCooperativeMatrixStoreTensorNV: out.debug << "Store cooperative matrix tensor NV"; break;
case EOpCooperativeMatrixMulAddNV: out.debug << "MulAdd cooperative matrices NV"; break;
case EOpCooperativeMatrixReduceNV: out.debug << "Reduce cooperative matrices"; break;
case EOpCooperativeMatrixPerElementOpNV: out.debug << "cooperative matrix per element op"; break;
case EOpCooperativeMatrixTransposeNV: out.debug << "Transpose cooperative matrix"; break;
case EOpCooperativeVectorMatMulNV: out.debug << "Cooperative vector matrix multiply NV"; break;
case EOpCooperativeVectorMatMulAddNV: out.debug << "Cooperative vector matrix multiply add NV"; break;
case EOpCooperativeVectorLoadNV: out.debug << "Load cooperative vector NV"; break;
case EOpCooperativeVectorStoreNV: out.debug << "Store cooperative vector NV"; break;
case EOpCooperativeVectorOuterProductAccumulateNV: out.debug << "Cooperative vector outer product accumulate NV"; break;
case EOpCooperativeVectorReduceSumAccumulateNV: out.debug << "Cooperative vector reduce sum accumulate NV"; break;
case EOpTensorReadARM: out.debug << "Read from tensor"; break;
case EOpTensorWriteARM: out.debug << "Write to tensor"; break;
case EOpTensorSizeARM: out.debug << "Get tensor size"; break;
case EOpIsHelperInvocation: out.debug << "IsHelperInvocation"; break;
case EOpDebugPrintf: out.debug << "Debug printf"; break;
@ -1148,14 +1026,32 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node
case EOpHitObjectGetCurrentTimeNV: out.debug << "HitObjectGetCurrentTimeNV"; break;
case EOpHitObjectGetShaderBindingTableRecordIndexNV: out.debug << "HitObjectGetShaderBindingTableRecordIndexNV"; break;
case EOpHitObjectGetShaderRecordBufferHandleNV: out.debug << "HitObjectReadShaderRecordBufferHandleNV"; break;
case EOpHitObjectGetClusterIdNV: out.debug << "HitObjectGetClusterIdNV"; break;
case EOpReorderThreadNV: out.debug << "ReorderThreadNV"; break;
case EOpFetchMicroTriangleVertexPositionNV: out.debug << "MicroTriangleVertexPositionNV"; break;
case EOpFetchMicroTriangleVertexBarycentricNV: out.debug << "MicroTriangleVertexBarycentricNV"; break;
case EOpHitObjectGetSpherePositionNV: out.debug << "HitObjectGetSpherePositionNV"; break;
case EOpHitObjectGetSphereRadiusNV: out.debug << "HitObjectGetSphereRadiusNV"; break;
case EOpHitObjectGetLSSPositionsNV: out.debug << "HitObjectGetLSSPositionsNV"; break;
case EOpHitObjectGetLSSRadiiNV: out.debug << "HitObjectGetLSSRadiiNV"; break;
case EOpHitObjectIsSphereHitNV: out.debug << "HitObjectIsSphereHitNV"; break;
case EOpHitObjectIsLSSHitNV: out.debug << "HitObjectIsLSSHitNV"; break;
case EOpSpirvInst: out.debug << "spirv_instruction"; break;
case EOpStencilAttachmentReadEXT: out.debug << "stencilAttachmentReadEXT"; break;
case EOpDepthAttachmentReadEXT: out.debug << "depthAttachmentReadEXT"; break;
case EOpCreateTensorLayoutNV: out.debug << "createTensorLayout"; break;
case EOpTensorLayoutSetBlockSizeNV: out.debug << "setBlockSize"; break;
case EOpTensorLayoutSetDimensionNV: out.debug << "setDimension"; break;
case EOpTensorLayoutSetStrideNV: out.debug << "setStride"; break;
case EOpTensorLayoutSliceNV: out.debug << "slice"; break;
case EOpTensorLayoutSetClampValueNV: out.debug << "setClampValue"; break;
case EOpCreateTensorViewNV: out.debug << "createTensorView"; break;
case EOpTensorViewSetDimensionNV: out.debug << "setTensorViewDimensions"; break;
case EOpTensorViewSetStrideNV: out.debug << "setTensorViewStride"; break;
case EOpTensorViewSetClipNV: out.debug << "clipTensorView"; break;
default: out.debug.message(EPrefixError, "Bad aggregation op");
}
@ -1285,6 +1181,9 @@ static void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const
case EbtFloat:
case EbtDouble:
case EbtFloat16:
case EbtBFloat16:
case EbtFloatE5M2:
case EbtFloatE4M3:
OutputDouble(out, constUnion[i].getDConst(), extra);
out.debug << "\n";
break;
@ -1501,6 +1400,16 @@ bool TOutputTraverser::visitSwitch(TVisit /* visit */, TIntermSwitch* node)
return false;
}
bool TOutputTraverser::visitVariableDecl(TVisit /* visit */, TIntermVariableDecl* node)
{
TInfoSink& out = infoSink;
OutputTreeText(out, node, depth);
out.debug << "VarDecl: " << node->getDeclSymbol()->getName() << '\n';
return true;
}
//
// This function is the one to call externally to start the traversal.
// Individual functions can be initialized to 0 to skip processing of that
@ -1568,6 +1477,8 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree)
infoSink.debug << "using non_coherent_depth_attachment_readEXT\n";
if (nonCoherentStencilAttachmentReadEXT)
infoSink.debug << "using non_coherent_stencil_attachment_readEXT\n";
if (nonCoherentTileAttachmentReadQCOM)
infoSink.debug << "using non_coherent_attachment_readQCOM\n";
if (depthLayout != EldNone)
infoSink.debug << "using " << TQualifier::getLayoutDepthString(depthLayout) << "\n";
if (blendEquations != 0) {
@ -1602,6 +1513,13 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree)
localSizeSpecId[2] << ")\n";
}
}
if (nonCoherentTileAttachmentReadQCOM)
infoSink.debug << "using non_coherent_attachment_readQCOM\n";
if (isTileShadingRateQCOMSet()) {
infoSink.debug << "shading_rateQCOM = (" << tileShadingRateQCOM[0] << ", "
<< tileShadingRateQCOM[1] << ", "
<< tileShadingRateQCOM[2] << ")\n";
}
break;
default:

View file

@ -39,6 +39,7 @@
#include "gl_types.h"
#include "iomapper.h"
#include "LiveTraverser.h"
#include "SymbolTable.h"
//
@ -60,10 +61,112 @@
namespace glslang {
struct TVarEntryInfo {
long long id;
TIntermSymbol* symbol;
bool live;
TLayoutPacking upgradedToPushConstantPacking; // ElpNone means it hasn't been upgraded
int newBinding;
int newSet;
int newLocation;
int newComponent;
int newIndex;
EShLanguage stage;
void clearNewAssignments() {
upgradedToPushConstantPacking = ElpNone;
newBinding = -1;
newSet = -1;
newLocation = -1;
newComponent = -1;
newIndex = -1;
}
struct TOrderById {
inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r) { return l.id < r.id; }
};
struct TOrderByPriority {
// ordering:
// 1) has both binding and set
// 2) has binding but no set
// 3) has no binding but set
// 4) has no binding and no set
inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r) {
const TQualifier& lq = l.symbol->getQualifier();
const TQualifier& rq = r.symbol->getQualifier();
// simple rules:
// has binding gives 2 points
// has set gives 1 point
// who has the most points is more important.
int lPoints = (lq.hasBinding() ? 2 : 0) + (lq.hasSet() ? 1 : 0);
int rPoints = (rq.hasBinding() ? 2 : 0) + (rq.hasSet() ? 1 : 0);
if (lPoints == rPoints)
return l.id < r.id;
return lPoints > rPoints;
}
};
struct TOrderByPriorityAndLive {
// ordering:
// 1) do live variables first
// 2) has both binding and set
// 3) has binding but no set
// 4) has no binding but set
// 5) has no binding and no set
inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r) {
const TQualifier& lq = l.symbol->getQualifier();
const TQualifier& rq = r.symbol->getQualifier();
// simple rules:
// has binding gives 2 points
// has set gives 1 point
// who has the most points is more important.
int lPoints = (lq.hasBinding() ? 2 : 0) + (lq.hasSet() ? 1 : 0);
int rPoints = (rq.hasBinding() ? 2 : 0) + (rq.hasSet() ? 1 : 0);
if (l.live != r.live)
return l.live > r.live;
if (lPoints != rPoints)
return lPoints > rPoints;
return l.id < r.id;
}
};
};
// override function "operator=", if a vector<const _Kty, _Ty> being sort,
// when use vc++, the sort function will call :
// pair& operator=(const pair<_Other1, _Other2>& _Right)
// {
// first = _Right.first;
// second = _Right.second;
// return (*this);
// }
// that will make a const type handing on left.
// override this function can avoid a compiler error.
// In the future, if the vc++ compiler can handle such a situation,
// this part of the code will be removed.
struct TVarLivePair : std::pair<const TString, TVarEntryInfo> {
TVarLivePair(const std::pair<const TString, TVarEntryInfo>& _Right) : pair(_Right.first, _Right.second) {}
TVarLivePair& operator=(const TVarLivePair& _Right) {
const_cast<TString&>(first) = _Right.first;
second = _Right.second;
return (*this);
}
TVarLivePair(const TVarLivePair& src) : pair(src) { }
};
typedef std::vector<TVarLivePair> TVarLiveVector;
class TVarGatherTraverser : public TLiveTraverser {
public:
TVarGatherTraverser(const TIntermediate& i, bool traverseDeadCode, TVarLiveMap& inList, TVarLiveMap& outList, TVarLiveMap& uniformList)
: TLiveTraverser(i, traverseDeadCode, true, true, false)
: TLiveTraverser(i, traverseDeadCode, true, true, false, false)
, inputList(inList)
, outputList(outList)
, uniformList(uniformList)
@ -106,7 +209,7 @@ class TVarSetTraverser : public TLiveTraverser
{
public:
TVarSetTraverser(const TIntermediate& i, const TVarLiveMap& inList, const TVarLiveMap& outList, const TVarLiveMap& uniformList)
: TLiveTraverser(i, true, true, true, false)
: TLiveTraverser(i, true, true, true, false, true)
, inputList(inList)
, outputList(outList)
, uniformList(uniformList)
@ -143,8 +246,11 @@ public:
base->getWritableType().getQualifier().layoutComponent = at->second.newComponent;
if (at->second.newIndex != -1)
base->getWritableType().getQualifier().layoutIndex = at->second.newIndex;
if (at->second.upgradedToPushConstant)
if (at->second.upgradedToPushConstantPacking != ElpNone) {
base->getWritableType().getQualifier().layoutPushConstant = true;
base->getWritableType().getQualifier().setBlockStorage(EbsPushConstant);
base->getWritableType().getQualifier().layoutPacking = at->second.upgradedToPushConstantPacking;
}
}
private:
@ -176,7 +282,7 @@ struct TNotifyInOutAdaptor
{
EShLanguage stage;
TIoMapResolver& resolver;
inline TNotifyInOutAdaptor(EShLanguage s, TIoMapResolver& r)
inline TNotifyInOutAdaptor(EShLanguage s, TIoMapResolver& r)
: stage(s)
, resolver(r)
{
@ -913,6 +1019,7 @@ uint32_t TDefaultIoResolverBase::computeTypeLocationSize(const TType& type, EShL
//TDefaultGlslIoResolver
TResourceType TDefaultGlslIoResolver::getResourceType(const glslang::TType& type) {
assert(isValidGlslType(type));
if (isImageType(type)) {
return EResImage;
}
@ -928,6 +1035,15 @@ TResourceType TDefaultGlslIoResolver::getResourceType(const glslang::TType& type
if (isUboType(type)) {
return EResUbo;
}
if (isCombinedSamplerType(type)) {
return EResCombinedSampler;
}
if (isAsType(type)) {
return EResAs;
}
if (isTensorType(type)) {
return EResTensor;
}
return EResCount;
}
@ -1277,6 +1393,7 @@ struct TDefaultIoResolver : public TDefaultIoResolverBase {
bool validateBinding(EShLanguage /*stage*/, TVarEntryInfo& /*ent*/) override { return true; }
TResourceType getResourceType(const glslang::TType& type) override {
assert(isValidGlslType(type));
if (isImageType(type)) {
return EResImage;
}
@ -1292,6 +1409,15 @@ struct TDefaultIoResolver : public TDefaultIoResolverBase {
if (isUboType(type)) {
return EResUbo;
}
if (isCombinedSamplerType(type)) {
return EResCombinedSampler;
}
if (isAsType(type)) {
return EResAs;
}
if (isTensorType(type)) {
return EResTensor;
}
return EResCount;
}
@ -1377,6 +1503,11 @@ struct TDefaultHlslIoResolver : public TDefaultIoResolverBase {
if (isUboType(type)) {
return EResUbo;
}
// no support for combined samplers in HLSL
if (isAsType(type)) {
return EResAs;
}
// no support for tensors in HLSL
return EResCount;
}
@ -1497,6 +1628,36 @@ bool TIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSi
return !hadError;
}
TGlslIoMapper::TGlslIoMapper() {
memset(inVarMaps, 0, sizeof(TVarLiveMap*) * EShLangCount);
memset(outVarMaps, 0, sizeof(TVarLiveMap*) * EShLangCount);
memset(uniformVarMap, 0, sizeof(TVarLiveMap*) * EShLangCount);
memset(intermediates, 0, sizeof(TIntermediate*) * EShLangCount);
profile = ENoProfile;
version = 0;
autoPushConstantMaxSize = 128;
autoPushConstantBlockPacking = ElpStd430;
}
TGlslIoMapper::~TGlslIoMapper() {
for (size_t stage = 0; stage < EShLangCount; stage++) {
if (inVarMaps[stage] != nullptr) {
delete inVarMaps[stage];
inVarMaps[stage] = nullptr;
}
if (outVarMaps[stage] != nullptr) {
delete outVarMaps[stage];
outVarMaps[stage] = nullptr;
}
if (uniformVarMap[stage] != nullptr) {
delete uniformVarMap[stage];
uniformVarMap[stage] = nullptr;
}
if (intermediates[stage] != nullptr)
intermediates[stage] = nullptr;
}
}
// Map I/O variables to provided offsets, and make bindings for
// unbound but live variables.
//
@ -1677,7 +1838,8 @@ bool TGlslIoMapper::doMap(TIoMapResolver* resolver, TInfoSink& infoSink) {
std::for_each(uniformVector.begin(), uniformVector.end(),
[this](TVarLivePair& p) {
if (p.first == autoPushConstantBlockName) {
p.second.upgradedToPushConstant = true;
p.second.upgradedToPushConstantPacking = autoPushConstantBlockPacking;
p.second.newSet = TQualifier::layoutSetEnd;
}
});
}
@ -1690,8 +1852,8 @@ bool TGlslIoMapper::doMap(TIoMapResolver* resolver, TInfoSink& infoSink) {
std::for_each(uniformVector.begin(), uniformVector.end(), [pUniformVarMap, stage](TVarLivePair p) {
auto at = pUniformVarMap[stage]->find(p.second.symbol->getAccessName());
if (at != pUniformVarMap[stage]->end() && at->second.id == p.second.id){
if (p.second.upgradedToPushConstant) {
at->second.upgradedToPushConstant = true;
if (p.second.upgradedToPushConstantPacking != ElpNone) {
at->second.upgradedToPushConstantPacking = p.second.upgradedToPushConstantPacking;
} else {
int resolvedBinding = at->second.newBinding;
at->second = p.second;

View file

@ -37,7 +37,6 @@
#define _IOMAPPER_INCLUDED
#include <cstdint>
#include "LiveTraverser.h"
#include <unordered_map>
#include <unordered_set>
//
@ -49,84 +48,7 @@ class TInfoSink;
namespace glslang {
class TIntermediate;
struct TVarEntryInfo {
long long id;
TIntermSymbol* symbol;
bool live;
bool upgradedToPushConstant;
int newBinding;
int newSet;
int newLocation;
int newComponent;
int newIndex;
EShLanguage stage;
void clearNewAssignments() {
upgradedToPushConstant = false;
newBinding = -1;
newSet = -1;
newLocation = -1;
newComponent = -1;
newIndex = -1;
}
struct TOrderById {
inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r) { return l.id < r.id; }
};
struct TOrderByPriority {
// ordering:
// 1) has both binding and set
// 2) has binding but no set
// 3) has no binding but set
// 4) has no binding and no set
inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r) {
const TQualifier& lq = l.symbol->getQualifier();
const TQualifier& rq = r.symbol->getQualifier();
// simple rules:
// has binding gives 2 points
// has set gives 1 point
// who has the most points is more important.
int lPoints = (lq.hasBinding() ? 2 : 0) + (lq.hasSet() ? 1 : 0);
int rPoints = (rq.hasBinding() ? 2 : 0) + (rq.hasSet() ? 1 : 0);
if (lPoints == rPoints)
return l.id < r.id;
return lPoints > rPoints;
}
};
struct TOrderByPriorityAndLive {
// ordering:
// 1) do live variables first
// 2) has both binding and set
// 3) has binding but no set
// 4) has no binding but set
// 5) has no binding and no set
inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r) {
const TQualifier& lq = l.symbol->getQualifier();
const TQualifier& rq = r.symbol->getQualifier();
// simple rules:
// has binding gives 2 points
// has set gives 1 point
// who has the most points is more important.
int lPoints = (lq.hasBinding() ? 2 : 0) + (lq.hasSet() ? 1 : 0);
int rPoints = (rq.hasBinding() ? 2 : 0) + (rq.hasSet() ? 1 : 0);
if (l.live != r.live)
return l.live > r.live;
if (lPoints != rPoints)
return lPoints > rPoints;
return l.id < r.id;
}
};
};
struct TVarEntryInfo;
// Base class for shared TIoMapResolver services, used by several derivations.
struct TDefaultIoResolverBase : public glslang::TIoMapResolver {
public:
@ -198,12 +120,12 @@ protected:
}
static bool isTextureType(const glslang::TType& type) {
return (type.getBasicType() == glslang::EbtSampler &&
return (type.getBasicType() == glslang::EbtSampler && !type.getSampler().isCombined() &&
(type.getSampler().isTexture() || type.getSampler().isSubpass()));
}
static bool isUboType(const glslang::TType& type) {
return type.getQualifier().storage == EvqUniform;
return type.getQualifier().storage == EvqUniform && type.isStruct();
}
static bool isImageType(const glslang::TType& type) {
@ -214,6 +136,24 @@ protected:
return type.getQualifier().storage == EvqBuffer;
}
static bool isCombinedSamplerType(const glslang::TType& type) {
return type.getBasicType() == glslang::EbtSampler && type.getSampler().isCombined();
}
static bool isAsType(const glslang::TType& type) {
return type.getBasicType() == glslang::EbtAccStruct;
}
static bool isTensorType(const glslang::TType& type) {
return type.isTensorARM();
}
static bool isValidGlslType(const glslang::TType& type) {
// at most one must be true
return (isSamplerType(type) + isTextureType(type) + isUboType(type) + isImageType(type) +
isSsboType(type) + isCombinedSamplerType(type) + isAsType(type) + isTensorType(type)) <= 1;
}
// Return true if this is a SRV (shader resource view) type:
static bool isSrvType(const glslang::TType& type) {
return isTextureType(type) || type.getQualifier().storage == EvqBuffer;
@ -267,82 +207,22 @@ protected:
typedef std::map<TString, TVarEntryInfo> TVarLiveMap;
// override function "operator=", if a vector<const _Kty, _Ty> being sort,
// when use vc++, the sort function will call :
// pair& operator=(const pair<_Other1, _Other2>& _Right)
// {
// first = _Right.first;
// second = _Right.second;
// return (*this);
// }
// that will make a const type handing on left.
// override this function can avoid a compiler error.
// In the future, if the vc++ compiler can handle such a situation,
// this part of the code will be removed.
struct TVarLivePair : std::pair<const TString, TVarEntryInfo> {
TVarLivePair(const std::pair<const TString, TVarEntryInfo>& _Right) : pair(_Right.first, _Right.second) {}
TVarLivePair& operator=(const TVarLivePair& _Right) {
const_cast<TString&>(first) = _Right.first;
second = _Right.second;
return (*this);
}
TVarLivePair(const TVarLivePair& src) : pair(src) { }
};
typedef std::vector<TVarLivePair> TVarLiveVector;
// I/O mapper
class TIoMapper {
public:
TIoMapper() {}
virtual ~TIoMapper() {}
// grow the reflection stage by stage
bool virtual addStage(EShLanguage, TIntermediate&, TInfoSink&, TIoMapResolver*);
bool virtual doMap(TIoMapResolver*, TInfoSink&) { return true; }
};
// I/O mapper for GLSL
class TGlslIoMapper : public TIoMapper {
public:
TGlslIoMapper() {
memset(inVarMaps, 0, sizeof(TVarLiveMap*) * (EShLangCount + 1));
memset(outVarMaps, 0, sizeof(TVarLiveMap*) * (EShLangCount + 1));
memset(uniformVarMap, 0, sizeof(TVarLiveMap*) * (EShLangCount + 1));
memset(intermediates, 0, sizeof(TIntermediate*) * (EShLangCount + 1));
profile = ENoProfile;
version = 0;
autoPushConstantMaxSize = 128;
autoPushConstantBlockPacking = ElpStd430;
}
virtual ~TGlslIoMapper() {
for (size_t stage = 0; stage < EShLangCount; stage++) {
if (inVarMaps[stage] != nullptr) {
delete inVarMaps[stage];
inVarMaps[stage] = nullptr;
}
if (outVarMaps[stage] != nullptr) {
delete outVarMaps[stage];
outVarMaps[stage] = nullptr;
}
if (uniformVarMap[stage] != nullptr) {
delete uniformVarMap[stage];
uniformVarMap[stage] = nullptr;
}
if (intermediates[stage] != nullptr)
intermediates[stage] = nullptr;
}
}
TGlslIoMapper();
virtual ~TGlslIoMapper();
// If set, the uniform block with the given name will be changed to be backed by
// push_constant if it's size is <= maxSize
void setAutoPushConstantBlock(const char* name, unsigned int maxSize, TLayoutPacking packing) {
bool setAutoPushConstantBlock(const char* name, unsigned int maxSize, TLayoutPacking packing) override {
autoPushConstantBlockName = name;
autoPushConstantMaxSize = maxSize;
autoPushConstantBlockPacking = packing;
return true;
}
// grow the reflection stage by stage
bool addStage(EShLanguage, TIntermediate&, TInfoSink&, TIoMapResolver*) override;
bool doMap(TIoMapResolver*, TInfoSink&) override;
TVarLiveMap *inVarMaps[EShLangCount], *outVarMaps[EShLangCount],
*uniformVarMap[EShLangCount];
TIntermediate* intermediates[EShLangCount];
bool hadError = false;
EProfile profile;
@ -352,6 +232,8 @@ private:
TString autoPushConstantBlockName;
unsigned int autoPushConstantMaxSize;
TLayoutPacking autoPushConstantBlockPacking;
TVarLiveMap *inVarMaps[EShLangCount], *outVarMaps[EShLangCount],
*uniformVarMap[EShLangCount];
};
} // end namespace glslang

View file

@ -46,34 +46,46 @@
// even if no merging was done (i.e., the stage was only one compilation unit).
//
#include "glslang/Public/ShaderLang.h"
#include "localintermediate.h"
#include "../Include/InfoSink.h"
#include "SymbolTable.h"
#include "LiveTraverser.h"
namespace glslang {
//
// Link-time error emitter.
//
void TIntermediate::error(TInfoSink& infoSink, const char* message, EShLanguage unitStage)
void TIntermediate::error(TInfoSink& infoSink, const TSourceLoc* loc, EShMessages messages, const char* message,
EShLanguage unitStage)
{
infoSink.info.prefix(EPrefixError);
if (unitStage < EShLangCount)
infoSink.info << "Linking " << StageName(getStage()) << " and " << StageName(unitStage) << " stages: " << message << "\n";
else
if (loc)
infoSink.info.location(*loc, messages & EShMsgAbsolutePath, messages & EShMsgDisplayErrorColumn);
if (unitStage == EShLangCount)
infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n";
else if (language == EShLangCount)
infoSink.info << "Linking " << StageName(unitStage) << " stage: " << message << "\n";
else
infoSink.info << "Linking " << StageName(language) << " and " << StageName(unitStage) << " stages: " << message << "\n";
++numErrors;
}
// Link-time warning.
void TIntermediate::warn(TInfoSink& infoSink, const char* message, EShLanguage unitStage)
void TIntermediate::warn(TInfoSink& infoSink, const TSourceLoc* loc, EShMessages messages, const char* message,
EShLanguage unitStage)
{
infoSink.info.prefix(EPrefixWarning);
if (unitStage < EShLangCount)
infoSink.info << "Linking " << StageName(language) << " and " << StageName(unitStage) << " stages: " << message << "\n";
else
if (loc)
infoSink.info.location(*loc, messages & EShMsgAbsolutePath, messages & EShMsgDisplayErrorColumn);
if (unitStage == EShLangCount)
infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n";
else if (language == EShLangCount)
infoSink.info << "Linking " << StageName(unitStage) << " stage: " << message << "\n";
else
infoSink.info << "Linking " << StageName(language) << " and " << StageName(unitStage) << " stages: " << message << "\n";
}
// TODO: 4.4 offset/align: "Two blocks linked together in the same program with the same block
@ -113,10 +125,67 @@ void TIntermediate::mergeUniformObjects(TInfoSink& infoSink, TIntermediate& unit
mergeLinkerObjects(infoSink, linkerObjects, unitLinkerObjects, unit.getStage());
}
static inline bool isSameInterface(TIntermSymbol* symbol, TIntermSymbol* unitSymbol) {
EShLanguage stage = symbol->getStage();
EShLanguage unitStage = unitSymbol->getStage();
return // 1) same stage and same shader interface
(stage == unitStage && symbol->getType().getShaderInterface() == unitSymbol->getType().getShaderInterface()) ||
// 2) accross stages and both are uniform or buffer
(symbol->getQualifier().storage == EvqUniform && unitSymbol->getQualifier().storage == EvqUniform) ||
(symbol->getQualifier().storage == EvqBuffer && unitSymbol->getQualifier().storage == EvqBuffer) ||
// 3) in/out matched across stage boundary
(stage < unitStage && symbol->getQualifier().storage == EvqVaryingOut && unitSymbol->getQualifier().storage == EvqVaryingIn) ||
(unitStage < stage && symbol->getQualifier().storage == EvqVaryingIn && unitSymbol->getQualifier().storage == EvqVaryingOut);
}
static bool isSameSymbol(TIntermSymbol* symbol1, TIntermSymbol* symbol2) {
// If they are both blocks in the same shader interface,
// match by the block-name, not the identifier name.
if (symbol1->getType().getBasicType() == EbtBlock && symbol2->getType().getBasicType() == EbtBlock) {
if (isSameInterface(symbol1, symbol2)) {
return symbol1->getType().getTypeName() == symbol2->getType().getTypeName();
}
} else if (symbol1->getName() == symbol2->getName())
return true;
return false;
}
//
// merge implicit array sizes for uniform/buffer objects
//
void TIntermediate::mergeImplicitArraySizes(TInfoSink&, TIntermediate& unit) {
if (unit.treeRoot == nullptr || treeRoot == nullptr)
return;
// Get the linker-object lists
TIntermSequence& linkerObjects = findLinkerObjects()->getSequence();
TIntermSequence unitLinkerObjects = unit.findLinkerObjects()->getSequence();
// filter unitLinkerObjects to only contain uniforms
auto end = std::remove_if(unitLinkerObjects.begin(), unitLinkerObjects.end(),
[](TIntermNode* node) {return node->getAsSymbolNode()->getQualifier().storage != EvqUniform &&
node->getAsSymbolNode()->getQualifier().storage != EvqBuffer; });
unitLinkerObjects.resize(end - unitLinkerObjects.begin());
std::size_t initialNumLinkerObjects = linkerObjects.size();
for (unsigned int unitLinkObj = 0; unitLinkObj < unitLinkerObjects.size(); ++unitLinkObj) {
for (std::size_t linkObj = 0; linkObj < initialNumLinkerObjects; ++linkObj) {
TIntermSymbol* symbol = linkerObjects[linkObj]->getAsSymbolNode();
TIntermSymbol* unitSymbol = unitLinkerObjects[unitLinkObj]->getAsSymbolNode();
assert(symbol && unitSymbol);
if (isSameSymbol(symbol, unitSymbol)) {
// Update implicit array sizes
mergeImplicitArraySizes(symbol->getWritableType(), unitSymbol->getType());
}
}
}
}
//
// do error checking on the shader boundary in / out vars
//
void TIntermediate::checkStageIO(TInfoSink& infoSink, TIntermediate& unit) {
void TIntermediate::checkStageIO(TInfoSink& infoSink, TIntermediate& unit, EShMessages messages) {
if (unit.treeRoot == nullptr || treeRoot == nullptr)
return;
@ -137,7 +206,272 @@ void TIntermediate::checkStageIO(TInfoSink& infoSink, TIntermediate& unit) {
// do matching and error checking
mergeLinkerObjects(infoSink, linkerObjects, unitLinkerObjects, unit.getStage());
// TODO: final check; make sure that any statically used `in` have matching `out` written to
if ((messages & EShMsgValidateCrossStageIO) == 0)
return;
// The OpenGL Shading Language, Version 4.60.8 (https://registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf)
// 4.3.4 Input Variables
// Only the input variables that are statically read need to be written by the previous stage; it is
// allowed to have superfluous declarations of input variables. This is shown in the following table.
// +------------------------------------------------------------------------------------------------+
// | Treatment of Mismatched Input | Consuming Shader (input variables) |
// | Variables |---------------------------------------------------------|
// | | No | Declared but no | Declared and Static Use |
// | | Declaration | Static Use | |
// |--------------------------------------+-------------+-----------------+-------------------------|
// | Generating Shader | No Declaration | Allowed | Allowed | Link-Time Error |
// | (output variables) |-----------------+-------------+-----------------+-------------------------|
// | | Declared but no | Allowed | Allowed | Allowed (values are |
// | | Static Use | | | undefined) |
// | |-----------------+-------------+-----------------+-------------------------|
// | | Declared and | Allowed | Allowed | Allowed (values are |
// | | Static Use | | | potentially undefined) |
// +------------------------------------------------------------------------------------------------+
// Consumption errors are based on static use only. Compilation may generate a warning, but not an
// error, for any dynamic use the compiler can deduce that might cause consumption of undefined values.
// TODO: implement support for geometry passthrough
if (getGeoPassthroughEXT()) {
unit.warn(infoSink, "GL_NV_geometry_shader_passthrough is enabled, skipping cross-stage IO validation",
getStage());
return;
}
class TIOTraverser : public TLiveTraverser {
public:
TIOTraverser(TIntermediate& i, bool all, TIntermSequence& sequence, TStorageQualifier storage)
: TLiveTraverser(i, all, true, false, false), sequence(sequence), storage(storage)
{
}
virtual void visitSymbol(TIntermSymbol* symbol)
{
if (symbol->getQualifier().storage == storage)
sequence.push_back(symbol);
}
private:
TIntermSequence& sequence;
TStorageQualifier storage;
};
// live symbols only
TIntermSequence unitLiveInputs;
TIOTraverser unitTraverser(unit, false, unitLiveInputs, EvqVaryingIn);
unitTraverser.pushFunction(unit.getEntryPointMangledName().c_str());
while (! unitTraverser.destinations.empty()) {
TIntermNode* destination = unitTraverser.destinations.back();
unitTraverser.destinations.pop_back();
destination->traverse(&unitTraverser);
}
// all symbols
TIntermSequence allOutputs;
TIOTraverser traverser(*this, true, allOutputs, EvqVaryingOut);
getTreeRoot()->traverse(&traverser);
std::unordered_set<int> outputLocations;
for (auto& output : allOutputs) {
if (output->getAsSymbolNode()->getBasicType() == EbtBlock) {
int lastLocation = -1;
if (output->getAsSymbolNode()->getQualifier().hasLocation())
lastLocation = output->getAsSymbolNode()->getQualifier().layoutLocation;
const TTypeList* members = output->getAsSymbolNode()->getType().getStruct();
for (auto& member : *members) {
int location = lastLocation;
if (member.type->getQualifier().hasLocation())
location = member.type->getQualifier().layoutLocation;
if (location != -1) {
int locationSize = TIntermediate::computeTypeLocationSize(*member.type, getStage());
for (int i = 0; i < locationSize; ++i)
outputLocations.insert(location + i);
lastLocation = location + locationSize;
}
}
} else {
int locationSize = TIntermediate::computeTypeLocationSize(output->getAsSymbolNode()->getType(), getStage());
for (int i = 0; i < locationSize; ++i)
outputLocations.insert(output->getAsSymbolNode()->getQualifier().layoutLocation + i);
}
}
// remove unitStage inputs with matching outputs in the current stage
auto liveEnd = std::remove_if(
unitLiveInputs.begin(), unitLiveInputs.end(), [this, &allOutputs, &outputLocations](TIntermNode* input) {
// ignore built-ins
if (input->getAsSymbolNode()->getAccessName().compare(0, 3, "gl_") == 0)
return true;
// try to match by location
if (input->getAsSymbolNode()->getQualifier().hasLocation() &&
outputLocations.find(input->getAsSymbolNode()->getQualifier().layoutLocation) != outputLocations.end())
return true;
if (input->getAsSymbolNode()->getBasicType() == EbtBlock) {
int lastLocation = -1;
if (input->getAsSymbolNode()->getQualifier().hasLocation())
lastLocation = input->getAsSymbolNode()->getQualifier().layoutLocation;
const TTypeList* members = input->getAsSymbolNode()->getType().getStruct();
for (auto& member : *members) {
int location = lastLocation;
if (member.type->getQualifier().hasLocation())
location = member.type->getQualifier().layoutLocation;
if (location != -1) {
int locationSize = TIntermediate::computeTypeLocationSize(*member.type, getStage());
for (int i = 0; i < locationSize; ++i)
if (outputLocations.find(location + i) != outputLocations.end())
return true;
lastLocation = location + locationSize;
}
}
}
// otherwise, try to match by name
return std::any_of(allOutputs.begin(), allOutputs.end(), [input](TIntermNode* output) {
return output->getAsSymbolNode()->getAccessName() == input->getAsSymbolNode()->getAccessName();
});
});
unitLiveInputs.resize(liveEnd - unitLiveInputs.begin());
// check remaining loose unitStage inputs for a matching output block member
liveEnd = std::remove_if(unitLiveInputs.begin(), unitLiveInputs.end(), [&allOutputs](TIntermNode* input) {
return std::any_of(allOutputs.begin(), allOutputs.end(), [input](TIntermNode* output) {
if (output->getAsSymbolNode()->getBasicType() != EbtBlock)
return false;
const TTypeList* members = output->getAsSymbolNode()->getType().getStruct();
return std::any_of(members->begin(), members->end(), [input](TTypeLoc type) {
return type.type->getFieldName() == input->getAsSymbolNode()->getName();
});
});
});
unitLiveInputs.resize(liveEnd - unitLiveInputs.begin());
// finally, check remaining unitStage block inputs for a matching loose output
liveEnd = std::remove_if(
unitLiveInputs.begin(), unitLiveInputs.end(), [&allOutputs](TIntermNode* input) {
if (input->getAsSymbolNode()->getBasicType() != EbtBlock)
return false;
// liveness isn't tracked per member so finding any one live member is the best we can do
const TTypeList* members = input->getAsSymbolNode()->getType().getStruct();
return std::any_of(members->begin(), members->end(), [allOutputs](TTypeLoc type) {
return std::any_of(allOutputs.begin(), allOutputs.end(), [&type](TIntermNode* output) {
return type.type->getFieldName() == output->getAsSymbolNode()->getName();
});
});
});
unitLiveInputs.resize(liveEnd - unitLiveInputs.begin());
// any remaining unitStage inputs have no matching output
std::for_each(unitLiveInputs.begin(), unitLiveInputs.end(), [&](TIntermNode* input) {
unit.error(infoSink, &input->getLoc(), messages,
"Preceding stage has no matching declaration for statically used input:", getStage());
infoSink.info << " "
<< input->getAsSymbolNode()->getType().getCompleteString(
true, true, false, true, input->getAsSymbolNode()->getAccessName())
<< "\n";
});
// TODO: warn about statically read inputs with outputs declared but not written to
}
void TIntermediate::optimizeStageIO(TInfoSink&, TIntermediate& unit)
{
// don't do any input/output demotion on compute, raytracing, or task/mesh stages
// TODO: support task/mesh
if (getStage() > EShLangFragment || unit.getStage() > EShLangFragment) {
return;
}
class TIOTraverser : public TLiveTraverser {
public:
TIOTraverser(TIntermediate& i, bool all, TIntermSequence& sequence, TStorageQualifier storage)
: TLiveTraverser(i, all, true, false, false), sequence(sequence), storage(storage)
{
}
virtual void visitSymbol(TIntermSymbol* symbol)
{
if (symbol->getQualifier().storage == storage) {
sequence.push_back(symbol);
}
}
private:
TIntermSequence& sequence;
TStorageQualifier storage;
};
// live symbols only
TIntermSequence unitLiveInputs;
TIOTraverser unitTraverser(unit, false, unitLiveInputs, EvqVaryingIn);
unitTraverser.pushFunction(unit.getEntryPointMangledName().c_str());
while (! unitTraverser.destinations.empty()) {
TIntermNode* destination = unitTraverser.destinations.back();
unitTraverser.destinations.pop_back();
destination->traverse(&unitTraverser);
}
TIntermSequence allOutputs;
TIntermSequence unitAllInputs;
TIOTraverser allTraverser(*this, true, allOutputs, EvqVaryingOut);
getTreeRoot()->traverse(&allTraverser);
TIOTraverser unitAllTraverser(unit, true, unitAllInputs, EvqVaryingIn);
unit.getTreeRoot()->traverse(&unitAllTraverser);
// find outputs not consumed by the next stage
std::for_each(allOutputs.begin(), allOutputs.end(), [&unitLiveInputs, &unitAllInputs](TIntermNode* output) {
// don't do anything to builtins
if (output->getAsSymbolNode()->getAccessName().compare(0, 3, "gl_") == 0)
return;
// don't demote block outputs (for now)
if (output->getAsSymbolNode()->getBasicType() == EbtBlock)
return;
// check if the (loose) output has a matching loose input
auto isMatchingInput = [output](TIntermNode* input) {
return output->getAsSymbolNode()->getAccessName() == input->getAsSymbolNode()->getAccessName();
};
// check if the (loose) output has a matching block member input
auto isMatchingInputBlockMember = [output](TIntermNode* input) {
// ignore loose inputs
if (input->getAsSymbolNode()->getBasicType() != EbtBlock)
return false;
// don't demote loose outputs with matching input block members
auto isMatchingBlockMember = [output](TTypeLoc type) {
return type.type->getFieldName() == output->getAsSymbolNode()->getName();
};
const TTypeList* members = input->getAsSymbolNode()->getType().getStruct();
return std::any_of(members->begin(), members->end(), isMatchingBlockMember);
};
// determine if the input/output pair should be demoted
// do the faster (and more likely) loose-loose check first
if (std::none_of(unitLiveInputs.begin(), unitLiveInputs.end(), isMatchingInput) &&
std::none_of(unitAllInputs.begin(), unitAllInputs.end(), isMatchingInputBlockMember)) {
// demote any input matching the output
auto demoteMatchingInputs = [output](TIntermNode* input) {
if (output->getAsSymbolNode()->getAccessName() == input->getAsSymbolNode()->getAccessName()) {
// demote input to a plain variable
TIntermSymbol* symbol = input->getAsSymbolNode();
symbol->getQualifier().storage = EvqGlobal;
symbol->getQualifier().clearInterstage();
symbol->getQualifier().clearLayout();
}
};
// demote all matching outputs to a plain variable
TIntermSymbol* symbol = output->getAsSymbolNode();
symbol->getQualifier().storage = EvqGlobal;
symbol->getQualifier().clearInterstage();
symbol->getQualifier().clearLayout();
std::for_each(unitAllInputs.begin(), unitAllInputs.end(), demoteMatchingInputs);
}
});
}
void TIntermediate::mergeCallGraphs(TInfoSink& infoSink, TIntermediate& unit)
@ -201,6 +535,9 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit)
error(infoSink, "number of invocations must match between compilation units");
}
// The GLSL specification requires that at least one compilation unit
// must declare the vertices layout, but not all units need to do so.
// However, all declarations must match.
if (vertices == TQualifier::layoutNotSet)
vertices = unit.vertices;
else if (unit.vertices != TQualifier::layoutNotSet && vertices != unit.vertices) {
@ -211,20 +548,30 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit)
else
assert(0);
}
// The mesh shader extension requires that at least one compilation unit
// must declare the max_primitives layout, but not all units need to do so.
// However, all declarations must match.
if (primitives == TQualifier::layoutNotSet)
primitives = unit.primitives;
else if (primitives != unit.primitives) {
else if (unit.primitives != TQualifier::layoutNotSet && primitives != unit.primitives) {
if (language == EShLangMesh)
error(infoSink, "Contradictory layout max_primitives values");
else
assert(0);
}
// The GLSL specification requires that at least one compilation unit
// must declare the input primitive layout, but not all units need to do so.
// However, all declarations must match.
if (inputPrimitive == ElgNone)
inputPrimitive = unit.inputPrimitive;
else if (unit.inputPrimitive != ElgNone && inputPrimitive != unit.inputPrimitive)
error(infoSink, "Contradictory input layout primitives");
// The GLSL specification requires that at least one compilation unit
// must declare the output primitive layout, but not all units need to do so.
// However, all declarations must match.
if (outputPrimitive == ElgNone)
outputPrimitive = unit.outputPrimitive;
else if (unit.outputPrimitive != ElgNone && outputPrimitive != unit.outputPrimitive)
@ -233,19 +580,27 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit)
if (originUpperLeft != unit.originUpperLeft || pixelCenterInteger != unit.pixelCenterInteger)
error(infoSink, "gl_FragCoord redeclarations must match across shaders");
// The GLSL specification requires that at least one compilation unit
// must declare the vertex spacing layout, but not all units need to do so.
// However, all declarations must match.
if (vertexSpacing == EvsNone)
vertexSpacing = unit.vertexSpacing;
else if (vertexSpacing != unit.vertexSpacing)
else if (unit.vertexSpacing != EvsNone && vertexSpacing != unit.vertexSpacing)
error(infoSink, "Contradictory input vertex spacing");
// The GLSL specification requires that at least one compilation unit
// must declare the triangle ordering layout, but not all units need to do so.
// However, all declarations must match.
if (vertexOrder == EvoNone)
vertexOrder = unit.vertexOrder;
else if (vertexOrder != unit.vertexOrder)
else if (unit.vertexOrder != EvoNone && vertexOrder != unit.vertexOrder)
error(infoSink, "Contradictory triangle ordering");
MERGE_TRUE(pointMode);
for (int i = 0; i < 3; ++i) {
// The GLSL specification requires that all workgroup size declarations must match
// but not all units have to declare the layout.
if (unit.localSizeNotDefault[i]) {
if (!localSizeNotDefault[i]) {
localSize[i] = unit.localSize[i];
@ -255,9 +610,11 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit)
error(infoSink, "Contradictory local size");
}
// The GLSL specification requires that all workgroup size specialization
// ids declarations must match, but not all units have to declare the layout.
if (localSizeSpecId[i] == TQualifier::layoutNotSet)
localSizeSpecId[i] = unit.localSizeSpecId[i];
else if (localSizeSpecId[i] != unit.localSizeSpecId[i])
else if (unit.localSizeSpecId[i] != TQualifier::layoutNotSet && localSizeSpecId[i] != unit.localSizeSpecId[i])
error(infoSink, "Contradictory local size specialization ids");
}
@ -266,10 +623,13 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit)
MERGE_TRUE(nonCoherentColorAttachmentReadEXT);
MERGE_TRUE(nonCoherentDepthAttachmentReadEXT);
MERGE_TRUE(nonCoherentStencilAttachmentReadEXT);
MERGE_TRUE(nonCoherentTileAttachmentReadQCOM);
// The GLSL specification requires that all depth layout redeclarations must match,
// but not all units have to declare the layout.
if (depthLayout == EldNone)
depthLayout = unit.depthLayout;
else if (depthLayout != unit.depthLayout)
else if (unit.depthLayout != EldNone && depthLayout != unit.depthLayout)
error(infoSink, "Contradictory depth layouts");
MERGE_TRUE(depthReplacing);
@ -280,9 +640,11 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit)
MERGE_TRUE(xfbMode);
for (size_t b = 0; b < xfbBuffers.size(); ++b) {
// The GLSL specification requires that all xfb_stride declarations for
// the same buffer must match, but not all units have to declare the layout.
if (xfbBuffers[b].stride == TQualifier::layoutXfbStrideEnd)
xfbBuffers[b].stride = unit.xfbBuffers[b].stride;
else if (xfbBuffers[b].stride != unit.xfbBuffers[b].stride)
else if (unit.xfbBuffers[b].stride != TQualifier::layoutXfbStrideEnd && xfbBuffers[b].stride != unit.xfbBuffers[b].stride)
error(infoSink, "Contradictory xfb_stride");
xfbBuffers[b].implicitStride = std::max(xfbBuffers[b].implicitStride, unit.xfbBuffers[b].implicitStride);
if (unit.xfbBuffers[b].contains64BitType)
@ -511,17 +873,6 @@ void TIntermediate::mergeBodies(TInfoSink& infoSink, TIntermSequence& globals, c
globals.insert(globals.end() - 1, unitGlobals.begin(), unitGlobals.end() - 1);
}
static inline bool isSameInterface(TIntermSymbol* symbol, EShLanguage stage, TIntermSymbol* unitSymbol, EShLanguage unitStage) {
return // 1) same stage and same shader interface
(stage == unitStage && symbol->getType().getShaderInterface() == unitSymbol->getType().getShaderInterface()) ||
// 2) accross stages and both are uniform or buffer
(symbol->getQualifier().storage == EvqUniform && unitSymbol->getQualifier().storage == EvqUniform) ||
(symbol->getQualifier().storage == EvqBuffer && unitSymbol->getQualifier().storage == EvqBuffer) ||
// 3) in/out matched across stage boundary
(stage < unitStage && symbol->getQualifier().storage == EvqVaryingOut && unitSymbol->getQualifier().storage == EvqVaryingIn) ||
(unitStage < stage && symbol->getQualifier().storage == EvqVaryingIn && unitSymbol->getQualifier().storage == EvqVaryingOut);
}
//
// Global Unfiform block stores any default uniforms (i.e. uniforms without a block)
// If two linked stages declare the same member, they are meant to be the same uniform
@ -611,10 +962,10 @@ void TIntermediate::mergeBlockDefinitions(TInfoSink& infoSink, TIntermSymbol* bl
// don't need as many checks as when merging symbols, since
// initializers and most qualifiers are stripped when the member is moved into the block
if ((*memberType) != (*unitMemberType)) {
error(infoSink, "Types must match:");
error(infoSink, "Types must match:", unitBlock->getStage());
infoSink.info << " " << memberType->getFieldName() << ": ";
infoSink.info << "\"" << memberType->getCompleteString() << "\" versus ";
infoSink.info << "\"" << unitMemberType->getCompleteString() << "\"\n";
infoSink.info << "\"" << memberType->getCompleteString() << "\" in stage " << StageName(block->getStage()) << " versus ";
infoSink.info << "\"" << unitMemberType->getCompleteString() << "\" in stage " << StageName(unitBlock->getStage()) << "\n";
}
memberIndexUpdates[i] = j;
@ -713,18 +1064,7 @@ void TIntermediate::mergeLinkerObjects(TInfoSink& infoSink, TIntermSequence& lin
TIntermSymbol* unitSymbol = unitLinkerObjects[unitLinkObj]->getAsSymbolNode();
assert(symbol && unitSymbol);
bool isSameSymbol = false;
// If they are both blocks in the same shader interface,
// match by the block-name, not the identifier name.
if (symbol->getType().getBasicType() == EbtBlock && unitSymbol->getType().getBasicType() == EbtBlock) {
if (isSameInterface(symbol, getStage(), unitSymbol, unitStage)) {
isSameSymbol = symbol->getType().getTypeName() == unitSymbol->getType().getTypeName();
}
}
else if (symbol->getName() == unitSymbol->getName())
isSameSymbol = true;
if (isSameSymbol) {
if (isSameSymbol(symbol, unitSymbol)) {
// filter out copy
merge = false;
@ -750,18 +1090,39 @@ void TIntermediate::mergeLinkerObjects(TInfoSink& infoSink, TIntermSequence& lin
}
else if (symbol->getWritableType().isImplicitlySizedArray() && unitSymbol->getType().isSizedArray()) {
if (symbol->getWritableType().getImplicitArraySize() > unitSymbol->getType().getOuterArraySize())
error(infoSink, "Implicit size of unsized array doesn't match same symbol among multiple shaders.");
error(infoSink, "Implicit size of unsized array doesn't match same symbol among multiple shaders.", unitStage);
}
else if (unitSymbol->getType().isImplicitlySizedArray() && symbol->getWritableType().isSizedArray()) {
if (unitSymbol->getType().getImplicitArraySize() > symbol->getWritableType().getOuterArraySize())
error(infoSink, "Implicit size of unsized array doesn't match same symbol among multiple shaders.");
error(infoSink, "Implicit size of unsized array doesn't match same symbol among multiple shaders.", unitStage);
}
if (symbol->getType().isStruct() && unitSymbol->getType().isStruct() &&
symbol->getType().getStruct()->size() == unitSymbol->getType().getStruct()->size()) {
for (int i = 0; i < (int)symbol->getType().getStruct()->size(); ++i) {
auto& type = (*symbol->getWritableType().getStruct())[i];
auto& unitType = (*unitSymbol->getWritableType().getStruct())[i];
if (type.type->isImplicitlySizedArray() && unitType.type->isImplicitlySizedArray()) {
if (unitType.type->getImplicitArraySize() > type.type->getImplicitArraySize())
type.type->updateImplicitArraySize(unitType.type->getImplicitArraySize());
}
else if (type.type->isImplicitlySizedArray() && unitType.type->isSizedArray()) {
if (type.type->getImplicitArraySize() > unitType.type->getOuterArraySize())
error(infoSink, "Implicit size of unsized array doesn't match same symbol among multiple shaders.", unitStage);
}
else if (type.type->isSizedArray() && unitType.type->isImplicitlySizedArray()) {
if (type.type->getOuterArraySize() < unitType.type->getImplicitArraySize())
error(infoSink, "Implicit size of unsized array doesn't match same symbol among multiple shaders.", unitStage);
}
}
}
// Update implicit array sizes
mergeImplicitArraySizes(symbol->getWritableType(), unitSymbol->getType());
// Check for consistent types/qualification/initializers etc.
mergeErrorCheck(infoSink, *symbol, *unitSymbol, unitStage);
mergeErrorCheck(infoSink, *symbol, *unitSymbol);
}
// If different symbols, verify they arn't push_constant since there can only be one per stage
else if (symbol->getQualifier().isPushConstant() && unitSymbol->getQualifier().isPushConstant() && getStage() == unitStage)
@ -803,7 +1164,7 @@ void TIntermediate::mergeLinkerObjects(TInfoSink& infoSink, TIntermSequence& lin
}
};
if (isSameInterface(symbol, getStage(), unitSymbol, unitStage)) {
if (isSameInterface(symbol, unitSymbol)) {
checkName(symbol->getName());
// check members of other anonymous blocks
@ -847,9 +1208,11 @@ void TIntermediate::mergeImplicitArraySizes(TType& type, const TType& unitType)
//
// This function only does one of intra- or cross-stage matching per call.
//
void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& symbol, const TIntermSymbol& unitSymbol, EShLanguage unitStage)
void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& symbol, const TIntermSymbol& unitSymbol)
{
bool crossStage = getStage() != unitStage;
EShLanguage stage = symbol.getStage();
EShLanguage unitStage = unitSymbol.getStage();
bool crossStage = stage != unitStage;
bool writeTypeComparison = false;
bool errorReported = false;
bool printQualifiers = false;
@ -861,10 +1224,10 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy
// but, we make an exception if one is an implicit array and the other is sized
// or if the array sizes differ because of the extra array dimension on some in/out boundaries
bool arraysMatch = false;
if (isIoResizeArray(symbol.getType(), getStage()) || isIoResizeArray(unitSymbol.getType(), unitStage)) {
if (isIoResizeArray(symbol.getType(), stage) || isIoResizeArray(unitSymbol.getType(), unitStage)) {
// if the arrays have an extra dimension because of the stage.
// compare dimensions while ignoring the outer dimension
unsigned int firstDim = isIoResizeArray(symbol.getType(), getStage()) ? 1 : 0;
unsigned int firstDim = isIoResizeArray(symbol.getType(), stage) ? 1 : 0;
unsigned int numDim = symbol.getArraySizes()
? symbol.getArraySizes()->getNumDims() : 0;
unsigned int unitFirstDim = isIoResizeArray(unitSymbol.getType(), unitStage) ? 1 : 0;
@ -893,7 +1256,7 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy
if (lpidx >= 0 && rpidx >= 0) {
error(infoSink, "Member names and types must match:", unitStage);
infoSink.info << " Block: " << symbol.getType().getTypeName() << "\n";
infoSink.info << " " << StageName(getStage()) << " stage: \""
infoSink.info << " " << StageName(stage) << " stage: \""
<< (*symbol.getType().getStruct())[lpidx].type->getCompleteString(true, false, false, true,
(*symbol.getType().getStruct())[lpidx].type->getFieldName()) << "\"\n";
infoSink.info << " " << StageName(unitStage) << " stage: \""
@ -901,20 +1264,20 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy
(*unitSymbol.getType().getStruct())[rpidx].type->getFieldName()) << "\"\n";
errorReported = true;
} else if (lpidx >= 0 && rpidx == -1) {
TString errmsg = StageName(getStage());
TString errmsg = StageName(stage);
errmsg.append(" block member has no corresponding member in ").append(StageName(unitStage)).append(" block:");
error(infoSink, errmsg.c_str(), unitStage);
infoSink.info << " " << StageName(getStage()) << " stage: Block: " << symbol.getType().getTypeName() << ", Member: "
infoSink.info << " " << StageName(stage) << " stage: Block: " << symbol.getType().getTypeName() << ", Member: "
<< (*symbol.getType().getStruct())[lpidx].type->getFieldName() << "\n";
infoSink.info << " " << StageName(unitStage) << " stage: Block: " << unitSymbol.getType().getTypeName() << ", Member: n/a \n";
errorReported = true;
} else if (lpidx == -1 && rpidx >= 0) {
TString errmsg = StageName(unitStage);
errmsg.append(" block member has no corresponding member in ").append(StageName(getStage())).append(" block:");
errmsg.append(" block member has no corresponding member in ").append(StageName(stage)).append(" block:");
error(infoSink, errmsg.c_str(), unitStage);
infoSink.info << " " << StageName(unitStage) << " stage: Block: " << unitSymbol.getType().getTypeName() << ", Member: "
<< (*unitSymbol.getType().getStruct())[rpidx].type->getFieldName() << "\n";
infoSink.info << " " << StageName(getStage()) << " stage: Block: " << symbol.getType().getTypeName() << ", Member: n/a \n";
infoSink.info << " " << StageName(stage) << " stage: Block: " << symbol.getType().getTypeName() << ", Member: n/a \n";
errorReported = true;
} else {
error(infoSink, "Types must match:", unitStage);
@ -971,7 +1334,7 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy
layoutQualifierError = true;
}
if (layoutQualifierError) {
infoSink.info << " " << StageName(getStage()) << " stage: Block: " << symbol.getType().getTypeName() << ", Member: "
infoSink.info << " " << StageName(stage) << " stage: Block: " << symbol.getType().getTypeName() << ", Member: "
<< (*symbol.getType().getStruct())[li].type->getFieldName() << " \""
<< (*symbol.getType().getStruct())[li].type->getCompleteString(true, true, false, false) << "\"\n";
infoSink.info << " " << StageName(unitStage) << " stage: Block: " << unitSymbol.getType().getTypeName() << ", Member: "
@ -1083,6 +1446,10 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy
error(infoSink, "Memory volatil qualifier must match:", unitStage);
memoryQualifierError = true;
}
if (symbol.getQualifier().nontemporal != unitSymbol.getQualifier().nontemporal) {
error(infoSink, "Memory nontemporal qualifier must match:", unitStage);
memoryQualifierError = true;
}
if (symbol.getQualifier().restrict != unitSymbol.getQualifier().restrict) {
error(infoSink, "Memory restrict qualifier must match:", unitStage);
memoryQualifierError = true;
@ -1152,24 +1519,24 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy
if (symbol.getType().getBasicType() == EbtBlock && unitSymbol.getType().getBasicType() == EbtBlock &&
symbol.getType().getStruct() && unitSymbol.getType().getStruct()) {
if (printType) {
infoSink.info << " " << StageName(getStage()) << " stage: \"" << symbol.getType().getCompleteString(true, printQualifiers, printPrecision,
infoSink.info << " " << StageName(stage) << " stage: \"" << symbol.getType().getCompleteString(true, printQualifiers, printPrecision,
printType, symbol.getName(), symbol.getType().getTypeName()) << "\"\n";
infoSink.info << " " << StageName(unitStage) << " stage: \"" << unitSymbol.getType().getCompleteString(true, printQualifiers, printPrecision,
printType, unitSymbol.getName(), unitSymbol.getType().getTypeName()) << "\"\n";
} else {
infoSink.info << " " << StageName(getStage()) << " stage: Block: " << symbol.getType().getTypeName() << " Instance: " << symbol.getName()
infoSink.info << " " << StageName(stage) << " stage: Block: " << symbol.getType().getTypeName() << " Instance: " << symbol.getName()
<< ": \"" << symbol.getType().getCompleteString(true, printQualifiers, printPrecision, printType) << "\"\n";
infoSink.info << " " << StageName(unitStage) << " stage: Block: " << unitSymbol.getType().getTypeName() << " Instance: " << unitSymbol.getName()
<< ": \"" << unitSymbol.getType().getCompleteString(true, printQualifiers, printPrecision, printType) << "\"\n";
}
} else {
if (printType) {
infoSink.info << " " << StageName(getStage()) << " stage: \""
infoSink.info << " " << StageName(stage) << " stage: \""
<< symbol.getType().getCompleteString(true, printQualifiers, printPrecision, printType, symbol.getName()) << "\"\n";
infoSink.info << " " << StageName(unitStage) << " stage: \""
<< unitSymbol.getType().getCompleteString(true, printQualifiers, printPrecision, printType, unitSymbol.getName()) << "\"\n";
} else {
infoSink.info << " " << StageName(getStage()) << " stage: " << symbol.getName() << " \""
infoSink.info << " " << StageName(stage) << " stage: " << symbol.getName() << " \""
<< symbol.getType().getCompleteString(true, printQualifiers, printPrecision, printType) << "\"\n";
infoSink.info << " " << StageName(unitStage) << " stage: " << unitSymbol.getName() << " \""
<< unitSymbol.getType().getCompleteString(true, printQualifiers, printPrecision, printType) << "\"\n";
@ -1201,7 +1568,8 @@ void TIntermediate::sharedBlockCheck(TInfoSink& infoSink)
// Do final link-time error checking of a complete (merged) intermediate representation.
// (Much error checking was done during merging).
//
// Also, lock in defaults of things not set, including array sizes.
// Also, lock in defaults of things not set.
// Defer adopting implicit array sizes to later, after all stages are merged.
//
void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled)
{
@ -1362,23 +1730,6 @@ void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled)
error(infoSink, "Unknown Stage.");
break;
}
// Process the tree for any node-specific work.
class TFinalLinkTraverser : public TIntermTraverser {
public:
TFinalLinkTraverser() { }
virtual ~TFinalLinkTraverser() { }
virtual void visitSymbol(TIntermSymbol* symbol)
{
// Implicitly size arrays.
// If an unsized array is left as unsized, it effectively
// becomes run-time sized.
symbol->getWritableType().adoptImplicitArraySizes(false);
}
} finalLinkTraverser;
treeRoot->traverse(&finalLinkTraverser);
}
//
@ -1635,6 +1986,8 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ
set = 1;
else if (qualifier.isHitObjectAttrNV())
set = 2;
else if (qualifier.isHitObjectAttrEXT())
set = 2;
else
return -1;
@ -1673,7 +2026,7 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ
// For raytracing IO (payloads and callabledata) each declaration occupies a single
// slot irrespective of type.
int collision = -1; // no collision
if (qualifier.isAnyPayload() || qualifier.isAnyCallable() || qualifier.isHitObjectAttrNV()) {
if (qualifier.isAnyPayload() || qualifier.isAnyCallable() || qualifier.isHitObjectAttrNV() || qualifier.isHitObjectAttrEXT()) {
TRange range(qualifier.layoutLocation, qualifier.layoutLocation);
collision = checkLocationRT(set, qualifier.layoutLocation);
if (collision < 0)
@ -1689,7 +2042,7 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ
// First range:
TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation);
TRange componentRange(0, 3);
TIoRange range(locationRange, componentRange, type.getBasicType(), 0, qualifier.centroid, qualifier.smooth, qualifier.flat);
TIoRange range(locationRange, componentRange, type.getBasicType(), 0, qualifier.centroid, qualifier.smooth, qualifier.flat, qualifier.sample, qualifier.patch);
// check for collisions
collision = checkLocationRange(set, range, type, typeCollision);
@ -1699,7 +2052,7 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ
// Second range:
TRange locationRange2(qualifier.layoutLocation + 1, qualifier.layoutLocation + 1);
TRange componentRange2(0, 1);
TIoRange range2(locationRange2, componentRange2, type.getBasicType(), 0, qualifier.centroid, qualifier.smooth, qualifier.flat);
TIoRange range2(locationRange2, componentRange2, type.getBasicType(), 0, qualifier.centroid, qualifier.smooth, qualifier.flat, qualifier.sample, qualifier.patch);
// check for collisions
collision = checkLocationRange(set, range2, type, typeCollision);
@ -1725,7 +2078,7 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ
TBasicType basicTy = type.getBasicType();
if (basicTy == EbtSampler && type.getSampler().isAttachmentEXT())
basicTy = type.getSampler().type;
TIoRange range(locationRange, componentRange, basicTy, qualifier.hasIndex() ? qualifier.getIndex() : 0, qualifier.centroid, qualifier.smooth, qualifier.flat);
TIoRange range(locationRange, componentRange, basicTy, qualifier.hasIndex() ? qualifier.getIndex() : 0, qualifier.centroid, qualifier.smooth, qualifier.flat, qualifier.sample, qualifier.patch);
// check for collisions, except for vertex inputs on desktop targeting OpenGL
if (! (!isEsProfile() && language == EShLangVertex && qualifier.isPipeInput()) || spvVersion.vulkan > 0)
@ -1737,6 +2090,24 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ
return collision;
}
// Check that two types can be stored in different components in the same location.
// They must be the same type, except signed/unsigned integers are considered compatible.
static bool checkCompatibleTypes(TBasicType t1, TBasicType t2) {
if (t1 != t2) {
if ((t1 == EbtInt8 && t2 == EbtUint8) ||
(t2 == EbtInt8 && t1 == EbtUint8) ||
(t1 == EbtInt16 && t2 == EbtUint16) ||
(t2 == EbtInt16 && t1 == EbtUint16)||
(t1 == EbtInt && t2 == EbtUint) ||
(t2 == EbtInt && t1 == EbtUint)||
(t1 == EbtInt64 && t2 == EbtUint64) ||
(t2 == EbtInt64 && t1 == EbtUint64)) {
return true;
}
}
return t1 == t2;
}
// Compare a new (the passed in) 'range' against the existing set, and see
// if there are any collisions.
//
@ -1749,10 +2120,12 @@ int TIntermediate::checkLocationRange(int set, const TIoRange& range, const TTyp
// there is a collision; pick one
return std::max(range.location.start, usedIo[set][r].location.start);
} else if (range.location.overlap(usedIo[set][r].location) &&
(type.getBasicType() != usedIo[set][r].basicType ||
(!checkCompatibleTypes(type.getBasicType(), usedIo[set][r].basicType) ||
type.getQualifier().centroid != usedIo[set][r].centroid ||
type.getQualifier().smooth != usedIo[set][r].smooth ||
type.getQualifier().flat != usedIo[set][r].flat)) {
type.getQualifier().flat != usedIo[set][r].flat ||
type.getQualifier().sample != usedIo[set][r].sample ||
type.getQualifier().patch != usedIo[set][r].patch)) {
// aliased-type mismatch
typeCollision = true;
return std::max(range.location.start, usedIo[set][r].location.start);
@ -2041,6 +2414,9 @@ int TIntermediate::getBaseAlignmentScalar(const TType& type, int& size)
case EbtUint64:
case EbtDouble: size = 8; return 8;
case EbtFloat16: size = 2; return 2;
case EbtBFloat16: size = 2; return 2;
case EbtFloatE5M2:
case EbtFloatE4M3:
case EbtInt8:
case EbtUint8: size = 1; return 1;
case EbtInt16:

View file

@ -48,6 +48,7 @@
#include <functional>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>
class TInfoSink;
@ -99,7 +100,8 @@ private:
// A "call" is a pair: <caller, callee>.
// There can be duplicates. General assumption is the list is small.
struct TCall {
TCall(const TString& pCaller, const TString& pCallee) : caller(pCaller), callee(pCallee) { }
TCall(const TString& pCaller, const TString& pCallee)
: caller(pCaller), callee(pCallee), visited(false), currentPath(false), errorGiven(false) { }
TString caller;
TString callee;
bool visited;
@ -123,8 +125,8 @@ struct TRange {
// within the same location range, component range, and index value. Locations don't alias unless
// all other dimensions of their range overlap.
struct TIoRange {
TIoRange(TRange location, TRange component, TBasicType basicType, int index, bool centroid, bool smooth, bool flat)
: location(location), component(component), basicType(basicType), index(index), centroid(centroid), smooth(smooth), flat(flat)
TIoRange(TRange location, TRange component, TBasicType basicType, int index, bool centroid, bool smooth, bool flat, bool sample, bool patch)
: location(location), component(component), basicType(basicType), index(index), centroid(centroid), smooth(smooth), flat(flat), sample(sample), patch(patch)
{
}
bool overlap(const TIoRange& rhs) const
@ -138,6 +140,8 @@ struct TIoRange {
bool centroid;
bool smooth;
bool flat;
bool sample;
bool patch;
};
// An offset range is a 2-D rectangle; the set of (binding, offset) pairs all lying
@ -265,6 +269,7 @@ public:
gpu_shader_fp64 = 1 << 9,
gpu_shader_int16 = 1 << 10,
gpu_shader_half_float = 1 << 11,
nv_gpu_shader5_types = 1 << 12,
} feature;
void insert(feature f) { features |= f; }
void erase(feature f) { features &= ~f; }
@ -339,6 +344,7 @@ public:
numTaskNVBlocks(0),
layoutPrimitiveCulling(false),
numTaskEXTPayloads(0),
nonCoherentTileAttachmentReadQCOM(false),
autoMapBindings(false),
autoMapLocations(false),
flattenUniformArrays(false),
@ -367,6 +373,12 @@ public:
localSizeSpecId[1] = TQualifier::layoutNotSet;
localSizeSpecId[2] = TQualifier::layoutNotSet;
xfbBuffers.resize(TQualifier::layoutXfbBufferEnd);
tileShadingRateQCOM[0] = 0;
tileShadingRateQCOM[1] = 0;
tileShadingRateQCOM[2] = 0;
tileShadingRateQCOMNotDefault[0] = false;
tileShadingRateQCOMNotDefault[1] = false;
tileShadingRateQCOMNotDefault[2] = false;
shiftBinding.fill(0);
}
@ -436,6 +448,9 @@ public:
case EShTargetVulkan_1_3:
processes.addProcess("target-env vulkan1.3");
break;
case EShTargetVulkan_1_4:
processes.addProcess("target-env vulkan1.4");
break;
default:
processes.addProcess("target-env vulkanUnknown");
break;
@ -560,8 +575,8 @@ public:
TIntermConstantUnion* addConstantUnion(const TString*, const TSourceLoc&, bool literal = false) const;
TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst,
TIntermLoop* addLoop(TIntermNode*, TIntermNode*, TIntermTyped*, bool testFirst, const TSourceLoc&);
TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermNode*, TIntermTyped*, bool testFirst,
const TSourceLoc&, TIntermLoop*&);
TIntermBranch* addBranch(TOperator, const TSourceLoc&);
TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
@ -644,6 +659,21 @@ public:
bool isEsProfile() const { return profile == EEsProfile; }
bool setTileShadingRateQCOM(int dim, int size)
{
if (tileShadingRateQCOMNotDefault[dim])
return size == tileShadingRateQCOM[dim];
tileShadingRateQCOMNotDefault[dim] = true;
tileShadingRateQCOM[dim] = size;
return true;
}
unsigned int getTileShadingRateQCOM(int dim) const { return tileShadingRateQCOM[dim]; }
bool isTileShadingRateQCOMSet() const
{
// Return true if any component has been set (i.e. any component is not default).
return tileShadingRateQCOMNotDefault[0] || tileShadingRateQCOMNotDefault[1] || tileShadingRateQCOMNotDefault[2];
}
void setShiftBinding(TResourceType res, unsigned int shift)
{
shiftBinding[res] = shift;
@ -729,6 +759,21 @@ public:
usePhysicalStorageBuffer = true;
}
bool usingPhysicalStorageBuffer() const { return usePhysicalStorageBuffer; }
void setReplicatedComposites()
{
useReplicatedComposites = true;
}
bool usingReplicatedComposites() const { return useReplicatedComposites; }
void setPromoteUint32Indices()
{
promoteUint32Indices = true;
}
bool usingPromoteUint32Indices() const { return promoteUint32Indices; }
void setShader64BitIndexing()
{
shader64BitIndexing = true;
}
bool usingShader64BitIndexing() const { return shader64BitIndexing; }
void setUseVariablePointers()
{
useVariablePointers = true;
@ -884,6 +929,8 @@ public:
bool getNonCoherentDepthAttachmentReadEXT() const { return nonCoherentDepthAttachmentReadEXT; }
void setNonCoherentStencilAttachmentReadEXT() { nonCoherentStencilAttachmentReadEXT = true; }
bool getNonCoherentStencilAttachmentReadEXT() const { return nonCoherentStencilAttachmentReadEXT; }
void setNonCoherentTileAttachmentReadQCOM() { nonCoherentTileAttachmentReadQCOM = true; }
bool getNonCoherentTileAttachmentReadQCOM() const { return nonCoherentTileAttachmentReadQCOM; }
void setPostDepthCoverage() { postDepthCoverage = true; }
bool getPostDepthCoverage() const { return postDepthCoverage; }
void setEarlyFragmentTests() { earlyFragmentTests = true; }
@ -1024,11 +1071,11 @@ public:
#endif
bool usingScalarBlockLayout() const {
for (auto extIt = requestedExtensions.begin(); extIt != requestedExtensions.end(); ++extIt) {
if (*extIt == E_GL_EXT_scalar_block_layout)
return true;
}
return false;
return IsRequestedExtension(E_GL_EXT_scalar_block_layout);
}
bool usingTextureOffsetNonConst() const {
return IsRequestedExtension(E_GL_EXT_texture_offset_non_const);
}
bool IsRequestedExtension(const char* extension) const
@ -1042,7 +1089,9 @@ public:
void mergeGlobalUniformBlocks(TInfoSink& infoSink, TIntermediate& unit, bool mergeExistingOnly);
void mergeUniformObjects(TInfoSink& infoSink, TIntermediate& unit);
void checkStageIO(TInfoSink&, TIntermediate&);
void mergeImplicitArraySizes(TInfoSink& infoSink, TIntermediate& unit);
void checkStageIO(TInfoSink&, TIntermediate&, EShMessages);
void optimizeStageIO(TInfoSink&, TIntermediate&);
bool buildConvertOp(TBasicType dst, TBasicType src, TOperator& convertOp) const;
TIntermTyped* createConversion(TBasicType convertTo, TIntermTyped* node) const;
@ -1055,6 +1104,7 @@ public:
int checkLocationRT(int set, int location);
int addUsedOffsets(int binding, int offset, int numOffsets);
bool addUsedConstantId(int id);
GLSLANG_EXPORT_FOR_TESTS
static int computeTypeLocationSize(const TType&, EShLanguage);
static int computeTypeUniformLocationSize(const TType&);
@ -1093,26 +1143,42 @@ public:
// Certain explicit conversions are allowed conditionally
bool getArithemeticInt8Enabled() const {
return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
numericFeatures.contains(TNumericFeatures::nv_gpu_shader5_types) ||
numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int8);
}
bool getArithemeticInt16Enabled() const {
return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
numericFeatures.contains(TNumericFeatures::gpu_shader_int16) ||
numericFeatures.contains(TNumericFeatures::nv_gpu_shader5_types) ||
numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int16);
}
bool getArithemeticFloat16Enabled() const {
return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
numericFeatures.contains(TNumericFeatures::gpu_shader_half_float) ||
numericFeatures.contains(TNumericFeatures::nv_gpu_shader5_types) ||
numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float16);
}
void updateNumericFeature(TNumericFeatures::feature f, bool on)
{ on ? numericFeatures.insert(f) : numericFeatures.erase(f); }
void setBuiltinAliasLookup(std::unordered_multimap<std::string, std::string> symbolMap) {
builtinAliasLookup = std::move(symbolMap);
}
const std::unordered_multimap<std::string, std::string>& getBuiltinAliasLookup() const {
return builtinAliasLookup;
}
protected:
TIntermSymbol* addSymbol(long long Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&);
void error(TInfoSink& infoSink, const char*, EShLanguage unitStage = EShLangCount);
void warn(TInfoSink& infoSink, const char*, EShLanguage unitStage = EShLangCount);
TIntermSymbol* addSymbol(long long Id, const TString&, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&);
void error(TInfoSink& infoSink, const TSourceLoc* loc, EShMessages messages, const char*, EShLanguage unitStage = EShLangCount);
void error(TInfoSink& infoSink, const char* message, EShLanguage unitStage = EShLangCount) {
error(infoSink, nullptr, EShMsgDefault, message, unitStage);
}
void warn(TInfoSink& infoSink, const TSourceLoc* loc, EShMessages, const char*, EShLanguage unitStage = EShLangCount);
void warn(TInfoSink& infoSink, const char* message, EShLanguage unitStage = EShLangCount) {
warn(infoSink, nullptr, EShMsgDefault, message, unitStage);
}
void mergeCallGraphs(TInfoSink&, TIntermediate&);
void mergeModes(TInfoSink&, TIntermediate&);
void mergeTrees(TInfoSink&, TIntermediate&);
@ -1122,7 +1188,7 @@ protected:
void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects, EShLanguage);
void mergeBlockDefinitions(TInfoSink&, TIntermSymbol* block, TIntermSymbol* unitBlock, TIntermediate* unitRoot);
void mergeImplicitArraySizes(TType&, const TType&);
void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, EShLanguage);
void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&);
void checkCallGraphCycles(TInfoSink&);
void checkCallGraphBodies(TInfoSink&, bool keepUncalled);
void inOutLocationCheck(TInfoSink&);
@ -1218,6 +1284,10 @@ protected:
bool layoutPrimitiveCulling;
int numTaskEXTPayloads;
bool nonCoherentTileAttachmentReadQCOM;
int tileShadingRateQCOM[3];
bool tileShadingRateQCOMNotDefault[3];
// Base shift values
std::array<unsigned int, EResCount> shiftBinding;
@ -1242,6 +1312,9 @@ protected:
bool subgroupUniformControlFlow;
bool maximallyReconverges;
bool usePhysicalStorageBuffer;
bool useReplicatedComposites { false };
bool promoteUint32Indices { false };
bool shader64BitIndexing { false };
TSpirvRequirement* spirvRequirement;
TSpirvExecutionMode* spirvExecutionMode;
@ -1270,6 +1343,9 @@ protected:
// Included text. First string is a name, second is the included text
std::map<std::string, std::string> includeText;
// Maps from canonical symbol name to alias symbol names
std::unordered_multimap<std::string, std::string> builtinAliasLookup;
// for OpModuleProcessed, or equivalent
TProcesses processes;

View file

@ -103,6 +103,9 @@ public:
virtual void doubleCheck(const TSourceLoc&, const char* op);
virtual void float16Check(const TSourceLoc&, const char* op, bool builtIn = false);
virtual void float16ScalarVectorCheck(const TSourceLoc&, const char* op, bool builtIn = false);
virtual void bfloat16ScalarVectorCheck(const TSourceLoc&, const char* op, bool builtIn = false);
virtual void floate5m2ScalarVectorCheck(const TSourceLoc&, const char* op, bool builtIn = false);
virtual void floate4m3ScalarVectorCheck(const TSourceLoc&, const char* op, bool builtIn = false);
virtual bool float16Arithmetic();
virtual void requireFloat16Arithmetic(const TSourceLoc& loc, const char* op, const char* featureDesc);
virtual void int16ScalarVectorCheck(const TSourceLoc&, const char* op, bool builtIn = false);
@ -121,6 +124,11 @@ public:
virtual void fcoopmatCheckNV(const TSourceLoc&, const char* op, bool builtIn = false);
virtual void intcoopmatCheckNV(const TSourceLoc&, const char *op, bool builtIn = false);
virtual void coopmatCheck(const TSourceLoc&, const char* op, bool builtIn = false);
virtual void coopmatConverisonCheckQCOM(const TSourceLoc& loc, const char* op, bool builtIn = false);
virtual void tensorLayoutViewCheck(const TSourceLoc&, const char* op, bool builtIn = false);
virtual void coopvecCheck(const TSourceLoc&, const char* op, bool builtIn = false);
virtual void intattachmentCheck(const TSourceLoc&, const char *op, bool builtIn = false);
virtual void tensorCheckARM(const TSourceLoc&, const char *op, bool builtIn = false);
bool relaxedErrors() const { return (messages & EShMsgRelaxedErrors) != 0; }
bool suppressWarnings() const { return (messages & EShMsgSuppressWarnings) != 0; }
bool isForwardCompatible() const { return forwardCompatible; }

View file

@ -153,12 +153,57 @@ int TPpContext::CPPdefine(TPpToken* ppToken)
return token;
}
int pendingPoundSymbols = 0;
TPpToken savePound;
// record the definition of the macro
while (token != '\n' && token != EndOfInput) {
mac.body.putToken(token, ppToken);
if (token == '#') {
pendingPoundSymbols++;
if (pendingPoundSymbols == 0) {
savePound = *ppToken;
}
} else if (pendingPoundSymbols == 0) {
mac.body.putToken(token, ppToken);
} else if (pendingPoundSymbols == 1) {
// A single #: stringify
parseContext.requireProfile(ppToken->loc, ~EEsProfile, "stringify (#)");
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, nullptr, "stringify (#)");
bool isArg = false;
if (token == PpAtomIdentifier) {
for (int i = (int)mac.args.size() - 1; i >= 0; i--) {
if (strcmp(atomStrings.getString(mac.args[i]), ppToken->name) == 0) {
isArg = true;
break;
}
}
}
if (!isArg) {
parseContext.ppError(ppToken->loc, "'#' is not followed by a macro parameter.", "#", "");
return token;
}
mac.body.putToken(tStringifyLevelInput::PUSH, ppToken);
mac.body.putToken(token, ppToken);
mac.body.putToken(tStringifyLevelInput::POP, ppToken);
pendingPoundSymbols = 0;
} else if (pendingPoundSymbols % 2 == 0) {
// Any number of pastes '##' in a row: idempotent, just becomes one paste
parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)");
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, nullptr, "token pasting (##)");
for (int i = 0; i < pendingPoundSymbols / 2; i++) {
mac.body.putToken(PpAtomPaste, &savePound);
}
mac.body.putToken(token, ppToken);
pendingPoundSymbols = 0;
} else {
// An odd number of '#' i.e., mix of paste and stringify: does not give valid preprocessing token
parseContext.ppError(ppToken->loc, "Illegal sequence of paste (##) and stringify (#).", "#", "");
return token;
}
token = scanToken(ppToken);
if (token != '\n' && ppToken->space)
mac.body.putToken(' ', ppToken);
}
if (pendingPoundSymbols != 0) {
parseContext.ppError(ppToken->loc, "Macro ended with incomplete '#' paste/stringify operators", "#", "");
}
// check for duplicate definition
@ -241,6 +286,7 @@ int TPpContext::CPPundef(TPpToken* ppToken)
*/
int TPpContext::CPPelse(int matchelse, TPpToken* ppToken)
{
inElseSkip = true;
int depth = 0;
int token = scanToken(ppToken);
@ -297,7 +343,7 @@ int TPpContext::CPPelse(int matchelse, TPpToken* ppToken)
elseSeen[elsetracker] = false;
--elsetracker;
}
inElseSkip = false;
return CPPif(ppToken);
}
} else if (nextAtom == PpAtomElse) {
@ -311,7 +357,8 @@ int TPpContext::CPPelse(int matchelse, TPpToken* ppToken)
parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
}
}
inElseSkip = false;
return token;
}
@ -374,7 +421,7 @@ namespace {
int op_div(int a, int b) { return a == INT_MIN && b == -1 ? 0 : a / b; }
int op_mod(int a, int b) { return a == INT_MIN && b == -1 ? 0 : a % b; }
int op_pos(int a) { return a; }
int op_neg(int a) { return -a; }
int op_neg(int a) { return a == INT_MIN ? INT_MIN : -a; }
int op_cmpl(int a) { return ~a; }
int op_not(int a) { return !a; }
@ -1117,7 +1164,7 @@ int TPpContext::tMacroInput::scan(TPpToken* ppToken)
}
// see if are preceding a ##
if (mac->body.peekUntokenizedPasting()) {
if (mac->body.peekTokenizedPasting(false)) {
prepaste = true;
pasting = true;
}

View file

@ -88,7 +88,8 @@ TPpContext::TPpContext(TParseContextBase& pc, const std::string& rootFileName, T
preamble(nullptr), strings(nullptr), previous_token('\n'), parseContext(pc), includer(inclr), inComment(false),
rootFileName(rootFileName),
currentSourceFile(rootFileName),
disableEscapeSequences(false)
disableEscapeSequences(false),
inElseSkip(false)
{
ifdepth = 0;
for (elsetracker = 0; elsetracker < maxIfNesting; elsetracker++)

View file

@ -311,7 +311,6 @@ public:
int getToken(TParseContextBase&, TPpToken*);
bool atEnd() { return currentPos >= stream.size(); }
bool peekTokenizedPasting(bool lastTokenPastes);
bool peekUntokenizedPasting();
void reset() { currentPos = 0; }
protected:
@ -371,24 +370,8 @@ protected:
break;
popInput();
}
if (!inputStack.empty() && inputStack.back()->isStringInput()) {
if (!inputStack.empty() && inputStack.back()->isStringInput() && !inElseSkip) {
if (token == '\n') {
bool seenNumSign = false;
for (int i = 0; i < (int)lastLineTokens.size() - 1;) {
int curPos = i;
int curToken = lastLineTokens[i++];
if (curToken == '#' && lastLineTokens[i] == '#') {
curToken = PpAtomPaste;
i++;
}
if (curToken == '#') {
if (seenNumSign) {
parseContext.ppError(lastLineTokenLocs[curPos], "(#) can be preceded in its line only by spaces or horizontal tabs", "#", "");
} else {
seenNumSign = true;
}
}
}
lastLineTokens.clear();
lastLineTokenLocs.clear();
} else {
@ -458,6 +441,38 @@ protected:
static const int marker = -3;
};
class tStringifyLevelInput : public tInput {
int what;
tStringifyLevelInput(TPpContext* pp) : tInput(pp) { }
public:
static tStringifyLevelInput popMarker(TPpContext* pp)
{
tStringifyLevelInput sl(pp);
sl.what = POP;
return sl;
}
static tStringifyLevelInput pushMarker(TPpContext* pp)
{
tStringifyLevelInput sl(pp);
sl.what = PUSH;
return sl;
}
int scan(TPpToken*) override
{
if (done)
return EndOfInput;
done = true;
return what;
}
virtual int getch() override { assert(0); return EndOfInput; }
virtual void ungetch() override { assert(0); }
static const int PUSH = -4;
static const int POP = -5;
};
class tZeroInput : public tInput {
public:
tZeroInput(TPpContext* pp) : tInput(pp) { }
@ -732,6 +747,9 @@ protected:
std::istringstream strtodStream;
bool disableEscapeSequences;
// True if we're skipping a section enclosed by #if/#ifdef/#elif/#else which was evaluated to
// be inactive, e.g. #if 0
bool inElseSkip;
};
} // end namespace glslang

View file

@ -97,7 +97,6 @@ namespace glslang {
/////////////////////////////////// Floating point constants: /////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
//
// Scan a single- or double-precision floating point constant.
// Assumes that the scanner has seen at least one digit,
// followed by either a decimal '.' or the letter 'e', or a
@ -470,6 +469,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken)
static const char* const Int64_Extensions[] = {
E_GL_ARB_gpu_shader_int64,
E_GL_EXT_shader_explicit_arithmetic_types,
E_GL_NV_gpu_shader5,
E_GL_EXT_shader_explicit_arithmetic_types_int64 };
static const int Num_Int64_Extensions = sizeof(Int64_Extensions) / sizeof(Int64_Extensions[0]);
@ -1225,7 +1225,9 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken)
//
int TPpContext::tokenize(TPpToken& ppToken)
{
for(;;) {
int stringifyDepth = 0;
TPpToken stringifiedToken; // Tokens are appended to this as they come in
for (;;) {
int token = scanToken(&ppToken);
// Handle token-pasting logic
@ -1253,6 +1255,20 @@ int TPpContext::tokenize(TPpToken& ppToken)
if (token == '\n')
continue;
if (token == tStringifyLevelInput::PUSH) {
stringifyDepth++;
continue;
}
if (token == tStringifyLevelInput::POP) {
assert(stringifyDepth > 0);
stringifyDepth--;
if (stringifyDepth == 0) {
snprintf(ppToken.name, sizeof(ppToken.name), "%s", stringifiedToken.name);
return PpAtomConstString;
}
continue;
}
// expand macros
if (token == PpAtomIdentifier) {
switch (MacroExpand(&ppToken, false, true)) {
@ -1266,7 +1282,21 @@ int TPpContext::tokenize(TPpToken& ppToken)
}
}
bool needStringSupport = ifdepth == 0 && (token == PpAtomConstString || stringifyDepth > 0);
if (needStringSupport && parseContext.intermediate.getSource() != EShSourceHlsl) {
// HLSL allows string literals.
// GLSL allows string literals with GL_EXT_debug_printf.
const char* const string_literal_EXTs[] = { E_GL_EXT_debug_printf, E_GL_EXT_spirv_intrinsics };
parseContext.requireExtensions(ppToken.loc, 2, string_literal_EXTs, "string literal");
if (!parseContext.extensionTurnedOn(E_GL_EXT_debug_printf) &&
!parseContext.extensionTurnedOn(E_GL_EXT_spirv_intrinsics)) {
continue;
}
}
switch (token) {
case PpAtomConstString:
break;
case PpAtomIdentifier:
case PpAtomConstInt:
case PpAtomConstUint:
@ -1280,17 +1310,6 @@ int TPpContext::tokenize(TPpToken& ppToken)
if (ppToken.name[0] == '\0')
continue;
break;
case PpAtomConstString:
// HLSL allows string literals.
// GLSL allows string literals with GL_EXT_debug_printf.
if (ifdepth == 0 && parseContext.intermediate.getSource() != EShSourceHlsl) {
const char* const string_literal_EXTs[] = { E_GL_EXT_debug_printf, E_GL_EXT_spirv_intrinsics };
parseContext.requireExtensions(ppToken.loc, 2, string_literal_EXTs, "string literal");
if (!parseContext.extensionTurnedOn(E_GL_EXT_debug_printf) &&
!parseContext.extensionTurnedOn(E_GL_EXT_spirv_intrinsics))
continue;
}
break;
case '\'':
parseContext.ppError(ppToken.loc, "character literals not supported", "\'", "");
continue;
@ -1298,6 +1317,17 @@ int TPpContext::tokenize(TPpToken& ppToken)
snprintf(ppToken.name, sizeof(ppToken.name), "%s", atomStrings.getString(token));
break;
}
if (stringifyDepth > 0) {
size_t existingLen = strlen(stringifiedToken.name);
char* dst = stringifiedToken.name + existingLen;
// stringify_depth would determine how many layers of \\\"\\\" are needed, if we wanted to.
if (ppToken.space) {
snprintf(dst, sizeof(stringifiedToken.name) - existingLen - 1, " %s", ppToken.name);
} else {
snprintf(dst, sizeof(stringifiedToken.name) - existingLen, "%s", ppToken.name);
}
continue;
}
return token;
}
@ -1328,6 +1358,7 @@ int TPpContext::tokenPaste(int token, TPpToken& ppToken)
// This covers end of macro expansion
if (endOfReplacementList()) {
// this should be unreachable, incomplete #/## sequences are caught at macro parsing time.
parseContext.ppError(ppToken.loc, "unexpected location; end of replacement list", "##", "");
break;
}

View file

@ -105,7 +105,7 @@ void TPpContext::TokenStream::putToken(int atom, TPpToken* ppToken)
}
// Read the next token from a macro token stream.
int TPpContext::TokenStream::getToken(TParseContextBase& parseContext, TPpToken *ppToken)
int TPpContext::TokenStream::getToken(TParseContextBase& parseContext, TPpToken* ppToken)
{
if (atEnd())
return EndOfInput;
@ -113,16 +113,6 @@ int TPpContext::TokenStream::getToken(TParseContextBase& parseContext, TPpToken
int atom = stream[currentPos++].get(*ppToken);
ppToken->loc = parseContext.getCurrentLoc();
// Check for ##, unless the current # is the last character
if (atom == '#') {
if (peekToken('#')) {
parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)");
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, nullptr, "token pasting (##)");
currentPos++;
atom = PpAtomPaste;
}
}
return atom;
}
@ -146,8 +136,10 @@ bool TPpContext::TokenStream::peekTokenizedPasting(bool lastTokenPastes)
// 2. last token and we've been told after this there will be a ##
if (! lastTokenPastes)
if (! lastTokenPastes) {
currentPos = savePos;
return false;
}
// Getting here means the last token will be pasted, after this
// Are we at the last non-whitespace token?
@ -167,29 +159,6 @@ bool TPpContext::TokenStream::peekTokenizedPasting(bool lastTokenPastes)
return !moreTokens;
}
// See if the next non-white-space tokens are two consecutive #
bool TPpContext::TokenStream::peekUntokenizedPasting()
{
// don't return early, have to restore this
size_t savePos = currentPos;
// skip white-space
while (peekToken(' '))
++currentPos;
// check for ##
bool pasting = false;
if (peekToken('#')) {
++currentPos;
if (peekToken('#'))
pasting = true;
}
currentPos = savePos;
return pasting;
}
void TPpContext::pushTokenStreamInput(TokenStream& ts, bool prepasting, bool expanded)
{
pushInput(new tTokenInput(this, &ts, prepasting, expanded));

View file

@ -174,6 +174,9 @@ bool isArithmeticOperation(glslang::TOperator op)
case glslang::EOpMatrixTimesMatrix:
case glslang::EOpDot:
case glslang::EOpDotPackedEXT:
case glslang::EOpDotAccSatEXT:
case glslang::EOpDotPackedAccSatEXT:
case glslang::EOpPostIncrement:
case glslang::EOpPostDecrement:

View file

@ -52,4 +52,5 @@ namespace glslang {
// 'noContraction' means the object is 'precise'; and for arithmetic operation
// nodes, it means the operation should not be contracted.
void PropagateNoContraction(const glslang::TIntermediate& intermediate);
};
} // end namespace glslang

View file

@ -1138,8 +1138,10 @@ void TReflection::buildAttributeReflection(EShLanguage stage, const TIntermediat
{
if (stage == EShLangCompute) {
// Remember thread dimensions
for (int dim=0; dim<3; ++dim)
for (int dim=0; dim<3; ++dim) {
localSize[dim] = intermediate.getLocalSize(dim);
tileShadingRateQCOM[dim] = intermediate.getTileShadingRateQCOM(dim);
}
}
}
@ -1270,9 +1272,8 @@ void TReflection::dump()
indexToPipeOutput[i].dump();
printf("\n");
static const char* axis[] = { "X", "Y", "Z" };
if (getLocalSize(0) > 1) {
static const char* axis[] = { "X", "Y", "Z" };
for (int dim=0; dim<3; ++dim)
if (getLocalSize(dim) > 1)
printf("Local size %s: %u\n", axis[dim], getLocalSize(dim));
@ -1280,6 +1281,12 @@ void TReflection::dump()
printf("\n");
}
if (getTileShadingRateQCOM(0) > 1 || getTileShadingRateQCOM(1) > 1) {
for (int dim=0; dim<3; ++dim)
printf("Tile shading rate QCOM %s: %u\n", axis[dim], getTileShadingRateQCOM(dim));
printf("\n");
}
// printf("Live names\n");
// for (TNameToIndex::const_iterator it = nameToIndex.begin(); it != nameToIndex.end(); ++it)
// printf("%s: %d\n", it->first.c_str(), it->second);

View file

@ -37,8 +37,8 @@
#define _REFLECTION_INCLUDED
#include "../Public/ShaderLang.h"
#include "../Include/Types.h"
#include "../Include/BaseTypes.h"
#include "../Include/visibility.h"
#include <list>
#include <set>
@ -58,13 +58,16 @@ public:
TReflection(EShReflectionOptions opts, EShLanguage first, EShLanguage last)
: options(opts), firstStage(first), lastStage(last), badReflection(TObjectReflection::badReflection())
{
for (int dim=0; dim<3; ++dim)
for (int dim=0; dim<3; ++dim) {
localSize[dim] = 0;
tileShadingRateQCOM[dim] = 0;
}
}
virtual ~TReflection() {}
// grow the reflection stage by stage
GLSLANG_EXPORT_FOR_TESTS
bool addStage(EShLanguage, const TIntermediate&);
// for mapping a uniform index to a uniform object's description
@ -167,6 +170,9 @@ public:
// Thread local size
unsigned getLocalSize(int dim) const { return dim <= 2 ? localSize[dim] : 0; }
// Tile shading rate QCOM
unsigned getTileShadingRateQCOM(int dim) const { return dim <= 2 ? tileShadingRateQCOM[dim] : 0; }
void dump();
protected:
@ -212,6 +218,7 @@ protected:
TIndices atomicCounterUniformIndices;
unsigned int localSize[3];
unsigned int tileShadingRateQCOM[3];
};
} // end namespace glslang

View file

@ -35,9 +35,10 @@
#ifndef __OSINCLUDE_H
#define __OSINCLUDE_H
#include "../Include/visibility.h"
namespace glslang {
void OS_DumpMemoryCounters();
GLSLANG_EXPORT void OS_DumpMemoryCounters();
} // end namespace glslang

View file

@ -38,20 +38,21 @@
#include <string>
#include "../Include/ResourceLimits.h"
#include "../Include/visibility.h"
// Return pointer to user-writable Resource to pass through API in
// future-proof way.
extern TBuiltInResource* GetResources();
GLSLANG_EXPORT extern TBuiltInResource* GetResources();
// These are the default resources for TBuiltInResources, used for both
// - parsing this string for the case where the user didn't supply one,
// - dumping out a template for user construction of a config file.
extern const TBuiltInResource* GetDefaultResources();
GLSLANG_EXPORT extern const TBuiltInResource* GetDefaultResources();
// Returns the DefaultTBuiltInResource as a human-readable string.
std::string GetDefaultTBuiltInResourceString();
GLSLANG_EXPORT std::string GetDefaultTBuiltInResourceString();
// Decodes the resource limits from |config| to |resources|.
void DecodeResourceLimits(TBuiltInResource* resources, char* config);
GLSLANG_EXPORT void DecodeResourceLimits(TBuiltInResource* resources, char* config);
#endif // _STAND_ALONE_RESOURCE_LIMITS_INCLUDED_

View file

@ -38,6 +38,7 @@
#define _COMPILER_INTERFACE_INCLUDED_
#include "../Include/ResourceLimits.h"
#include "../Include/visibility.h"
#include "../MachineIndependent/Versions.h"
#include <cstring>
@ -49,22 +50,6 @@
#define C_DECL
#endif
#ifdef GLSLANG_IS_SHARED_LIBRARY
#ifdef _WIN32
#ifdef GLSLANG_EXPORTING
#define GLSLANG_EXPORT __declspec(dllexport)
#else
#define GLSLANG_EXPORT __declspec(dllimport)
#endif
#elif __GNUC__ >= 4
#define GLSLANG_EXPORT __attribute__((visibility("default")))
#endif
#endif // GLSLANG_IS_SHARED_LIBRARY
#ifndef GLSLANG_EXPORT
#define GLSLANG_EXPORT
#endif
//
// This is the platform independent interface between an OGL driver
// and the shading language compiler/linker.
@ -171,8 +156,9 @@ typedef enum {
EShTargetVulkan_1_1 = (1 << 22) | (1 << 12), // Vulkan 1.1
EShTargetVulkan_1_2 = (1 << 22) | (2 << 12), // Vulkan 1.2
EShTargetVulkan_1_3 = (1 << 22) | (3 << 12), // Vulkan 1.3
EShTargetVulkan_1_4 = (1 << 22) | (4 << 12), // Vulkan 1.4
EShTargetOpenGL_450 = 450, // OpenGL
LAST_ELEMENT_MARKER(EShTargetClientVersionCount = 5),
LAST_ELEMENT_MARKER(EShTargetClientVersionCount = 6),
} EShTargetClientVersion;
typedef EShTargetClientVersion EshTargetClientVersion;
@ -188,6 +174,21 @@ typedef enum {
LAST_ELEMENT_MARKER(EShTargetLanguageVersionCount = 7),
} EShTargetLanguageVersion;
//
// Following are a series of helper enums for managing layouts and qualifiers,
// used for TPublicType, TType, others.
//
enum TLayoutPacking {
ElpNone,
ElpShared, // default, but different than saying nothing
ElpStd140,
ElpStd430,
ElpPacked,
ElpScalar,
ElpCount // If expanding, see bitfield width below
};
struct TInputLanguage {
EShSource languageFamily; // redundant information with other input, this one overrides when not EShSourceNone
EShLanguage stage; // redundant information with other input, this one overrides when not EShSourceNone
@ -270,6 +271,9 @@ enum EShMessages : unsigned {
EShMsgBuiltinSymbolTable = (1 << 14), // print the builtin symbol table
EShMsgEnhanced = (1 << 15), // enhanced message readability
EShMsgAbsolutePath = (1 << 16), // Output Absolute path for messages
EShMsgDisplayErrorColumn = (1 << 17), // Display error message column aswell as line
EShMsgLinkTimeOptimization = (1 << 18), // perform cross-stage optimizations during linking
EShMsgValidateCrossStageIO = (1 << 19), // validate shader inputs have matching outputs in previous stage
LAST_ELEMENT_MARKER(EShMsgCount),
};
@ -414,6 +418,7 @@ GLSLANG_EXPORT int GetKhronosToolId();
class TIntermediate;
class TProgram;
class TPoolAllocator;
class TIoMapResolver;
// Call this exactly once per process before using anything else
GLSLANG_EXPORT bool InitializeProcess();
@ -429,6 +434,9 @@ enum TResourceType {
EResUbo,
EResSsbo,
EResUav,
EResCombinedSampler,
EResAs,
EResTensor,
EResCount
};
@ -458,56 +466,59 @@ enum TBlockStorageClass
//
// N.B.: Destruct a linked program *before* destructing the shaders linked into it.
//
class TShader {
class GLSLANG_EXPORT TShader {
public:
GLSLANG_EXPORT explicit TShader(EShLanguage);
GLSLANG_EXPORT virtual ~TShader();
GLSLANG_EXPORT void setStrings(const char* const* s, int n);
GLSLANG_EXPORT void setStringsWithLengths(
explicit TShader(EShLanguage);
virtual ~TShader();
void setStrings(const char* const* s, int n);
void setStringsWithLengths(
const char* const* s, const int* l, int n);
GLSLANG_EXPORT void setStringsWithLengthsAndNames(
void setStringsWithLengthsAndNames(
const char* const* s, const int* l, const char* const* names, int n);
void setPreamble(const char* s) { preamble = s; }
GLSLANG_EXPORT void setEntryPoint(const char* entryPoint);
GLSLANG_EXPORT void setSourceEntryPoint(const char* sourceEntryPointName);
GLSLANG_EXPORT void addProcesses(const std::vector<std::string>&);
GLSLANG_EXPORT void setUniqueId(unsigned long long id);
GLSLANG_EXPORT void setOverrideVersion(int version);
GLSLANG_EXPORT void setDebugInfo(bool debugInfo);
void setEntryPoint(const char* entryPoint);
void setSourceEntryPoint(const char* sourceEntryPointName);
void addProcesses(const std::vector<std::string>&);
void setUniqueId(unsigned long long id);
void setOverrideVersion(int version);
void setDebugInfo(bool debugInfo);
// IO resolver binding data: see comments in ShaderLang.cpp
GLSLANG_EXPORT void setShiftBinding(TResourceType res, unsigned int base);
GLSLANG_EXPORT void setShiftSamplerBinding(unsigned int base); // DEPRECATED: use setShiftBinding
GLSLANG_EXPORT void setShiftTextureBinding(unsigned int base); // DEPRECATED: use setShiftBinding
GLSLANG_EXPORT void setShiftImageBinding(unsigned int base); // DEPRECATED: use setShiftBinding
GLSLANG_EXPORT void setShiftUboBinding(unsigned int base); // DEPRECATED: use setShiftBinding
GLSLANG_EXPORT void setShiftUavBinding(unsigned int base); // DEPRECATED: use setShiftBinding
GLSLANG_EXPORT void setShiftCbufferBinding(unsigned int base); // synonym for setShiftUboBinding
GLSLANG_EXPORT void setShiftSsboBinding(unsigned int base); // DEPRECATED: use setShiftBinding
GLSLANG_EXPORT void setShiftBindingForSet(TResourceType res, unsigned int base, unsigned int set);
GLSLANG_EXPORT void setResourceSetBinding(const std::vector<std::string>& base);
GLSLANG_EXPORT void setAutoMapBindings(bool map);
GLSLANG_EXPORT void setAutoMapLocations(bool map);
GLSLANG_EXPORT void addUniformLocationOverride(const char* name, int loc);
GLSLANG_EXPORT void setUniformLocationBase(int base);
GLSLANG_EXPORT void setInvertY(bool invert);
GLSLANG_EXPORT void setDxPositionW(bool dxPosW);
GLSLANG_EXPORT void setEnhancedMsgs();
void setShiftBinding(TResourceType res, unsigned int base);
void setShiftSamplerBinding(unsigned int base); // DEPRECATED: use setShiftBinding
void setShiftTextureBinding(unsigned int base); // DEPRECATED: use setShiftBinding
void setShiftImageBinding(unsigned int base); // DEPRECATED: use setShiftBinding
void setShiftUboBinding(unsigned int base); // DEPRECATED: use setShiftBinding
void setShiftUavBinding(unsigned int base); // DEPRECATED: use setShiftBinding
void setShiftCbufferBinding(unsigned int base); // synonym for setShiftUboBinding
void setShiftSsboBinding(unsigned int base); // DEPRECATED: use setShiftBinding
void setShiftBindingForSet(TResourceType res, unsigned int base, unsigned int set);
void setResourceSetBinding(const std::vector<std::string>& base);
void setAutoMapBindings(bool map);
void setAutoMapLocations(bool map);
void addUniformLocationOverride(const char* name, int loc);
void setUniformLocationBase(int base);
void setInvertY(bool invert);
void setDxPositionW(bool dxPosW);
void setEnhancedMsgs();
#ifdef ENABLE_HLSL
GLSLANG_EXPORT void setHlslIoMapping(bool hlslIoMap);
GLSLANG_EXPORT void setFlattenUniformArrays(bool flatten);
void setHlslIoMapping(bool hlslIoMap);
void setFlattenUniformArrays(bool flatten);
#endif
GLSLANG_EXPORT void setNoStorageFormat(bool useUnknownFormat);
GLSLANG_EXPORT void setNanMinMaxClamp(bool nanMinMaxClamp);
GLSLANG_EXPORT void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode);
GLSLANG_EXPORT void addBlockStorageOverride(const char* nameStr, glslang::TBlockStorageClass backing);
void setNoStorageFormat(bool useUnknownFormat);
void setNanMinMaxClamp(bool nanMinMaxClamp);
void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode);
void addBlockStorageOverride(const char* nameStr, glslang::TBlockStorageClass backing);
GLSLANG_EXPORT void setGlobalUniformBlockName(const char* name);
GLSLANG_EXPORT void setAtomicCounterBlockName(const char* name);
GLSLANG_EXPORT void setGlobalUniformSet(unsigned int set);
GLSLANG_EXPORT void setGlobalUniformBinding(unsigned int binding);
GLSLANG_EXPORT void setAtomicCounterBlockSet(unsigned int set);
GLSLANG_EXPORT void setAtomicCounterBlockBinding(unsigned int binding);
void setGlobalUniformBlockName(const char* name);
void setAtomicCounterBlockName(const char* name);
void setGlobalUniformSet(unsigned int set);
void setGlobalUniformBinding(unsigned int binding);
void setAtomicCounterBlockSet(unsigned int set);
void setAtomicCounterBlockBinding(unsigned int binding);
void addSourceText(const char* text, size_t len);
void setSourceFile(const char* file);
// For setting up the environment (cleared to nothingness in the constructor).
// These must be called so that parsing is done for the right source language and
@ -656,7 +667,7 @@ public:
virtual void releaseInclude(IncludeResult*) override { }
};
GLSLANG_EXPORT bool parse(
bool parse(
const TBuiltInResource*, int defaultVersion, EProfile defaultProfile,
bool forceDefaultVersionAndProfile, bool forwardCompatible,
EShMessages, Includer&);
@ -682,14 +693,14 @@ public:
// NOTE: Doing just preprocessing to obtain a correct preprocessed shader string
// is not an officially supported or fully working path.
GLSLANG_EXPORT bool preprocess(
bool preprocess(
const TBuiltInResource* builtInResources, int defaultVersion,
EProfile defaultProfile, bool forceDefaultVersionAndProfile,
bool forwardCompatible, EShMessages message, std::string* outputString,
Includer& includer);
GLSLANG_EXPORT const char* getInfoLog();
GLSLANG_EXPORT const char* getInfoDebugLog();
const char* getInfoLog();
const char* getInfoDebugLog();
EShLanguage getStage() const { return stage; }
TIntermediate* getIntermediate() const { return intermediate; }
@ -736,15 +747,17 @@ private:
//
// Data needed for just a single object at the granularity exchanged by the reflection API
class TObjectReflection {
class GLSLANG_EXPORT TObjectReflection {
public:
GLSLANG_EXPORT TObjectReflection(const std::string& pName, const TType& pType, int pOffset, int pGLDefineType, int pSize, int pIndex);
TObjectReflection(const std::string& pName, const TType& pType, int pOffset, int pGLDefineType, int pSize, int pIndex);
const TType* getType() const { return type; }
GLSLANG_EXPORT int getBinding() const;
GLSLANG_EXPORT void dump() const;
int getBinding() const;
void dump() const;
static TObjectReflection badReflection() { return TObjectReflection(); }
unsigned int layoutLocation() const;
std::string name;
int offset;
int glDefineType;
@ -794,8 +807,7 @@ struct TVarEntryInfo;
//
// NOTE: that still limit checks are applied to bindings and sets
// and may result in an error.
class TIoMapResolver
{
class GLSLANG_EXPORT TIoMapResolver {
public:
virtual ~TIoMapResolver() {}
@ -847,46 +859,61 @@ public:
virtual void addStage(EShLanguage stage, TIntermediate& stageIntermediate) = 0;
};
// I/O mapper
class TIoMapper {
public:
TIoMapper() {}
virtual ~TIoMapper() {}
// grow the reflection stage by stage
bool virtual addStage(EShLanguage, TIntermediate&, TInfoSink&, TIoMapResolver*);
bool virtual doMap(TIoMapResolver*, TInfoSink&) { return true; }
bool virtual setAutoPushConstantBlock(const char*, unsigned int, TLayoutPacking) { return false; }
};
// Get the default GLSL IO mapper
GLSLANG_EXPORT TIoMapper* GetGlslIoMapper();
// Make one TProgram per set of shaders that will get linked together. Add all
// the shaders that are to be linked together. After calling shader.parse()
// for all shaders, call link().
//
// N.B.: Destruct a linked program *before* destructing the shaders linked into it.
//
class TProgram {
class GLSLANG_EXPORT TProgram {
public:
GLSLANG_EXPORT TProgram();
GLSLANG_EXPORT virtual ~TProgram();
TProgram();
virtual ~TProgram();
void addShader(TShader* shader) { stages[shader->stage].push_back(shader); }
std::list<TShader*>& getShaders(EShLanguage stage) { return stages[stage]; }
// Link Validation interface
GLSLANG_EXPORT bool link(EShMessages);
GLSLANG_EXPORT const char* getInfoLog();
GLSLANG_EXPORT const char* getInfoDebugLog();
bool link(EShMessages);
const char* getInfoLog();
const char* getInfoDebugLog();
TIntermediate* getIntermediate(EShLanguage stage) const { return intermediate[stage]; }
// Reflection Interface
// call first, to do liveness analysis, index mapping, etc.; returns false on failure
GLSLANG_EXPORT bool buildReflection(int opts = EShReflectionDefault);
GLSLANG_EXPORT unsigned getLocalSize(int dim) const; // return dim'th local size
GLSLANG_EXPORT int getReflectionIndex(const char *name) const;
GLSLANG_EXPORT int getReflectionPipeIOIndex(const char* name, const bool inOrOut) const;
GLSLANG_EXPORT int getNumUniformVariables() const;
GLSLANG_EXPORT const TObjectReflection& getUniform(int index) const;
GLSLANG_EXPORT int getNumUniformBlocks() const;
GLSLANG_EXPORT const TObjectReflection& getUniformBlock(int index) const;
GLSLANG_EXPORT int getNumPipeInputs() const;
GLSLANG_EXPORT const TObjectReflection& getPipeInput(int index) const;
GLSLANG_EXPORT int getNumPipeOutputs() const;
GLSLANG_EXPORT const TObjectReflection& getPipeOutput(int index) const;
GLSLANG_EXPORT int getNumBufferVariables() const;
GLSLANG_EXPORT const TObjectReflection& getBufferVariable(int index) const;
GLSLANG_EXPORT int getNumBufferBlocks() const;
GLSLANG_EXPORT const TObjectReflection& getBufferBlock(int index) const;
GLSLANG_EXPORT int getNumAtomicCounters() const;
GLSLANG_EXPORT const TObjectReflection& getAtomicCounter(int index) const;
bool buildReflection(int opts = EShReflectionDefault);
unsigned getLocalSize(int dim) const; // return dim'th local size
unsigned getTileShadingRateQCOM(int dim) const; // return dim'th tile shading rate QCOM
int getReflectionIndex(const char *name) const;
int getReflectionPipeIOIndex(const char* name, const bool inOrOut) const;
int getNumUniformVariables() const;
const TObjectReflection& getUniform(int index) const;
int getNumUniformBlocks() const;
const TObjectReflection& getUniformBlock(int index) const;
int getNumPipeInputs() const;
const TObjectReflection& getPipeInput(int index) const;
int getNumPipeOutputs() const;
const TObjectReflection& getPipeOutput(int index) const;
int getNumBufferVariables() const;
const TObjectReflection& getBufferVariable(int index) const;
int getNumBufferBlocks() const;
const TObjectReflection& getBufferBlock(int index) const;
int getNumAtomicCounters() const;
const TObjectReflection& getAtomicCounter(int index) const;
// Legacy Reflection Interface - expressed in terms of above interface
@ -953,15 +980,19 @@ public:
// returns a TType*
const TType *getAttributeTType(int index) const { return getPipeInput(index).getType(); }
GLSLANG_EXPORT void dumpReflection();
void dumpReflection();
// Get the IO resolver to use for mapIO
TIoMapResolver* getGlslIoResolver(EShLanguage stage);
// I/O mapping: apply base offsets and map live unbound variables
// If resolver is not provided it uses the previous approach
// and respects auto assignment and offsets.
GLSLANG_EXPORT bool mapIO(TIoMapResolver* pResolver = nullptr, TIoMapper* pIoMapper = nullptr);
bool mapIO(TIoMapResolver* pResolver = nullptr, TIoMapper* pIoMapper = nullptr);
protected:
GLSLANG_EXPORT bool linkStage(EShLanguage, EShMessages);
GLSLANG_EXPORT bool crossStageCheck(EShMessages);
bool linkStage(EShLanguage, EShMessages);
bool crossStageCheck(EShMessages);
TPoolAllocator* pool;
std::list<TShader*> stages[EShLangCount];

View file

@ -39,9 +39,9 @@
#include "glslang/Public/ResourceLimits.h"
TBuiltInResource Resources;
static TBuiltInResource Resources;
const TBuiltInResource DefaultTBuiltInResource = {
static const TBuiltInResource DefaultTBuiltInResource = {
/* .MaxLights = */ 32,
/* .MaxClipPlanes = */ 6,
/* .MaxTextureUnits = */ 32,

View file

@ -34,8 +34,8 @@
#ifndef GLSLANG_BUILD_INFO
#define GLSLANG_BUILD_INFO
#define GLSLANG_VERSION_MAJOR 14
#define GLSLANG_VERSION_MINOR 2
#define GLSLANG_VERSION_MAJOR 16
#define GLSLANG_VERSION_MINOR 1
#define GLSLANG_VERSION_PATCH 0
#define GLSLANG_VERSION_FLAVOR ""

View file

@ -1,5 +1,5 @@
diff --git a/thirdparty/glslang/glslang/Include/InfoSink.h b/thirdparty/glslang/glslang/Include/InfoSink.h
index 23f495dcb7..137ede8510 100644
index 262933941d..dec05e651c 100644
--- a/thirdparty/glslang/glslang/Include/InfoSink.h
+++ b/thirdparty/glslang/glslang/Include/InfoSink.h
@@ -36,7 +36,7 @@
@ -11,8 +11,8 @@ index 23f495dcb7..137ede8510 100644
#include <cmath>
namespace glslang {
@@ -101,14 +101,14 @@ public:
snprintf(locText, maxSize, ":%d", loc.line);
@@ -105,14 +105,14 @@ public:
}
if(loc.getFilename() == nullptr && shaderFileName != nullptr && absolute) {
- append(std::filesystem::absolute(shaderFileName).string());

View file

@ -1,12 +0,0 @@
diff --git a/thirdparty/glslang/SPIRV/SpvBuilder.h b/thirdparty/glslang/SPIRV/SpvBuilder.h
index a65a98e337..1499592c4f 100644
--- a/thirdparty/glslang/SPIRV/SpvBuilder.h
+++ b/thirdparty/glslang/SPIRV/SpvBuilder.h
@@ -56,6 +56,7 @@ namespace spv {
}
#include <algorithm>
+#include <cstdint>
#include <map>
#include <memory>
#include <set>

View file

@ -81,31 +81,105 @@ bool CFG::is_back_edge(uint32_t to) const
// We have a back edge if the visit order is set with the temporary magic value 0.
// Crossing edges will have already been recorded with a visit order.
auto itr = visit_order.find(to);
return itr != end(visit_order) && itr->second.get() == 0;
return itr != end(visit_order) && itr->second.visited_branches && !itr->second.visited_resolve;
}
bool CFG::has_visited_forward_edge(uint32_t to) const
bool CFG::has_visited_branch(uint32_t to) const
{
// If > 0, we have visited the edge already, and this is not a back edge branch.
auto itr = visit_order.find(to);
return itr != end(visit_order) && itr->second.get() > 0;
return itr != end(visit_order) && itr->second.visited_branches;
}
bool CFG::post_order_visit(uint32_t block_id)
void CFG::post_order_visit_entry(uint32_t block)
{
// If we have already branched to this block (back edge), stop recursion.
// If our branches are back-edges, we do not record them.
// We have to record crossing edges however.
if (has_visited_forward_edge(block_id))
return true;
else if (is_back_edge(block_id))
return false;
visit_stack.push_back(block);
// Block back-edges from recursively revisiting ourselves.
visit_order[block_id].get() = 0;
while (!visit_stack.empty())
{
bool keep_iterating;
do
{
// Reverse the order to allow for stack-like behavior and preserves the visit order from recursive algorithm.
// Traverse depth first.
uint32_t to_visit = visit_stack.back();
last_visited_size = visit_stack.size();
post_order_visit_branches(to_visit);
keep_iterating = last_visited_size != visit_stack.size();
if (keep_iterating)
std::reverse(visit_stack.begin() + last_visited_size, visit_stack.end());
} while (keep_iterating);
// We've reached the end of some tree leaf. Resolve the stack.
// Any node which has been visited for real can be popped now.
while (!visit_stack.empty() && visit_order[visit_stack.back()].visited_branches)
{
post_order_visit_resolve(visit_stack.back());
visit_stack.pop_back();
}
}
}
void CFG::visit_branch(uint32_t block_id)
{
// Prune obvious duplicates.
if (std::find(visit_stack.begin() + last_visited_size, visit_stack.end(), block_id) == visit_stack.end() &&
!has_visited_branch(block_id))
{
visit_stack.push_back(block_id);
}
}
void CFG::post_order_visit_branches(uint32_t block_id)
{
auto &block = compiler.get<SPIRBlock>(block_id);
auto &visit = visit_order[block_id];
if (visit.visited_branches)
return;
visit.visited_branches = true;
if (block.merge == SPIRBlock::MergeLoop)
visit_branch(block.merge_block);
else if (block.merge == SPIRBlock::MergeSelection)
visit_branch(block.next_block);
// First visit our branch targets.
switch (block.terminator)
{
case SPIRBlock::Direct:
visit_branch(block.next_block);
break;
case SPIRBlock::Select:
visit_branch(block.true_block);
visit_branch(block.false_block);
break;
case SPIRBlock::MultiSelect:
{
const auto &cases = compiler.get_case_list(block);
for (const auto &target : cases)
visit_branch(target.block);
if (block.default_block)
visit_branch(block.default_block);
break;
}
default:
break;
}
}
void CFG::post_order_visit_resolve(uint32_t block_id)
{
auto &block = compiler.get<SPIRBlock>(block_id);
auto &visit_block = visit_order[block_id];
assert(visit_block.visited_branches);
auto &visited = visit_order[block_id].visited_resolve;
if (visited)
return;
// If this is a loop header, add an implied branch to the merge target.
// This is needed to avoid annoying cases with do { ... } while(false) loops often generated by inliners.
// To the CFG, this is linear control flow, but we risk picking the do/while scope as our dominating block.
@ -116,21 +190,21 @@ bool CFG::post_order_visit(uint32_t block_id)
// is lower than inside the loop, which is going to be key for some traversal algorithms like post-dominance analysis.
// For selection constructs true/false blocks will end up visiting the merge block directly and it works out fine,
// but for loops, only the header might end up actually branching to merge block.
if (block.merge == SPIRBlock::MergeLoop && post_order_visit(block.merge_block))
if (block.merge == SPIRBlock::MergeLoop && !is_back_edge(block.merge_block))
add_branch(block_id, block.merge_block);
// First visit our branch targets.
switch (block.terminator)
{
case SPIRBlock::Direct:
if (post_order_visit(block.next_block))
if (!is_back_edge(block.next_block))
add_branch(block_id, block.next_block);
break;
case SPIRBlock::Select:
if (post_order_visit(block.true_block))
if (!is_back_edge(block.true_block))
add_branch(block_id, block.true_block);
if (post_order_visit(block.false_block))
if (!is_back_edge(block.false_block))
add_branch(block_id, block.false_block);
break;
@ -139,10 +213,10 @@ bool CFG::post_order_visit(uint32_t block_id)
const auto &cases = compiler.get_case_list(block);
for (const auto &target : cases)
{
if (post_order_visit(target.block))
if (!is_back_edge(target.block))
add_branch(block_id, target.block);
}
if (block.default_block && post_order_visit(block.default_block))
if (block.default_block && !is_back_edge(block.default_block))
add_branch(block_id, block.default_block);
break;
}
@ -157,7 +231,7 @@ bool CFG::post_order_visit(uint32_t block_id)
// We can use the variable without a Phi since there is only one possible parent here.
// However, in this case, we need to hoist out the inner variable to outside the branch.
// Use same strategy as loops.
if (block.merge == SPIRBlock::MergeSelection && post_order_visit(block.next_block))
if (block.merge == SPIRBlock::MergeSelection && !is_back_edge(block.next_block))
{
// If there is only one preceding edge to the merge block and it's not ourselves, we need a fixup.
// Add a fake branch so any dominator in either the if (), or else () block, or a lone case statement
@ -201,10 +275,9 @@ bool CFG::post_order_visit(uint32_t block_id)
}
}
// Then visit ourselves. Start counting at one, to let 0 be a magic value for testing back vs. crossing edges.
visit_order[block_id].get() = ++visit_count;
visited = true;
visit_block.order = ++visit_count;
post_order.push_back(block_id);
return true;
}
void CFG::build_post_order_visit_order()
@ -213,11 +286,12 @@ void CFG::build_post_order_visit_order()
visit_count = 0;
visit_order.clear();
post_order.clear();
post_order_visit(block);
post_order_visit_entry(block);
}
void CFG::add_branch(uint32_t from, uint32_t to)
{
assert(from && to);
const auto add_unique = [](SmallVector<uint32_t> &l, uint32_t value) {
auto itr = find(begin(l), end(l), value);
if (itr == end(l))

View file

@ -68,7 +68,7 @@ public:
{
auto itr = visit_order.find(block);
assert(itr != std::end(visit_order));
int v = itr->second.get();
int v = itr->second.order;
assert(v > 0);
return uint32_t(v);
}
@ -114,17 +114,9 @@ public:
private:
struct VisitOrder
{
int &get()
{
return v;
}
const int &get() const
{
return v;
}
int v = -1;
int order = -1;
bool visited_resolve = false;
bool visited_branches = false;
};
Compiler &compiler;
@ -139,11 +131,17 @@ private:
void add_branch(uint32_t from, uint32_t to);
void build_post_order_visit_order();
void build_immediate_dominators();
bool post_order_visit(uint32_t block);
void post_order_visit_branches(uint32_t block);
void post_order_visit_resolve(uint32_t block);
void post_order_visit_entry(uint32_t block);
uint32_t visit_count = 0;
bool is_back_edge(uint32_t to) const;
bool has_visited_forward_edge(uint32_t to) const;
bool has_visited_branch(uint32_t to) const;
void visit_branch(uint32_t block_id);
SmallVector<uint32_t> visit_stack;
size_t last_visited_size = 0;
};
class DominatorBuilder

View file

@ -27,8 +27,17 @@
#ifndef SPV_ENABLE_UTILITY_CODE
#define SPV_ENABLE_UTILITY_CODE
#endif
#include "spirv.hpp"
// Pragmatic hack to avoid symbol conflicts when including both hpp11 and hpp headers in same translation unit.
// This is an unfortunate SPIRV-Headers issue that we cannot easily deal with ourselves.
#ifdef SPIRV_CROSS_SPV_HEADER_NAMESPACE_OVERRIDE
#define spv SPIRV_CROSS_SPV_HEADER_NAMESPACE_OVERRIDE
#define SPIRV_CROSS_SPV_HEADER_NAMESPACE SPIRV_CROSS_SPV_HEADER_NAMESPACE_OVERRIDE
#else
#define SPIRV_CROSS_SPV_HEADER_NAMESPACE spv
#endif
#include "spirv.hpp"
#include "spirv_cross_containers.hpp"
#include "spirv_cross_error_handling.hpp"
#include <functional>
@ -574,6 +583,7 @@ struct SPIRType : IVariant
Sampler,
AccelerationStructure,
RayQuery,
CoopVecNV,
// Keep internal types at the end.
ControlPointArray,
@ -583,7 +593,9 @@ struct SPIRType : IVariant
MeshGridProperties,
BFloat16,
FloatE4M3,
FloatE5M2
FloatE5M2,
Tensor
};
// Scalar/vector/matrix support.
@ -608,13 +620,29 @@ struct SPIRType : IVariant
bool pointer = false;
bool forward_pointer = false;
struct
union
{
uint32_t use_id = 0;
uint32_t rows_id = 0;
uint32_t columns_id = 0;
uint32_t scope_id = 0;
} cooperative;
struct
{
uint32_t use_id;
uint32_t rows_id;
uint32_t columns_id;
uint32_t scope_id;
} cooperative;
struct
{
uint32_t component_type_id;
uint32_t component_count_id;
} coopVecNV;
struct
{
uint32_t type;
uint32_t rank;
uint32_t shape;
} tensor;
} ext;
spv::StorageClass storage = spv::StorageClassGeneric;
@ -672,6 +700,12 @@ struct SPIRExtension : IVariant
NonSemanticGeneric
};
enum ShaderDebugInfoOps
{
DebugLine = 103,
DebugSource = 35
};
explicit SPIRExtension(Extension ext_)
: ext(ext_)
{
@ -698,6 +732,10 @@ struct SPIREntryPoint
std::string name;
std::string orig_name;
std::unordered_map<uint32_t, uint32_t> fp_fast_math_defaults;
bool signed_zero_inf_nan_preserve_8 = false;
bool signed_zero_inf_nan_preserve_16 = false;
bool signed_zero_inf_nan_preserve_32 = false;
bool signed_zero_inf_nan_preserve_64 = false;
SmallVector<VariableID> interface_variables;
Bitset flags;
@ -930,6 +968,7 @@ struct SPIRBlock : IVariant
// All access to these variables are dominated by this block,
// so before branching anywhere we need to make sure that we declare these variables.
SmallVector<VariableID> dominated_variables;
SmallVector<bool> rearm_dominated_variables;
// These are variables which should be declared in a for loop header, if we
// fail to use a classic for-loop,
@ -1825,7 +1864,8 @@ private:
static inline bool type_is_floating_point(const SPIRType &type)
{
return type.basetype == SPIRType::Half || type.basetype == SPIRType::Float || type.basetype == SPIRType::Double;
return type.basetype == SPIRType::Half || type.basetype == SPIRType::Float || type.basetype == SPIRType::Double ||
type.basetype == SPIRType::BFloat16 || type.basetype == SPIRType::FloatE5M2 || type.basetype == SPIRType::FloatE4M3;
}
static inline bool type_is_integral(const SPIRType &type)
@ -2010,4 +2050,7 @@ struct hash<SPIRV_CROSS_NAMESPACE::TypedID<type>>
};
} // namespace std
#ifdef SPIRV_CROSS_SPV_HEADER_NAMESPACE_OVERRIDE
#undef spv
#endif
#endif

View file

@ -31,7 +31,7 @@
#include <utility>
using namespace std;
using namespace spv;
using namespace SPIRV_CROSS_SPV_HEADER_NAMESPACE;
using namespace SPIRV_CROSS_NAMESPACE;
Compiler::Compiler(vector<uint32_t> ir_)
@ -280,6 +280,9 @@ bool Compiler::block_is_pure(const SPIRBlock &block)
// This is a global side effect of the function.
return false;
case OpTensorReadARM:
return false;
case OpExtInst:
{
uint32_t extension_set = ops[2];
@ -373,6 +376,7 @@ void Compiler::register_global_read_dependencies(const SPIRBlock &block, uint32_
case OpLoad:
case OpCooperativeMatrixLoadKHR:
case OpCooperativeVectorLoadNV:
case OpImageRead:
{
// If we're in a storage class which does not get invalidated, adding dependencies here is no big deal.
@ -624,7 +628,7 @@ bool Compiler::is_immutable(uint32_t id) const
return false;
}
static inline bool storage_class_is_interface(spv::StorageClass storage)
static inline bool storage_class_is_interface(StorageClass storage)
{
switch (storage)
{
@ -657,8 +661,8 @@ bool Compiler::is_hidden_variable(const SPIRVariable &var, bool include_builtins
// In SPIR-V 1.4 and up we must also use the active variable interface to disable global variables
// which are not part of the entry point.
if (ir.get_spirv_version() >= 0x10400 && var.storage != spv::StorageClassGeneric &&
var.storage != spv::StorageClassFunction && !interface_variable_exists_in_entry_point(var.self))
if (ir.get_spirv_version() >= 0x10400 && var.storage != StorageClassGeneric &&
var.storage != StorageClassFunction && !interface_variable_exists_in_entry_point(var.self))
{
return true;
}
@ -738,6 +742,14 @@ bool Compiler::is_physical_pointer(const SPIRType &type) const
return type.op == OpTypePointer && type.storage == StorageClassPhysicalStorageBuffer;
}
bool Compiler::is_physical_or_buffer_pointer(const SPIRType &type) const
{
return type.op == OpTypePointer &&
(type.storage == StorageClassPhysicalStorageBuffer || type.storage == StorageClassUniform ||
type.storage == StorageClassStorageBuffer || type.storage == StorageClassWorkgroup ||
type.storage == StorageClassPushConstant);
}
bool Compiler::is_physical_pointer_to_buffer_block(const SPIRType &type) const
{
return is_physical_pointer(type) && get_pointee_type(type).self == type.parent_type &&
@ -1152,6 +1164,11 @@ ShaderResources Compiler::get_shader_resources(const unordered_set<VariableID> *
{
res.acceleration_structures.push_back({ var.self, var.basetype, type.self, get_name(var.self) });
}
// Tensors
else if (type.basetype == SPIRType::Tensor)
{
res.tensors.push_back({ var.self, var.basetype, type.self, get_name(var.self) });
}
else
{
res.gl_plain_uniforms.push_back({ var.self, var.basetype, type.self, get_name(var.self) });
@ -1169,11 +1186,8 @@ bool Compiler::type_is_top_level_block(const SPIRType &type) const
return has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock);
}
bool Compiler::type_is_block_like(const SPIRType &type) const
bool Compiler::type_is_explicit_layout(const SPIRType &type) const
{
if (type_is_top_level_block(type))
return true;
if (type.basetype == SPIRType::Struct)
{
// Block-like types may have Offset decorations.
@ -1185,6 +1199,14 @@ bool Compiler::type_is_block_like(const SPIRType &type) const
return false;
}
bool Compiler::type_is_block_like(const SPIRType &type) const
{
if (type_is_top_level_block(type))
return true;
else
return type_is_explicit_layout(type);
}
void Compiler::parse_fixup()
{
// Figure out specialization constants for work group sizes.
@ -1327,7 +1349,7 @@ const SPIRType &Compiler::get_pointee_type(uint32_t type_id) const
uint32_t Compiler::get_variable_data_type_id(const SPIRVariable &var) const
{
if (var.phi_variable || var.storage == spv::StorageClass::StorageClassAtomicCounter)
if (var.phi_variable || var.storage == StorageClassAtomicCounter)
return var.basetype;
return get_pointee_type_id(var.basetype);
}
@ -1364,7 +1386,7 @@ bool Compiler::is_sampled_image_type(const SPIRType &type)
type.image.dim != DimBuffer;
}
void Compiler::set_member_decoration_string(TypeID id, uint32_t index, spv::Decoration decoration,
void Compiler::set_member_decoration_string(TypeID id, uint32_t index, Decoration decoration,
const std::string &argument)
{
ir.set_member_decoration_string(id, index, decoration, argument);
@ -1425,7 +1447,7 @@ void Compiler::unset_member_decoration(TypeID id, uint32_t index, Decoration dec
ir.unset_member_decoration(id, index, decoration);
}
void Compiler::set_decoration_string(ID id, spv::Decoration decoration, const std::string &argument)
void Compiler::set_decoration_string(ID id, Decoration decoration, const std::string &argument)
{
ir.set_decoration_string(id, decoration, argument);
}
@ -1588,7 +1610,7 @@ void Compiler::unset_decoration(ID id, Decoration decoration)
ir.unset_decoration(id, decoration);
}
bool Compiler::get_binary_offset_for_decoration(VariableID id, spv::Decoration decoration, uint32_t &word_offset) const
bool Compiler::get_binary_offset_for_decoration(VariableID id, Decoration decoration, uint32_t &word_offset) const
{
auto *m = ir.find_meta(id);
if (!m)
@ -1893,6 +1915,15 @@ bool Compiler::traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHand
handler.set_current_block(block);
handler.rearm_current_block(block);
if (handler.enable_result_types)
{
for (auto &phi: block.phi_variables)
{
auto &v = get<SPIRVariable>(phi.function_variable);
handler.result_types[phi.function_variable] = v.basetype;
}
}
// Ideally, perhaps traverse the CFG instead of all blocks in order to eliminate dead blocks,
// but this shouldn't be a problem in practice unless the SPIR-V is doing insane things like recursing
// inside dead blocks ...
@ -1904,11 +1935,24 @@ bool Compiler::traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHand
if (!handler.handle(op, ops, i.length))
return false;
if (handler.enable_result_types)
{
// If it has one, keep track of the instruction's result type, mapped by ID
uint32_t result_type, result_id;
if (instruction_to_result_type(result_type, result_id, op, ops, i.length))
handler.result_types[result_id] = result_type;
}
if (op == OpFunctionCall)
{
auto &func = get<SPIRFunction>(ops[2]);
if (handler.follow_function_call(func))
{
if (handler.enable_result_types)
for (auto &arg : func.arguments)
if (!arg.alias_global_variable)
handler.result_types[arg.id] = arg.type;
if (!handler.begin_function_scope(ops, i.length))
return false;
if (!traverse_all_reachable_opcodes(get<SPIRFunction>(ops[2]), handler))
@ -2443,7 +2487,7 @@ uint32_t Compiler::get_work_group_size_specialization_constants(SpecializationCo
return execution.workgroup_size.constant;
}
uint32_t Compiler::get_execution_mode_argument(spv::ExecutionMode mode, uint32_t index) const
uint32_t Compiler::get_execution_mode_argument(ExecutionMode mode, uint32_t index) const
{
auto &execution = get_entry_point();
switch (mode)
@ -2629,14 +2673,14 @@ SmallVector<EntryPoint> Compiler::get_entry_points_and_stages() const
return entries;
}
void Compiler::rename_entry_point(const std::string &old_name, const std::string &new_name, spv::ExecutionModel model)
void Compiler::rename_entry_point(const std::string &old_name, const std::string &new_name, ExecutionModel model)
{
auto &entry = get_entry_point(old_name, model);
entry.orig_name = new_name;
entry.name = new_name;
}
void Compiler::set_entry_point(const std::string &name, spv::ExecutionModel model)
void Compiler::set_entry_point(const std::string &name, ExecutionModel model)
{
auto &entry = get_entry_point(name, model);
ir.default_entry_point = entry.self;
@ -3332,7 +3376,7 @@ void Compiler::analyze_parameter_preservation(
Compiler::AnalyzeVariableScopeAccessHandler::AnalyzeVariableScopeAccessHandler(Compiler &compiler_,
SPIRFunction &entry_)
: compiler(compiler_)
: OpcodeHandler(compiler_)
, entry(entry_)
{
}
@ -3450,11 +3494,11 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle_terminator(const SPIRBl
return true;
}
bool Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op op, const uint32_t *args, uint32_t length)
bool Compiler::AnalyzeVariableScopeAccessHandler::handle(Op op, const uint32_t *args, uint32_t length)
{
// Keep track of the types of temporaries, so we can hoist them out as necessary.
uint32_t result_type = 0, result_id = 0;
if (compiler.instruction_to_result_type(result_type, result_id, op, args, length))
if (instruction_to_result_type(result_type, result_id, op, args, length))
{
// For some opcodes, we will need to override the result id.
// If we need to hoist the temporary, the temporary type is the input, not the result.
@ -3797,7 +3841,7 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op op, const uint3
}
Compiler::StaticExpressionAccessHandler::StaticExpressionAccessHandler(Compiler &compiler_, uint32_t variable_id_)
: compiler(compiler_)
: OpcodeHandler(compiler_)
, variable_id(variable_id_)
{
}
@ -3807,7 +3851,7 @@ bool Compiler::StaticExpressionAccessHandler::follow_function_call(const SPIRFun
return false;
}
bool Compiler::StaticExpressionAccessHandler::handle(spv::Op op, const uint32_t *args, uint32_t length)
bool Compiler::StaticExpressionAccessHandler::handle(Op op, const uint32_t *args, uint32_t length)
{
switch (op)
{
@ -4338,6 +4382,7 @@ bool Compiler::may_read_undefined_variable_in_block(const SPIRBlock &block, uint
case OpCopyObject:
case OpLoad:
case OpCooperativeVectorLoadNV:
case OpCooperativeMatrixLoadKHR:
if (ops[2] == var)
return true;
@ -4366,7 +4411,7 @@ bool Compiler::may_read_undefined_variable_in_block(const SPIRBlock &block, uint
return true;
}
bool Compiler::GeometryEmitDisocveryHandler::handle(spv::Op opcode, const uint32_t *, uint32_t)
bool Compiler::GeometryEmitDisocveryHandler::handle(Op opcode, const uint32_t *, uint32_t)
{
if (opcode == OpEmitVertex || opcode == OpEndPrimitive)
{
@ -4384,8 +4429,9 @@ bool Compiler::GeometryEmitDisocveryHandler::begin_function_scope(const uint32_t
return true;
}
bool Compiler::GeometryEmitDisocveryHandler::end_function_scope([[maybe_unused]] const uint32_t *stream, uint32_t)
bool Compiler::GeometryEmitDisocveryHandler::end_function_scope(const uint32_t *stream, uint32_t)
{
(void)stream;
assert(function_stack.back() == &compiler.get<SPIRFunction>(stream[2]));
function_stack.pop_back();
@ -4506,7 +4552,7 @@ void Compiler::ActiveBuiltinHandler::add_if_builtin_or_block(uint32_t id)
add_if_builtin(id, true);
}
bool Compiler::ActiveBuiltinHandler::handle(spv::Op opcode, const uint32_t *args, uint32_t length)
bool Compiler::ActiveBuiltinHandler::handle(Op opcode, const uint32_t *args, uint32_t length)
{
switch (opcode)
{
@ -4701,7 +4747,7 @@ void Compiler::analyze_image_and_sampler_usage()
comparison_ids.insert(combined.combined_id);
}
bool Compiler::CombinedImageSamplerDrefHandler::handle(spv::Op opcode, const uint32_t *args, uint32_t)
bool Compiler::CombinedImageSamplerDrefHandler::handle(Op opcode, const uint32_t *args, uint32_t)
{
// Mark all sampled images which are used with Dref.
switch (opcode)
@ -4810,11 +4856,11 @@ void Compiler::build_function_control_flow_graphs_and_analyze()
}
Compiler::CFGBuilder::CFGBuilder(Compiler &compiler_)
: compiler(compiler_)
: OpcodeHandler(compiler_)
{
}
bool Compiler::CFGBuilder::handle(spv::Op, const uint32_t *, uint32_t)
bool Compiler::CFGBuilder::handle(Op, const uint32_t *, uint32_t)
{
return true;
}
@ -4990,7 +5036,7 @@ void Compiler::make_constant_null(uint32_t id, uint32_t type)
}
}
const SmallVector<spv::Capability> &Compiler::get_declared_capabilities() const
const SmallVector<Capability> &Compiler::get_declared_capabilities() const
{
return ir.declared_capabilities;
}
@ -5065,7 +5111,7 @@ bool Compiler::reflection_ssbo_instance_name_is_significant() const
return aliased_ssbo_types;
}
bool Compiler::instruction_to_result_type(uint32_t &result_type, uint32_t &result_id, spv::Op op,
bool Compiler::instruction_to_result_type(uint32_t &result_type, uint32_t &result_id, Op op,
const uint32_t *args, uint32_t length)
{
if (length < 2)
@ -5112,7 +5158,7 @@ Bitset Compiler::combined_decoration_for_member(const SPIRType &type, uint32_t i
return flags;
}
bool Compiler::is_desktop_only_format(spv::ImageFormat format)
bool Compiler::is_desktop_only_format(ImageFormat format)
{
switch (format)
{
@ -5155,7 +5201,7 @@ bool Compiler::is_depth_image(const SPIRType &type, uint32_t id) const
bool Compiler::type_is_opaque_value(const SPIRType &type) const
{
return !type.pointer && (type.basetype == SPIRType::SampledImage || type.basetype == SPIRType::Image ||
type.basetype == SPIRType::Sampler);
type.basetype == SPIRType::Sampler || type.basetype == SPIRType::Tensor);
}
// Make these member functions so we can easily break on any force_recompile events.
@ -5182,7 +5228,7 @@ void Compiler::clear_force_recompile()
}
Compiler::PhysicalStorageBufferPointerHandler::PhysicalStorageBufferPointerHandler(Compiler &compiler_)
: compiler(compiler_)
: OpcodeHandler(compiler_)
{
}
@ -5231,7 +5277,7 @@ bool Compiler::PhysicalStorageBufferPointerHandler::type_is_bda_block_entry(uint
uint32_t Compiler::PhysicalStorageBufferPointerHandler::get_minimum_scalar_alignment(const SPIRType &type) const
{
if (type.storage == spv::StorageClassPhysicalStorageBuffer)
if (type.storage == StorageClassPhysicalStorageBuffer)
return 8;
else if (type.basetype == SPIRType::Struct)
{
@ -5473,6 +5519,7 @@ bool Compiler::InterlockedResourceAccessHandler::handle(Op opcode, const uint32_
{
case OpLoad:
case OpCooperativeMatrixLoadKHR:
case OpCooperativeVectorLoadNV:
{
if (length < 3)
return false;
@ -5551,6 +5598,7 @@ bool Compiler::InterlockedResourceAccessHandler::handle(Op opcode, const uint32_
case OpImageWrite:
case OpAtomicStore:
case OpCooperativeMatrixStoreKHR:
case OpCooperativeVectorStoreNV:
{
if (length < 1)
return false;
@ -5747,3 +5795,13 @@ void Compiler::add_loop_level()
{
current_loop_level++;
}
const SPIRType *Compiler::OpcodeHandler::get_expression_result_type(uint32_t id) const
{
auto itr = result_types.find(id);
if (itr == result_types.end())
return nullptr;
return &compiler.get<SPIRType>(itr->second);
}

View file

@ -27,12 +27,20 @@
#ifndef SPV_ENABLE_UTILITY_CODE
#define SPV_ENABLE_UTILITY_CODE
#endif
// Pragmatic hack to avoid symbol conflicts when including both hpp11 and hpp headers in same translation unit.
// This is an unfortunate SPIRV-Headers issue that we cannot easily deal with ourselves.
#ifdef SPIRV_CROSS_SPV_HEADER_NAMESPACE_OVERRIDE
#define spv SPIRV_CROSS_SPV_HEADER_NAMESPACE_OVERRIDE
#endif
#include "spirv.hpp"
#include "spirv_cfg.hpp"
#include "spirv_cross_parsed_ir.hpp"
namespace SPIRV_CROSS_NAMESPACE
{
using namespace SPIRV_CROSS_SPV_HEADER_NAMESPACE;
struct Resource
{
// Resources are identified with their SPIR-V ID.
@ -69,7 +77,7 @@ struct BuiltInResource
// A builtin present here does not necessarily mean it's considered an active builtin,
// since variable ID "activeness" is only tracked on OpVariable level, not Block members.
// For that, update_active_builtins() -> has_active_builtin() can be used to further refine the reflection.
spv::BuiltIn builtin;
BuiltIn builtin;
// This is the actual value type of the builtin.
// Typically float4, float, array<float, N> for the gl_PerVertex builtins.
@ -95,6 +103,7 @@ struct ShaderResources
SmallVector<Resource> atomic_counters;
SmallVector<Resource> acceleration_structures;
SmallVector<Resource> gl_plain_uniforms;
SmallVector<Resource> tensors;
// There can only be one push constant block,
// but keep the vector in case this restriction is lifted in the future.
@ -151,7 +160,7 @@ enum BufferPackingStandard
struct EntryPoint
{
std::string name;
spv::ExecutionModel execution_model;
ExecutionModel execution_model;
};
class Compiler
@ -182,8 +191,8 @@ public:
const std::string &get_name(ID id) const;
// Applies a decoration to an ID. Effectively injects OpDecorate.
void set_decoration(ID id, spv::Decoration decoration, uint32_t argument = 0);
void set_decoration_string(ID id, spv::Decoration decoration, const std::string &argument);
void set_decoration(ID id, Decoration decoration, uint32_t argument = 0);
void set_decoration_string(ID id, Decoration decoration, const std::string &argument);
// Overrides the identifier OpName of an ID.
// Identifiers beginning with underscores or identifiers which contain double underscores
@ -191,22 +200,22 @@ public:
void set_name(ID id, const std::string &name);
// Gets a bitmask for the decorations which are applied to ID.
// I.e. (1ull << spv::DecorationFoo) | (1ull << spv::DecorationBar)
// I.e. (1ull << DecorationFoo) | (1ull << DecorationBar)
const Bitset &get_decoration_bitset(ID id) const;
// Returns whether the decoration has been applied to the ID.
bool has_decoration(ID id, spv::Decoration decoration) const;
bool has_decoration(ID id, Decoration decoration) const;
// Gets the value for decorations which take arguments.
// If the decoration is a boolean (i.e. spv::DecorationNonWritable),
// If the decoration is a boolean (i.e. DecorationNonWritable),
// 1 will be returned.
// If decoration doesn't exist or decoration is not recognized,
// 0 will be returned.
uint32_t get_decoration(ID id, spv::Decoration decoration) const;
const std::string &get_decoration_string(ID id, spv::Decoration decoration) const;
uint32_t get_decoration(ID id, Decoration decoration) const;
const std::string &get_decoration_string(ID id, Decoration decoration) const;
// Removes the decoration for an ID.
void unset_decoration(ID id, spv::Decoration decoration);
void unset_decoration(ID id, Decoration decoration);
// Gets the SPIR-V type associated with ID.
// Mostly used with Resource::type_id and Resource::base_type_id to parse the underlying type of a resource.
@ -216,7 +225,7 @@ public:
const SPIRType &get_type_from_variable(VariableID id) const;
// Gets the underlying storage class for an OpVariable.
spv::StorageClass get_storage_class(VariableID id) const;
StorageClass get_storage_class(VariableID id) const;
// If get_name() is an empty string, get the fallback name which will be used
// instead in the disassembled source.
@ -231,8 +240,8 @@ public:
const std::string &get_member_name(TypeID id, uint32_t index) const;
// Given an OpTypeStruct in ID, obtain the OpMemberDecoration for member number "index".
uint32_t get_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration) const;
const std::string &get_member_decoration_string(TypeID id, uint32_t index, spv::Decoration decoration) const;
uint32_t get_member_decoration(TypeID id, uint32_t index, Decoration decoration) const;
const std::string &get_member_decoration_string(TypeID id, uint32_t index, Decoration decoration) const;
// Sets the member identifier for OpTypeStruct ID, member number "index".
void set_member_name(TypeID id, uint32_t index, const std::string &name);
@ -245,15 +254,15 @@ public:
const Bitset &get_member_decoration_bitset(TypeID id, uint32_t index) const;
// Returns whether the decoration has been applied to a member of a struct.
bool has_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration) const;
bool has_member_decoration(TypeID id, uint32_t index, Decoration decoration) const;
// Similar to set_decoration, but for struct members.
void set_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration, uint32_t argument = 0);
void set_member_decoration_string(TypeID id, uint32_t index, spv::Decoration decoration,
void set_member_decoration(TypeID id, uint32_t index, Decoration decoration, uint32_t argument = 0);
void set_member_decoration_string(TypeID id, uint32_t index, Decoration decoration,
const std::string &argument);
// Unsets a member decoration, similar to unset_decoration.
void unset_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration);
void unset_member_decoration(TypeID id, uint32_t index, Decoration decoration);
// Gets the fallback name for a member, similar to get_fallback_name.
virtual const std::string get_fallback_member_name(uint32_t index) const
@ -339,28 +348,28 @@ public:
// Names for entry points in the SPIR-V module may alias if they belong to different execution models.
// To disambiguate, we must pass along with the entry point names the execution model.
SmallVector<EntryPoint> get_entry_points_and_stages() const;
void set_entry_point(const std::string &entry, spv::ExecutionModel execution_model);
void set_entry_point(const std::string &entry, ExecutionModel execution_model);
// Renames an entry point from old_name to new_name.
// If old_name is currently selected as the current entry point, it will continue to be the current entry point,
// albeit with a new name.
// get_entry_points() is essentially invalidated at this point.
void rename_entry_point(const std::string &old_name, const std::string &new_name,
spv::ExecutionModel execution_model);
const SPIREntryPoint &get_entry_point(const std::string &name, spv::ExecutionModel execution_model) const;
SPIREntryPoint &get_entry_point(const std::string &name, spv::ExecutionModel execution_model);
ExecutionModel execution_model);
const SPIREntryPoint &get_entry_point(const std::string &name, ExecutionModel execution_model) const;
SPIREntryPoint &get_entry_point(const std::string &name, ExecutionModel execution_model);
const std::string &get_cleansed_entry_point_name(const std::string &name,
spv::ExecutionModel execution_model) const;
ExecutionModel execution_model) const;
// Traverses all reachable opcodes and sets active_builtins to a bitmask of all builtin variables which are accessed in the shader.
void update_active_builtins();
bool has_active_builtin(spv::BuiltIn builtin, spv::StorageClass storage) const;
bool has_active_builtin(BuiltIn builtin, StorageClass storage) const;
// Query and modify OpExecutionMode.
const Bitset &get_execution_mode_bitset() const;
void unset_execution_mode(spv::ExecutionMode mode);
void set_execution_mode(spv::ExecutionMode mode, uint32_t arg0 = 0, uint32_t arg1 = 0, uint32_t arg2 = 0);
void unset_execution_mode(ExecutionMode mode);
void set_execution_mode(ExecutionMode mode, uint32_t arg0 = 0, uint32_t arg1 = 0, uint32_t arg2 = 0);
// Gets argument for an execution mode (LocalSize, Invocations, OutputVertices).
// For LocalSize or LocalSizeId, the index argument is used to select the dimension (X = 0, Y = 1, Z = 2).
@ -368,8 +377,8 @@ public:
// LocalSizeId query returns an ID. If LocalSizeId execution mode is not used, it returns 0.
// LocalSize always returns a literal. If execution mode is LocalSizeId,
// the literal (spec constant or not) is still returned.
uint32_t get_execution_mode_argument(spv::ExecutionMode mode, uint32_t index = 0) const;
spv::ExecutionModel get_execution_model() const;
uint32_t get_execution_mode_argument(ExecutionMode mode, uint32_t index = 0) const;
ExecutionModel get_execution_model() const;
bool is_tessellation_shader() const;
bool is_tessellating_triangles() const;
@ -482,7 +491,7 @@ public:
// If the decoration was declared, sets the word_offset to an offset into the provided SPIR-V binary buffer and returns true,
// otherwise, returns false.
// If the decoration does not have any value attached to it (e.g. DecorationRelaxedPrecision), this function will also return false.
bool get_binary_offset_for_decoration(VariableID id, spv::Decoration decoration, uint32_t &word_offset) const;
bool get_binary_offset_for_decoration(VariableID id, Decoration decoration, uint32_t &word_offset) const;
// HLSL counter buffer reflection interface.
// Append/Consume/Increment/Decrement in HLSL is implemented as two "neighbor" buffer objects where
@ -508,7 +517,7 @@ public:
bool buffer_get_hlsl_counter_buffer(VariableID id, uint32_t &counter_id) const;
// Gets the list of all SPIR-V Capabilities which were declared in the SPIR-V module.
const SmallVector<spv::Capability> &get_declared_capabilities() const;
const SmallVector<Capability> &get_declared_capabilities() const;
// Gets the list of all SPIR-V extensions which were declared in the SPIR-V module.
const SmallVector<std::string> &get_declared_extensions() const;
@ -671,20 +680,21 @@ protected:
const SPIREntryPoint &get_entry_point() const;
SPIREntryPoint &get_entry_point();
static bool is_tessellation_shader(spv::ExecutionModel model);
static bool is_tessellation_shader(ExecutionModel model);
virtual std::string to_name(uint32_t id, bool allow_alias = true) const;
bool is_builtin_variable(const SPIRVariable &var) const;
bool is_builtin_type(const SPIRType &type) const;
bool is_hidden_variable(const SPIRVariable &var, bool include_builtins = false) const;
bool is_immutable(uint32_t id) const;
bool is_member_builtin(const SPIRType &type, uint32_t index, spv::BuiltIn *builtin) const;
bool is_member_builtin(const SPIRType &type, uint32_t index, BuiltIn *builtin) const;
bool is_scalar(const SPIRType &type) const;
bool is_vector(const SPIRType &type) const;
bool is_matrix(const SPIRType &type) const;
bool is_array(const SPIRType &type) const;
bool is_pointer(const SPIRType &type) const;
bool is_physical_pointer(const SPIRType &type) const;
bool is_physical_or_buffer_pointer(const SPIRType &type) const;
bool is_physical_pointer_to_buffer_block(const SPIRType &type) const;
static bool is_runtime_size_array(const SPIRType &type);
uint32_t expression_type_id(uint32_t id) const;
@ -787,11 +797,12 @@ protected:
// Used internally to implement various traversals for queries.
struct OpcodeHandler
{
explicit OpcodeHandler(Compiler &compiler_) : compiler(compiler_) {}
virtual ~OpcodeHandler() = default;
// Return true if traversal should continue.
// If false, traversal will end immediately.
virtual bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) = 0;
virtual bool handle(Op opcode, const uint32_t *args, uint32_t length) = 0;
virtual bool handle_terminator(const SPIRBlock &)
{
return true;
@ -822,20 +833,40 @@ protected:
{
return true;
}
Compiler &compiler;
std::unordered_map<uint32_t, uint32_t> result_types;
const SPIRType *get_expression_result_type(uint32_t id) const;
bool enable_result_types = false;
template <typename T> T &get(uint32_t id)
{
return compiler.get<T>(id);
}
template <typename T> const T &get(uint32_t id) const
{
return compiler.get<T>(id);
}
template <typename T, typename... P>
T &set(uint32_t id, P &&... args)
{
return compiler.set<T>(id, std::forward<P>(args)...);
}
};
struct BufferAccessHandler : OpcodeHandler
{
BufferAccessHandler(const Compiler &compiler_, SmallVector<BufferRange> &ranges_, uint32_t id_)
: compiler(compiler_)
: OpcodeHandler(const_cast<Compiler &>(compiler_))
, ranges(ranges_)
, id(id_)
{
}
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
bool handle(Op opcode, const uint32_t *args, uint32_t length) override;
const Compiler &compiler;
SmallVector<BufferRange> &ranges;
uint32_t id;
@ -845,29 +876,26 @@ protected:
struct InterfaceVariableAccessHandler : OpcodeHandler
{
InterfaceVariableAccessHandler(const Compiler &compiler_, std::unordered_set<VariableID> &variables_)
: compiler(compiler_)
: OpcodeHandler(const_cast<Compiler &>(compiler_))
, variables(variables_)
{
}
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
bool handle(Op opcode, const uint32_t *args, uint32_t length) override;
const Compiler &compiler;
std::unordered_set<VariableID> &variables;
};
struct CombinedImageSamplerHandler : OpcodeHandler
{
CombinedImageSamplerHandler(Compiler &compiler_)
: compiler(compiler_)
explicit CombinedImageSamplerHandler(Compiler &compiler_)
: OpcodeHandler(compiler_)
{
}
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
bool handle(Op opcode, const uint32_t *args, uint32_t length) override;
bool begin_function_scope(const uint32_t *args, uint32_t length) override;
bool end_function_scope(const uint32_t *args, uint32_t length) override;
Compiler &compiler;
// Each function in the call stack needs its own remapping for parameters so we can deduce which global variable each texture/sampler the parameter is statically bound to.
std::stack<std::unordered_map<uint32_t, uint32_t>> parameter_remapping;
std::stack<SPIRFunction *> functions;
@ -881,27 +909,24 @@ protected:
struct DummySamplerForCombinedImageHandler : OpcodeHandler
{
DummySamplerForCombinedImageHandler(Compiler &compiler_)
: compiler(compiler_)
explicit DummySamplerForCombinedImageHandler(Compiler &compiler_)
: OpcodeHandler(compiler_)
{
}
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
Compiler &compiler;
bool handle(Op opcode, const uint32_t *args, uint32_t length) override;
bool need_dummy_sampler = false;
};
struct ActiveBuiltinHandler : OpcodeHandler
{
ActiveBuiltinHandler(Compiler &compiler_)
: compiler(compiler_)
explicit ActiveBuiltinHandler(Compiler &compiler_)
: OpcodeHandler(compiler_)
{
}
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
Compiler &compiler;
bool handle(Op opcode, const uint32_t *args, uint32_t length) override;
void handle_builtin(const SPIRType &type, spv::BuiltIn builtin, const Bitset &decoration_flags);
void handle_builtin(const SPIRType &type, BuiltIn builtin, const Bitset &decoration_flags);
void add_if_builtin(uint32_t id);
void add_if_builtin_or_block(uint32_t id);
void add_if_builtin(uint32_t id, bool allow_blocks);
@ -953,13 +978,12 @@ protected:
struct CombinedImageSamplerDrefHandler : OpcodeHandler
{
CombinedImageSamplerDrefHandler(Compiler &compiler_)
: compiler(compiler_)
explicit CombinedImageSamplerDrefHandler(Compiler &compiler_)
: OpcodeHandler(compiler_)
{
}
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
bool handle(Op opcode, const uint32_t *args, uint32_t length) override;
Compiler &compiler;
std::unordered_set<uint32_t> dref_combined_samplers;
};
@ -967,14 +991,13 @@ protected:
{
CombinedImageSamplerUsageHandler(Compiler &compiler_,
const std::unordered_set<uint32_t> &dref_combined_samplers_)
: compiler(compiler_)
: OpcodeHandler(compiler_)
, dref_combined_samplers(dref_combined_samplers_)
{
}
bool begin_function_scope(const uint32_t *args, uint32_t length) override;
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
Compiler &compiler;
bool handle(Op opcode, const uint32_t *args, uint32_t length) override;
const std::unordered_set<uint32_t> &dref_combined_samplers;
std::unordered_map<uint32_t, std::unordered_set<uint32_t>> dependency_hierarchy;
@ -996,8 +1019,7 @@ protected:
explicit CFGBuilder(Compiler &compiler_);
bool follow_function_call(const SPIRFunction &func) override;
bool handle(spv::Op op, const uint32_t *args, uint32_t length) override;
Compiler &compiler;
bool handle(Op op, const uint32_t *args, uint32_t length) override;
std::unordered_map<uint32_t, std::unique_ptr<CFG>> function_cfgs;
};
@ -1011,10 +1033,9 @@ protected:
void notify_variable_access(uint32_t id, uint32_t block);
bool id_is_phi_variable(uint32_t id) const;
bool id_is_potential_temporary(uint32_t id) const;
bool handle(spv::Op op, const uint32_t *args, uint32_t length) override;
bool handle(Op op, const uint32_t *args, uint32_t length) override;
bool handle_terminator(const SPIRBlock &block) override;
Compiler &compiler;
SPIRFunction &entry;
std::unordered_map<uint32_t, std::unordered_set<uint32_t>> accessed_variables_to_block;
std::unordered_map<uint32_t, std::unordered_set<uint32_t>> accessed_temporaries_to_block;
@ -1032,9 +1053,8 @@ protected:
{
StaticExpressionAccessHandler(Compiler &compiler_, uint32_t variable_id_);
bool follow_function_call(const SPIRFunction &) override;
bool handle(spv::Op op, const uint32_t *args, uint32_t length) override;
bool handle(Op op, const uint32_t *args, uint32_t length) override;
Compiler &compiler;
uint32_t variable_id;
uint32_t static_expression = 0;
uint32_t write_count = 0;
@ -1048,8 +1068,7 @@ protected:
struct PhysicalStorageBufferPointerHandler : OpcodeHandler
{
explicit PhysicalStorageBufferPointerHandler(Compiler &compiler_);
bool handle(spv::Op op, const uint32_t *args, uint32_t length) override;
Compiler &compiler;
bool handle(Op op, const uint32_t *args, uint32_t length) override;
std::unordered_set<uint32_t> non_block_types;
std::unordered_map<uint32_t, PhysicalBlockMeta> physical_block_type_meta;
@ -1076,12 +1095,11 @@ protected:
struct GeometryEmitDisocveryHandler : OpcodeHandler
{
explicit GeometryEmitDisocveryHandler(Compiler &compiler_)
: compiler(compiler_)
: OpcodeHandler(compiler_)
{
}
Compiler &compiler;
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
bool handle(Op opcode, const uint32_t *args, uint32_t length) override;
bool begin_function_scope(const uint32_t *, uint32_t) override;
bool end_function_scope(const uint32_t *, uint32_t) override;
SmallVector<SPIRFunction *> function_stack;
@ -1096,16 +1114,15 @@ protected:
struct InterlockedResourceAccessHandler : OpcodeHandler
{
InterlockedResourceAccessHandler(Compiler &compiler_, uint32_t entry_point_id)
: compiler(compiler_)
: OpcodeHandler(compiler_)
{
call_stack.push_back(entry_point_id);
}
bool handle(spv::Op op, const uint32_t *args, uint32_t length) override;
bool handle(Op op, const uint32_t *args, uint32_t length) override;
bool begin_function_scope(const uint32_t *args, uint32_t length) override;
bool end_function_scope(const uint32_t *args, uint32_t length) override;
Compiler &compiler;
bool in_crit_sec = false;
uint32_t interlock_function_id = 0;
@ -1121,17 +1138,16 @@ protected:
struct InterlockedResourceAccessPrepassHandler : OpcodeHandler
{
InterlockedResourceAccessPrepassHandler(Compiler &compiler_, uint32_t entry_point_id)
: compiler(compiler_)
: OpcodeHandler(compiler_)
{
call_stack.push_back(entry_point_id);
}
void rearm_current_block(const SPIRBlock &block) override;
bool handle(spv::Op op, const uint32_t *args, uint32_t length) override;
bool handle(Op op, const uint32_t *args, uint32_t length) override;
bool begin_function_scope(const uint32_t *args, uint32_t length) override;
bool end_function_scope(const uint32_t *args, uint32_t length) override;
Compiler &compiler;
uint32_t interlock_function_id = 0;
uint32_t current_block_id = 0;
bool split_function_case = false;
@ -1148,11 +1164,11 @@ protected:
std::unordered_map<uint32_t, std::string> declared_block_names;
bool instruction_to_result_type(uint32_t &result_type, uint32_t &result_id, spv::Op op, const uint32_t *args,
uint32_t length);
static bool instruction_to_result_type(
uint32_t &result_type, uint32_t &result_id, Op op, const uint32_t *args, uint32_t length);
Bitset combined_decoration_for_member(const SPIRType &type, uint32_t index) const;
static bool is_desktop_only_format(spv::ImageFormat format);
static bool is_desktop_only_format(ImageFormat format);
bool is_depth_image(const SPIRType &type, uint32_t id) const;
@ -1171,6 +1187,7 @@ protected:
bool type_contains_recursion(const SPIRType &type);
bool type_is_array_of_pointers(const SPIRType &type) const;
bool type_is_block_like(const SPIRType &type) const;
bool type_is_explicit_layout(const SPIRType &type) const;
bool type_is_top_level_block(const SPIRType &type) const;
bool type_is_opaque_value(const SPIRType &type) const;
@ -1196,4 +1213,8 @@ private:
};
} // namespace SPIRV_CROSS_NAMESPACE
#ifdef SPIRV_CROSS_SPV_HEADER_NAMESPACE_OVERRIDE
#undef spv
#endif
#endif

Some files were not shown because too many files have changed in this diff Show more