diff --git a/Externals/glslang/.appveyor.yml b/Externals/glslang/.appveyor.yml index 64e7ae64af..07e269bedf 100644 --- a/Externals/glslang/.appveyor.yml +++ b/Externals/glslang/.appveyor.yml @@ -7,7 +7,7 @@ version: "{build}" os: Visual Studio 2013 platform: - - Any CPU + - x64 configuration: - Debug @@ -17,6 +17,13 @@ branches: only: - master +# Travis advances the master-tot tag to current top of the tree after +# each push into the master branch, because it relies on that tag to +# upload build artifacts to the master-tot release. This will cause +# double testing for each push on Appveyor: one for the push, one for +# the tag advance. Disable testing tags. +skip_tags: true + clone_depth: 5 matrix: @@ -25,6 +32,7 @@ matrix: # scripts that run after cloning repository install: - git clone https://github.com/google/googletest.git External/googletest + - C:/Python27/python.exe update_glslang_sources.py build: parallel: true # enable MSBuild parallel builds @@ -38,3 +46,45 @@ build_script: test_script: - ctest -C %CONFIGURATION% --output-on-failure - cd ../Test && bash runtests + - cd ../build + +after_test: + # For debug build, the generated dll has a postfix "d" in its name. + - ps: >- + If ($env:configuration -Match "Debug") { + $env:SUFFIX="d" + } Else { + $env:SUFFIX="" + } + - cd install + # Zip all glslang artifacts for uploading and deploying + - 7z a glslang-master-windows-"%PLATFORM%"-"%CONFIGURATION%".zip + bin\glslangValidator.exe + include\glslang\* + include\SPIRV\* + lib\glslang%SUFFIX%.lib + lib\HLSL%SUFFIX%.lib + lib\OGLCompiler%SUFFIX%.lib + lib\OSDependent%SUFFIX%.lib + lib\SPIRV%SUFFIX%.lib + lib\SPVRemapper%SUFFIX%.lib + lib\SPIRV-Tools%SUFFIX%.lib + lib\SPIRV-Tools-opt%SUFFIX%.lib + +artifacts: + - path: build\install\*.zip + name: artifacts-zip + +deploy: + - provider: GitHub + auth_token: + secure: YglcSYdl0TylEa59H4K6lylBEDr586NAt2EMgZquSo+iuPrwgZQuJLPCoihSm9y6 + release: master-tot + description: "Continuous build of the latest master branch by Appveyor and Travis CI" + artifact: artifacts-zip + draft: false + prerelease: false + force_update: true + on: + branch: master + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013 diff --git a/Externals/glslang/.gitattributes b/Externals/glslang/.gitattributes new file mode 100644 index 0000000000..cade39089b --- /dev/null +++ b/Externals/glslang/.gitattributes @@ -0,0 +1,17 @@ +# test files have a mix of lf/crlf, and that's a good thing, for testing, don't mess with it +# bash scripts need lines ending with lf, and that's correct for Windows too, e.g., under Cygwin +# (scripts often don't have a suffix) +* -text +*.sh text eof=lf + +# txt files should be native and normalized +*.txt text + +# source code can be native and normalized, but simpler if lf everywhere; will try that way +*.h text eof=lf +*.c text eof=lf +*.cpp text eof=lf +*.y text eof=lf +*.out text eof=lf +*.conf text eof=lf +*.err text eof=lf diff --git a/Externals/glslang/.gitignore b/Externals/glslang/.gitignore new file mode 100644 index 0000000000..a1fe3944b1 --- /dev/null +++ b/Externals/glslang/.gitignore @@ -0,0 +1,10 @@ +*.o +*.a +*.so +*.exe +tags +TAGS +build/ +Test/localResults/ +External/googletest +External/spirv-tools diff --git a/Externals/glslang/.travis.yml b/Externals/glslang/.travis.yml index 4a88dce5a9..4fe4b5e5ba 100644 --- a/Externals/glslang/.travis.yml +++ b/Externals/glslang/.travis.yml @@ -7,12 +7,15 @@ os: - osx # Use Ubuntu 14.04 LTS (Trusty) as the Linux testing environment. -sudo: required +sudo: false dist: trusty env: - - GLSLANG_BUILD_TYPE=Release - - GLSLANG_BUILD_TYPE=Debug + global: + - secure: aGFrgzyKp+84hKrGkxVWg8cHV61uqrKEHT38gfSQK6+WS4GfLOyH83p7WnsEBb7AMhzU7LMNFdvOFr6+NaMpVnqRvc40CEG1Q+lNg9Pq9mhIZLowvDrfqTL9kQ+8Nbw5Q6/dg6CTvY7fvRfpfCEmKIUZBRkoKUuHeuM1uy3IupFcdNuL5bSYn3Beo+apSJginh9DI4BLDXFUgBzTRSLLyCX5g3cpaeGGOCr8quJlYx75W6HRck5g9SZuLtUoH9GFEV3l+ZEWB8noErW+J56L03bwNwFuuAh321evw++oQk5KFa8rlDvar3SJ3b1RHB8u/eq5DBYMyaK/fS8+Q7QbGr8diF/wDe68bKO7U9IhpNfExXmczCpExjHomW5TQv4rYdGhygPMfW97aIsPRYyNKcl4fkmb7NDrM8w0Jscdq2g5c2Kz0ItyZoBri/NXLwFQQjaVCs7Pf97TjuMA7mK0GJmDTRzi6SrDYlWMt5BQL3y0CCojyfLIRcTh0CQjQI29s97bLfQrYAxt9GNNFR+HTXRLLrkaAlJkPGEPwUywlSfEThnvHLesNxYqemolAYpQT4ithoL4GehGIHmaxsW295aKVhuRf8K9eBODNqrfblvM42UHhjntT+92ZnQ/Gkq80GqaMxnxi4PO5FyPIxt0r981b54YBkWi8YA4P7w5pNI= + matrix: + - GLSLANG_BUILD_TYPE=Release + - GLSLANG_BUILD_TYPE=Debug compiler: - clang @@ -24,6 +27,9 @@ matrix: # Skip GCC builds on Mac OS X. - os: osx compiler: gcc + include: + # Additional build using Android NDK. + - env: BUILD_NDK=ON cache: apt: true @@ -36,25 +42,82 @@ addons: apt: packages: - clang-3.6 - - ninja-build install: - # Install ninja on Mac OS X. - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update && brew install ninja; fi - # Make sure that clang-3.6 is selected. + # Make sure that clang-3.6 is selected on Linux. - if [[ "$TRAVIS_OS_NAME" == "linux" && "$CC" == "clang" ]]; then export CC=clang-3.6 CXX=clang++-3.6; fi + # Download Android NDK and Android CMake toolchain file. + - if [[ "$BUILD_NDK" == "ON" ]]; then + git clone --depth=1 https://github.com/urho3d/android-ndk.git $HOME/android-ndk; + export ANDROID_NDK=$HOME/android-ndk; + git clone --depth=1 https://github.com/taka-no-me/android-cmake.git $HOME/android-cmake; + export TOOLCHAIN_PATH=$HOME/android-cmake/android.toolchain.cmake; + fi before_script: - - git clone https://github.com/google/googletest.git External/googletest + - git clone --depth=1 https://github.com/google/googletest.git External/googletest + - ./update_glslang_sources.py script: - mkdir build && cd build - # We need to install the compiled binaries so the paths in the runtests script can resolve correctly. - - cmake -GNinja -DCMAKE_BUILD_TYPE=${GLSLANG_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=`pwd`/install .. - - ninja install - # Run Google-Test-based tests. - - ctest --output-on-failure - # Run runtests-based tests. - - cd ../Test && ./runtests + # For Android, do release building using NDK without testing. + # For Linux and macOS, do debug/release building with testing. + - if [[ "$BUILD_NDK" == "ON" ]]; then + cmake -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_PATH} + -DANDROID_NATIVE_API_LEVEL=android-12 + -DCMAKE_BUILD_TYPE=Release + -DANDROID_ABI="armeabi-v7a with NEON" + -DBUILD_TESTING=OFF ..; + make -j4; + else + cmake -DCMAKE_BUILD_TYPE=${GLSLANG_BUILD_TYPE} + -DCMAKE_INSTALL_PREFIX=`pwd`/install ..; + make -j4 install; + ctest --output-on-failure && + cd ../Test && ./runtests; + fi + +after_success: + # For debug build, the generated dll has a postfix "d" in its name. + - if [[ "${GLSLANG_BUILD_TYPE}" == "Debug" ]]; then + export SUFFIX="d"; + else + export SUFFIX=""; + fi + # Create tarball for deployment + - if [[ ${CC} == clang* && "${BUILD_NDK}" != "ON" ]]; then + cd ../build/install; + export TARBALL=glslang-master-${TRAVIS_OS_NAME}-${GLSLANG_BUILD_TYPE}.zip; + zip ${TARBALL} + bin/glslangValidator + include/glslang/* + include/SPIRV/* + lib/libglslang${SUFFIX}.a + lib/libHLSL${SUFFIX}.a + lib/libOGLCompiler${SUFFIX}.a + lib/libOSDependent${SUFFIX}.a + lib/libSPIRV${SUFFIX}.a + lib/libSPVRemapper${SUFFIX}.a + lib/libSPIRV-Tools${SUFFIX}.a + lib/libSPIRV-Tools-opt${SUFFIX}.a; + fi + +before_deploy: + # Tag the current top of the tree as "master-tot". + # Travis CI replies on the tag name to properly push to GitHub Releases. + - git config --global user.name "Travis CI" + - git config --global user.email "builds@travis-ci.org" + - git tag -f master-tot + - git push -q -f https://${glslangtoken}@github.com/KhronosGroup/glslang --tags + +deploy: + provider: releases + api_key: ${glslangtoken} + on: + branch: master + condition: ${CC} == clang* && ${BUILD_NDK} != ON + file: ${TARBALL} + skip_cleanup: true + overwrite: true diff --git a/Externals/glslang/CMakeLists.txt b/Externals/glslang/CMakeLists.txt index f288020542..e531534a96 100644 --- a/Externals/glslang/CMakeLists.txt +++ b/Externals/glslang/CMakeLists.txt @@ -1,6 +1,7 @@ set(SRCS glslang/GenericCodeGen/CodeGen.cpp glslang/GenericCodeGen/Link.cpp + glslang/MachineIndependent/attribute.cpp glslang/MachineIndependent/Constant.cpp glslang/MachineIndependent/glslang_tab.cpp glslang/MachineIndependent/InfoSink.cpp @@ -8,17 +9,17 @@ set(SRCS glslang/MachineIndependent/Intermediate.cpp glslang/MachineIndependent/intermOut.cpp glslang/MachineIndependent/IntermTraverse.cpp + glslang/MachineIndependent/iomapper.cpp glslang/MachineIndependent/limits.cpp glslang/MachineIndependent/linkValidate.cpp glslang/MachineIndependent/parseConst.cpp + glslang/MachineIndependent/ParseContextBase.cpp glslang/MachineIndependent/ParseHelper.cpp glslang/MachineIndependent/PoolAlloc.cpp glslang/MachineIndependent/preprocessor/Pp.cpp glslang/MachineIndependent/preprocessor/PpAtom.cpp glslang/MachineIndependent/preprocessor/PpContext.cpp - glslang/MachineIndependent/preprocessor/PpMemory.cpp glslang/MachineIndependent/preprocessor/PpScanner.cpp - glslang/MachineIndependent/preprocessor/PpSymbols.cpp glslang/MachineIndependent/preprocessor/PpTokens.cpp glslang/MachineIndependent/propagateNoContraction.cpp glslang/MachineIndependent/reflection.cpp @@ -27,13 +28,6 @@ set(SRCS glslang/MachineIndependent/ShaderLang.cpp glslang/MachineIndependent/SymbolTable.cpp glslang/MachineIndependent/Versions.cpp - - hlsl/hlslGrammar.cpp - hlsl/hlslOpMap.cpp - hlsl/hlslParseables.cpp - hlsl/hlslParseHelper.cpp - hlsl/hlslScanContext.cpp - hlsl/hlslTokenStream.cpp OGLCompilersDLL/InitializeDll.cpp SPIRV/disassemble.cpp SPIRV/doc.cpp diff --git a/Externals/glslang/CMakeLists.txt.dist b/Externals/glslang/CMakeLists.txt.dist index f2f2355973..9a869c2c00 100644 --- a/Externals/glslang/CMakeLists.txt.dist +++ b/Externals/glslang/CMakeLists.txt.dist @@ -1,46 +1,122 @@ +# increase to 3.1 once all major distributions +# include a version of CMake >= 3.1 cmake_minimum_required(VERSION 2.8.12) +if (POLICY CMP0048) + cmake_policy(SET CMP0048 NEW) +endif() set_property(GLOBAL PROPERTY USE_FOLDERS ON) -enable_testing() +# Adhere to GNU filesystem layout conventions +include(GNUInstallDirs) -set(CMAKE_INSTALL_PREFIX "install" CACHE STRING "prefix") +option(BUILD_SHARED_LIBS "Build Shared Libraries" OFF) + +set(LIB_TYPE STATIC) + +if(BUILD_SHARED_LIBS) + set(LIB_TYPE SHARED) +endif() + +option(SKIP_GLSLANG_INSTALL "Skip installation" ${SKIP_GLSLANG_INSTALL}) +if(NOT ${SKIP_GLSLANG_INSTALL}) + set(ENABLE_GLSLANG_INSTALL ON) +endif() + +option(ENABLE_AMD_EXTENSIONS "Enables support of AMD-specific extensions" ON) +option(ENABLE_GLSLANG_BINARIES "Builds glslangValidator and spirv-remap" ON) + +option(ENABLE_NV_EXTENSIONS "Enables support of Nvidia-specific extensions" ON) + +option(ENABLE_HLSL "Enables HLSL input support" ON) + +option(ENABLE_OPT "Enables spirv-opt capability if present" ON) + +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND WIN32) + set(CMAKE_INSTALL_PREFIX "install" CACHE STRING "..." FORCE) +endif() project(glslang) +# make testing optional +include(CTest) + +if(ENABLE_AMD_EXTENSIONS) + add_definitions(-DAMD_EXTENSIONS) +endif(ENABLE_AMD_EXTENSIONS) + +if(ENABLE_NV_EXTENSIONS) + add_definitions(-DNV_EXTENSIONS) +endif(ENABLE_NV_EXTENSIONS) + +if(ENABLE_HLSL) + add_definitions(-DENABLE_HLSL) +endif(ENABLE_HLSL) if(WIN32) set(CMAKE_DEBUG_POSTFIX "d") - include(ChooseMSVCCRT.cmake) + if(MSVC) + include(ChooseMSVCCRT.cmake) + endif(MSVC) add_definitions(-DGLSLANG_OSINCLUDE_WIN32) elseif(UNIX) - add_definitions(-fPIC) add_definitions(-DGLSLANG_OSINCLUDE_UNIX) else(WIN32) message("unknown platform") endif(WIN32) -if(CMAKE_COMPILER_IS_GNUCXX) - add_definitions(-std=c++11) +if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") + add_compile_options(-Wall -Wmaybe-uninitialized -Wuninitialized -Wunused -Wunused-local-typedefs + -Wunused-parameter -Wunused-value -Wunused-variable -Wunused-but-set-parameter -Wunused-but-set-variable -fno-exceptions) + add_compile_options(-Wno-reorder) # disable this from -Wall, since it happens all over. elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") - add_definitions(-std=c++11) + add_compile_options(-Wall -Wuninitialized -Wunused -Wunused-local-typedefs + -Wunused-parameter -Wunused-value -Wunused-variable) + add_compile_options(-Wno-reorder) # disable this from -Wall, since it happens all over. +endif() + +# Request C++11 +if(${CMAKE_VERSION} VERSION_LESS 3.1) + # CMake versions before 3.1 do not understand CMAKE_CXX_STANDARD + # remove this block once CMake >=3.1 has fixated in the ecosystem + add_compile_options(-std=c++11) +else() + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_EXTENSIONS OFF) endif() function(glslang_set_link_args TARGET) # For MinGW compiles, statically link against the GCC and C++ runtimes. # This avoids the need to ship those runtimes as DLLs. - if(WIN32) - if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") - set_target_properties(${TARGET} PROPERTIES - LINK_FLAGS "-static -static-libgcc -static-libstdc++") - endif() - endif(WIN32) + if(WIN32 AND ${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") + set_target_properties(${TARGET} PROPERTIES + LINK_FLAGS "-static -static-libgcc -static-libstdc++") + endif() endfunction(glslang_set_link_args) # We depend on these for later projects, so they should come first. add_subdirectory(External) +if(NOT TARGET SPIRV-Tools-opt) + set(ENABLE_OPT OFF) +endif() + +if(ENABLE_OPT) + message(STATUS "optimizer enabled") + add_definitions(-DENABLE_OPT=1) +else() + if(ENABLE_HLSL) + message(STATUS "spirv-tools not linked - illegal SPIRV may be generated for HLSL") + endif() + add_definitions(-DENABLE_OPT=0) +endif() + add_subdirectory(glslang) add_subdirectory(OGLCompilersDLL) -add_subdirectory(StandAlone) +if(ENABLE_GLSLANG_BINARIES) + add_subdirectory(StandAlone) +endif() add_subdirectory(SPIRV) -add_subdirectory(hlsl) +if(ENABLE_HLSL) + add_subdirectory(hlsl) +endif(ENABLE_HLSL) add_subdirectory(gtests) diff --git a/Externals/glslang/External/CMakeLists.txt b/Externals/glslang/External/CMakeLists.txt index 5180ea5693..4d9690134a 100644 --- a/Externals/glslang/External/CMakeLists.txt +++ b/Externals/glslang/External/CMakeLists.txt @@ -1,34 +1,43 @@ # Suppress all warnings from external projects. set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS -w) -if (TARGET gmock) - message(STATUS "Google Mock already configured - use it") -elseif(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/googletest) - # We need to make sure Google Test does not mess up with the - # global CRT settings on Windows. - if(WIN32) - set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) - endif(WIN32) - add_subdirectory(googletest) - set(GTEST_TARGETS - gtest - gtest_main - gmock - gmock_main - ) - foreach(target ${GTEST_TARGETS}) - set_property(TARGET ${target} PROPERTY FOLDER gtest) - endforeach() - mark_as_advanced(gmock_build_tests - BUILD_GMOCK - BUILD_GTEST - BUILD_SHARED_LIBS - gtest_build_samples - gtest_build_tests - gtest_disable_pthreads - gtest_force_shared_crt - gtest_hide_internal_symbols) -else() - message(STATUS - "Google Mock was not found - tests based on that will not build") +if(BUILD_TESTING) + if(TARGET gmock) + message(STATUS "Google Mock already configured - use it") + elseif(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/googletest) + # We need to make sure Google Test does not mess up with the + # global CRT settings on Windows. + if(WIN32) + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + endif(WIN32) + add_subdirectory(googletest) + set(GTEST_TARGETS + gtest + gtest_main + gmock + gmock_main) + foreach(target ${GTEST_TARGETS}) + set_property(TARGET ${target} PROPERTY FOLDER gtest) + endforeach() + mark_as_advanced(gmock_build_tests + BUILD_GMOCK + BUILD_GTEST + BUILD_SHARED_LIBS + gtest_build_samples + gtest_build_tests + gtest_disable_pthreads + gtest_force_shared_crt + gtest_hide_internal_symbols) + else() + message(STATUS + "Google Mock was not found - tests based on that will not build") + endif() endif() + +if(ENABLE_OPT AND NOT TARGET SPIRV-Tools-opt) + if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/spirv-tools) + set(SPIRV_SKIP_TESTS ON CACHE BOOL "Skip building SPIRV-Tools tests") + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/spirv-tools spirv-tools) + endif() +endif() + diff --git a/Externals/glslang/OGLCompilersDLL/CMakeLists.txt b/Externals/glslang/OGLCompilersDLL/CMakeLists.txt index 4954db9458..5bb3f0ee69 100644 --- a/Externals/glslang/OGLCompilersDLL/CMakeLists.txt +++ b/Externals/glslang/OGLCompilersDLL/CMakeLists.txt @@ -2,10 +2,13 @@ set(SOURCES InitializeDll.cpp InitializeDll.h) add_library(OGLCompiler STATIC ${SOURCES}) set_property(TARGET OGLCompiler PROPERTY FOLDER glslang) +set_property(TARGET OGLCompiler PROPERTY POSITION_INDEPENDENT_CODE ON) if(WIN32) source_group("Source" FILES ${SOURCES}) endif(WIN32) -install(TARGETS OGLCompiler - ARCHIVE DESTINATION lib) +if(ENABLE_GLSLANG_INSTALL) + install(TARGETS OGLCompiler + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(ENABLE_GLSLANG_INSTALL) diff --git a/Externals/glslang/OGLCompilersDLL/InitializeDll.cpp b/Externals/glslang/OGLCompilersDLL/InitializeDll.cpp index cc2b742ed5..abea9108b1 100644 --- a/Externals/glslang/OGLCompilersDLL/InitializeDll.cpp +++ b/Externals/glslang/OGLCompilersDLL/InitializeDll.cpp @@ -1,10 +1,10 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -18,33 +18,37 @@ // 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. +// 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. // #define SH_EXPORTING -#include +#include #include "InitializeDll.h" #include "../glslang/Include/InitializeGlobals.h" - #include "../glslang/Public/ShaderLang.h" +#include "../glslang/Include/PoolAlloc.h" namespace glslang { OS_TLSIndex ThreadInitializeIndex = OS_INVALID_TLS_INDEX; +// Per-process initialization. +// Needs to be called at least once before parsing, etc. is done. +// Will also do thread initialization for the calling thread; other +// threads will need to do that explicitly. bool InitProcess() { glslang::GetGlobalLock(); @@ -85,7 +89,9 @@ bool InitProcess() return true; } - +// Per-thread scoped initialization. +// Must be called at least once by each new thread sharing the +// symbol tables, etc., needed to parse. bool InitThread() { // @@ -99,17 +105,21 @@ bool InitThread() if (OS_GetTLSValue(ThreadInitializeIndex) != 0) return true; - InitializeMemoryPools(); - if (! OS_SetTLSValue(ThreadInitializeIndex, (void *)1)) { assert(0 && "InitThread(): Unable to set init flag."); return false; } + glslang::SetThreadPoolAllocator(nullptr); + return true; } - +// Not necessary to call this: InitThread() is reentrant, and the need +// to do per thread tear down has been removed. +// +// This is kept, with memory management removed, to satisfy any exiting +// calls to it that rely on it. bool DetachThread() { bool success = true; @@ -125,14 +135,18 @@ bool DetachThread() assert(0 && "DetachThread(): Unable to clear init flag."); success = false; } - - FreeGlobalPools(); - } return success; } +// Not necessary to call this: InitProcess() is reentrant. +// +// This is kept, with memory management removed, to satisfy any exiting +// calls to it that rely on it. +// +// Users of glslang should call shFinalize() or glslang::FinalizeProcess() for +// process-scoped memory tear down. bool DetachProcess() { bool success = true; @@ -140,12 +154,8 @@ bool DetachProcess() if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) return true; - ShFinalize(); - success = DetachThread(); - FreePoolIndex(); - OS_FreeTLSIndex(ThreadInitializeIndex); ThreadInitializeIndex = OS_INVALID_TLS_INDEX; diff --git a/Externals/glslang/OGLCompilersDLL/InitializeDll.h b/Externals/glslang/OGLCompilersDLL/InitializeDll.h index 2d24557435..661cee4d24 100644 --- a/Externals/glslang/OGLCompilersDLL/InitializeDll.h +++ b/Externals/glslang/OGLCompilersDLL/InitializeDll.h @@ -1,10 +1,10 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -18,31 +18,30 @@ // 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. +// 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 __INITIALIZEDLL_H #define __INITIALIZEDLL_H - #include "../glslang/OSDependent/osinclude.h" namespace glslang { bool InitProcess(); bool InitThread(); -bool DetachThread(); -bool DetachProcess(); +bool DetachThread(); // not called from standalone, perhaps other tools rely on parts of it +bool DetachProcess(); // not called from standalone, perhaps other tools rely on parts of it } // end namespace glslang diff --git a/Externals/glslang/README-spirv-remap.txt b/Externals/glslang/README-spirv-remap.txt index 8e3259f895..3e5288aac5 100644 --- a/Externals/glslang/README-spirv-remap.txt +++ b/Externals/glslang/README-spirv-remap.txt @@ -98,7 +98,7 @@ options. See REMAPPING AND OPTIMIZATION OPTIONS. On error, the function supplied to registerErrorHandler() will be invoked. This can be a standard C/C++ function, a lambda function, or a functor. The default handler simply calls exit(5); The error handler is a static -members, so need only be set up once, not once per spirvbin_t instance. +member, so need only be set up once, not once per spirvbin_t instance. Log messages are supplied to registerLogHandler(). By default, log messages are eaten silently. The log handler is also a static member. diff --git a/Externals/glslang/README.md b/Externals/glslang/README.md index 3bdbae59e0..402b4d6005 100644 --- a/Externals/glslang/README.md +++ b/Externals/glslang/README.md @@ -13,12 +13,15 @@ glslang An OpenGL and OpenGL ES shader front end and validator. -There are two components: +There are several components: -1. A front-end library for programmatic parsing of GLSL/ESSL into an AST. +1. A GLSL/ESSL front-end for reference validation and translation of GLSL/ESSL into an AST. -2. A standalone wrapper, `glslangValidator`, that can be used as a shader - validation tool. +2. An HLSL front-end for translation of a broad generic HLL into the AST. See [issue 362](https://github.com/KhronosGroup/glslang/issues/362) and [issue 701](https://github.com/KhronosGroup/glslang/issues/701) for current status. + +3. A SPIR-V back end for translating the AST to SPIR-V. + +4. A standalone wrapper, `glslangValidator`, that can be used as a command-line tool for the above. How to add a feature protected by a version/extension/stage/profile: See the comment in `glslang/MachineIndependent/Versions.cpp`. @@ -46,49 +49,80 @@ There is also a non-shader extension Building -------- +Instead of building manually, you can also download the binaries for your +platform directly from the [master-tot release][master-tot-release] on GitHub. +Those binaries are automatically uploaded by the buildbots after successful +testing and they always reflect the current top of the tree of the master +branch. + ### Dependencies +* A C++11 compiler. + (For MSVS: 2015 is recommended, 2013 is fully supported/tested, and 2010 support is attempted, but not tested.) * [CMake][cmake]: for generating compilation targets. +* make: _Linux_, ninja is an alternative, if configured. +* [Python 2.7][python]: for executing SPIRV-Tools scripts. (Optional if not using SPIRV-Tools.) * [bison][bison]: _optional_, but needed when changing the grammar (glslang.y). * [googletest][googletest]: _optional_, but should use if making any changes to glslang. ### Build steps -#### 1) Check-Out External Projects +The following steps assume a Bash shell. On Windows, that could be the Git Bash +shell or some other shell of your choosing. + +#### 1) Check-Out this project ```bash -cd +cd +git clone https://github.com/KhronosGroup/glslang.git +``` + +#### 2) Check-Out External Projects + +```bash +cd git clone https://github.com/google/googletest.git External/googletest ``` -#### 2) Configure - -Assume the source directory is `$SOURCE_DIR` and -the build directory is `$BUILD_DIR`: - -For building on Linux (assuming using the Ninja generator): +If you wish to assure that SPIR-V generated from HLSL is legal for Vulkan, +or wish to invoke -Os to reduce SPIR-V size from HLSL or GLSL, install +spirv-tools with this: ```bash -cd $BUILD_DIR +./update_glslang_sources.py +``` -cmake -GNinja -DCMAKE_BUILD_TYPE={Debug|Release|RelWithDebInfo} \ - -DCMAKE_INSTALL_PREFIX=`pwd`/install $SOURCE_DIR +#### 3) Configure + +Assume the source directory is `$SOURCE_DIR` and the build directory is +`$BUILD_DIR`. First ensure the build directory exists, then navigate to it: + +```bash +mkdir -p $BUILD_DIR +cd $BUILD_DIR +``` + +For building on Linux: + +```bash +cmake -DCMAKE_BUILD_TYPE={Debug|Release|RelWithDebInfo} \ + -DCMAKE_INSTALL_PREFIX="$(pwd)/install" $SOURCE_DIR ``` For building on Windows: ```bash -cmake $SOURCE_DIR -DCMAKE_INSTALL_PREFIX=`pwd`/install +cmake $SOURCE_DIR -DCMAKE_INSTALL_PREFIX="$(pwd)/install" # The CMAKE_INSTALL_PREFIX part is for testing (explained later). ``` The CMake GUI also works for Windows (version 3.4.1 tested). -#### 3) Build and Install +#### 4) Build and Install ```bash # for Linux: -ninja install +make -j4 install # for Windows: cmake --build . --config {Release|Debug|MinSizeRel|RelWithDebInfo} \ @@ -207,8 +241,11 @@ bool InitializeProcess(); void FinalizeProcess(); class TShader + setStrings(...); + setEnvInput(EShSourceHlsl or EShSourceGlsl, stage, EShClientVulkan or EShClientOpenGL, 100); + setEnvClient(EShClientVulkan or EShClientOpenGL, EShTargetVulkan_1_0 or EShTargetVulkan_1_1 or EShTargetOpenGL_450); + setEnvTarget(EShTargetSpv, EShTargetSpv_1_0 or EShTargetSpv_1_3); bool parse(...); - void setStrings(...); const char* getInfoLog(); class TProgram @@ -288,6 +325,8 @@ Basic Internal Operation [cmake]: https://cmake.org/ +[python]: https://www.python.org/ [bison]: https://www.gnu.org/software/bison/ [googletest]: https://github.com/google/googletest [bison-gnu-win32]: http://gnuwin32.sourceforge.net/packages/bison.htm +[master-tot-release]: https://github.com/KhronosGroup/glslang/releases/tag/master-tot diff --git a/Externals/glslang/SPIRV/CMakeLists.txt b/Externals/glslang/SPIRV/CMakeLists.txt index 5c169b141a..1e5513c735 100755 --- a/Externals/glslang/SPIRV/CMakeLists.txt +++ b/Externals/glslang/SPIRV/CMakeLists.txt @@ -3,27 +3,81 @@ set(SOURCES InReadableOrder.cpp Logger.cpp SpvBuilder.cpp - SPVRemapper.cpp doc.cpp disassemble.cpp) +set(SPVREMAP_SOURCES + SPVRemapper.cpp + doc.cpp) + set(HEADERS + bitutils.h spirv.hpp GLSL.std.450.h + GLSL.ext.EXT.h + GLSL.ext.KHR.h GlslangToSpv.h + hex_float.h Logger.h SpvBuilder.h - SPVRemapper.h spvIR.h doc.h disassemble.h) -add_library(SPIRV STATIC ${SOURCES} ${HEADERS}) +set(SPVREMAP_HEADERS + SPVRemapper.h + doc.h) + +if(ENABLE_AMD_EXTENSIONS) + list(APPEND + HEADERS + GLSL.ext.AMD.h) +endif(ENABLE_AMD_EXTENSIONS) + +if(ENABLE_NV_EXTENSIONS) + list(APPEND + HEADERS + GLSL.ext.NV.h) +endif(ENABLE_NV_EXTENSIONS) + +add_library(SPIRV ${LIB_TYPE} ${SOURCES} ${HEADERS}) set_property(TARGET SPIRV PROPERTY FOLDER glslang) +set_property(TARGET SPIRV PROPERTY POSITION_INDEPENDENT_CODE ON) +target_include_directories(SPIRV PUBLIC ..) + +add_library(SPVRemapper ${LIB_TYPE} ${SPVREMAP_SOURCES} ${SPVREMAP_HEADERS}) +set_property(TARGET SPVRemapper PROPERTY FOLDER glslang) +set_property(TARGET SPVRemapper PROPERTY POSITION_INDEPENDENT_CODE ON) + +if(WIN32 AND BUILD_SHARED_LIBS) + set_target_properties(SPIRV PROPERTIES PREFIX "") + set_target_properties(SPVRemapper PROPERTIES PREFIX "") +endif() + +if(ENABLE_OPT) + target_include_directories(SPIRV + PRIVATE ${spirv-tools_SOURCE_DIR}/include + PRIVATE ${spirv-tools_SOURCE_DIR}/source + ) + target_link_libraries(SPIRV glslang SPIRV-Tools-opt) +else() + target_link_libraries(SPIRV glslang) +endif(ENABLE_OPT) if(WIN32) source_group("Source" FILES ${SOURCES} ${HEADERS}) + source_group("Source" FILES ${SPVREMAP_SOURCES} ${SPVREMAP_HEADERS}) endif(WIN32) -install(TARGETS SPIRV - ARCHIVE DESTINATION lib) +if(ENABLE_GLSLANG_INSTALL) + if(BUILD_SHARED_LIBS) + install(TARGETS SPIRV SPVRemapper + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + else() + install(TARGETS SPIRV SPVRemapper + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif() + + install(FILES ${HEADERS} ${SPVREMAP_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/SPIRV/) +endif(ENABLE_GLSLANG_INSTALL) diff --git a/Externals/glslang/SPIRV/GLSL.ext.AMD.h b/Externals/glslang/SPIRV/GLSL.ext.AMD.h new file mode 100644 index 0000000000..009d2f1cf0 --- /dev/null +++ b/Externals/glslang/SPIRV/GLSL.ext.AMD.h @@ -0,0 +1,108 @@ +/* +** Copyright (c) 2014-2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and/or associated documentation files (the "Materials"), +** to deal in the Materials without restriction, including without limitation +** the rights to use, copy, modify, merge, publish, distribute, sublicense, +** and/or sell copies of the Materials, and to permit persons to whom the +** Materials are furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Materials. +** +** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS +** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND +** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS +** IN THE MATERIALS. +*/ + +#ifndef GLSLextAMD_H +#define GLSLextAMD_H + +static const int GLSLextAMDVersion = 100; +static const int GLSLextAMDRevision = 7; + +// SPV_AMD_shader_ballot +static const char* const E_SPV_AMD_shader_ballot = "SPV_AMD_shader_ballot"; + +enum ShaderBallotAMD { + ShaderBallotBadAMD = 0, // Don't use + + SwizzleInvocationsAMD = 1, + SwizzleInvocationsMaskedAMD = 2, + WriteInvocationAMD = 3, + MbcntAMD = 4, + + ShaderBallotCountAMD +}; + +// SPV_AMD_shader_trinary_minmax +static const char* const E_SPV_AMD_shader_trinary_minmax = "SPV_AMD_shader_trinary_minmax"; + +enum ShaderTrinaryMinMaxAMD { + ShaderTrinaryMinMaxBadAMD = 0, // Don't use + + FMin3AMD = 1, + UMin3AMD = 2, + SMin3AMD = 3, + FMax3AMD = 4, + UMax3AMD = 5, + SMax3AMD = 6, + FMid3AMD = 7, + UMid3AMD = 8, + SMid3AMD = 9, + + ShaderTrinaryMinMaxCountAMD +}; + +// SPV_AMD_shader_explicit_vertex_parameter +static const char* const E_SPV_AMD_shader_explicit_vertex_parameter = "SPV_AMD_shader_explicit_vertex_parameter"; + +enum ShaderExplicitVertexParameterAMD { + ShaderExplicitVertexParameterBadAMD = 0, // Don't use + + InterpolateAtVertexAMD = 1, + + ShaderExplicitVertexParameterCountAMD +}; + +// SPV_AMD_gcn_shader +static const char* const E_SPV_AMD_gcn_shader = "SPV_AMD_gcn_shader"; + +enum GcnShaderAMD { + GcnShaderBadAMD = 0, // Don't use + + CubeFaceIndexAMD = 1, + CubeFaceCoordAMD = 2, + TimeAMD = 3, + + GcnShaderCountAMD +}; + +// SPV_AMD_gpu_shader_half_float +static const char* const E_SPV_AMD_gpu_shader_half_float = "SPV_AMD_gpu_shader_half_float"; + +// SPV_AMD_texture_gather_bias_lod +static const char* const E_SPV_AMD_texture_gather_bias_lod = "SPV_AMD_texture_gather_bias_lod"; + +// SPV_AMD_gpu_shader_int16 +static const char* const E_SPV_AMD_gpu_shader_int16 = "SPV_AMD_gpu_shader_int16"; + +// SPV_AMD_shader_image_load_store_lod +static const char* const E_SPV_AMD_shader_image_load_store_lod = "SPV_AMD_shader_image_load_store_lod"; + +// SPV_AMD_shader_fragment_mask +static const char* const E_SPV_AMD_shader_fragment_mask = "SPV_AMD_shader_fragment_mask"; + +// SPV_AMD_gpu_shader_half_float_fetch +static const char* const E_SPV_AMD_gpu_shader_half_float_fetch = "SPV_AMD_gpu_shader_half_float_fetch"; + +#endif // #ifndef GLSLextAMD_H diff --git a/Externals/glslang/SPIRV/GLSL.ext.EXT.h b/Externals/glslang/SPIRV/GLSL.ext.EXT.h new file mode 100644 index 0000000000..c4a243080c --- /dev/null +++ b/Externals/glslang/SPIRV/GLSL.ext.EXT.h @@ -0,0 +1,37 @@ +/* +** Copyright (c) 2014-2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and/or associated documentation files (the "Materials"), +** to deal in the Materials without restriction, including without limitation +** the rights to use, copy, modify, merge, publish, distribute, sublicense, +** and/or sell copies of the Materials, and to permit persons to whom the +** Materials are furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Materials. +** +** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS +** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND +** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS +** IN THE MATERIALS. +*/ + +#ifndef GLSLextEXT_H +#define GLSLextEXT_H + +static const int GLSLextEXTVersion = 100; +static const int GLSLextEXTRevision = 1; + +static const char* const E_SPV_EXT_shader_stencil_export = "SPV_EXT_shader_stencil_export"; +static const char* const E_SPV_EXT_shader_viewport_index_layer = "SPV_EXT_shader_viewport_index_layer"; +static const char* const E_SPV_EXT_fragment_fully_covered = "SPV_EXT_fragment_fully_covered"; + +#endif // #ifndef GLSLextEXT_H diff --git a/Externals/glslang/SPIRV/GLSL.ext.KHR.h b/Externals/glslang/SPIRV/GLSL.ext.KHR.h new file mode 100644 index 0000000000..d8ea9b67d6 --- /dev/null +++ b/Externals/glslang/SPIRV/GLSL.ext.KHR.h @@ -0,0 +1,42 @@ +/* +** Copyright (c) 2014-2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and/or associated documentation files (the "Materials"), +** to deal in the Materials without restriction, including without limitation +** the rights to use, copy, modify, merge, publish, distribute, sublicense, +** and/or sell copies of the Materials, and to permit persons to whom the +** Materials are furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Materials. +** +** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS +** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND +** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS +** IN THE MATERIALS. +*/ + +#ifndef GLSLextKHR_H +#define GLSLextKHR_H + +static const int GLSLextKHRVersion = 100; +static const int GLSLextKHRRevision = 2; + +static const char* const E_SPV_KHR_shader_ballot = "SPV_KHR_shader_ballot"; +static const char* const E_SPV_KHR_subgroup_vote = "SPV_KHR_subgroup_vote"; +static const char* const E_SPV_KHR_device_group = "SPV_KHR_device_group"; +static const char* const E_SPV_KHR_multiview = "SPV_KHR_multiview"; +static const char* const E_SPV_KHR_shader_draw_parameters = "SPV_KHR_shader_draw_parameters"; +static const char* const E_SPV_KHR_16bit_storage = "SPV_KHR_16bit_storage"; +static const char* const E_SPV_KHR_storage_buffer_storage_class = "SPV_KHR_storage_buffer_storage_class"; +static const char* const E_SPV_KHR_post_depth_coverage = "SPV_KHR_post_depth_coverage"; + +#endif // #ifndef GLSLextKHR_H diff --git a/Externals/glslang/SPIRV/GLSL.ext.NV.h b/Externals/glslang/SPIRV/GLSL.ext.NV.h new file mode 100644 index 0000000000..148d4b457f --- /dev/null +++ b/Externals/glslang/SPIRV/GLSL.ext.NV.h @@ -0,0 +1,57 @@ +/* +** Copyright (c) 2014-2017 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and/or associated documentation files (the "Materials"), +** to deal in the Materials without restriction, including without limitation +** the rights to use, copy, modify, merge, publish, distribute, sublicense, +** and/or sell copies of the Materials, and to permit persons to whom the +** Materials are furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Materials. +** +** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS +** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND +** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS +** IN THE MATERIALS. +*/ + +#ifndef GLSLextNV_H +#define GLSLextNV_H + +enum BuiltIn; +enum Decoration; +enum Op; +enum Capability; + +static const int GLSLextNVVersion = 100; +static const int GLSLextNVRevision = 5; + +//SPV_NV_sample_mask_override_coverage +const char* const E_SPV_NV_sample_mask_override_coverage = "SPV_NV_sample_mask_override_coverage"; + +//SPV_NV_geometry_shader_passthrough +const char* const E_SPV_NV_geometry_shader_passthrough = "SPV_NV_geometry_shader_passthrough"; + +//SPV_NV_viewport_array2 +const char* const E_SPV_NV_viewport_array2 = "SPV_NV_viewport_array2"; +const char* const E_ARB_shader_viewport_layer_array = "SPV_ARB_shader_viewport_layer_array"; + +//SPV_NV_stereo_view_rendering +const char* const E_SPV_NV_stereo_view_rendering = "SPV_NV_stereo_view_rendering"; + +//SPV_NVX_multiview_per_view_attributes +const char* const E_SPV_NVX_multiview_per_view_attributes = "SPV_NVX_multiview_per_view_attributes"; + +//SPV_NV_shader_subgroup_partitioned +const char* const E_SPV_NV_shader_subgroup_partitioned = "SPV_NV_shader_subgroup_partitioned"; + +#endif // #ifndef GLSLextNV_H \ No newline at end of file diff --git a/Externals/glslang/SPIRV/GlslangToSpv.cpp b/Externals/glslang/SPIRV/GlslangToSpv.cpp index aebc986cbc..aa8ed0bbc0 100755 --- a/Externals/glslang/SPIRV/GlslangToSpv.cpp +++ b/Externals/glslang/SPIRV/GlslangToSpv.cpp @@ -1,12 +1,13 @@ // -//Copyright (C) 2014-2016 LunarG, Inc. -//Copyright (C) 2015-2016 Google, Inc. +// Copyright (C) 2014-2016 LunarG, Inc. +// Copyright (C) 2015-2016 Google, Inc. +// Copyright (C) 2017 ARM Limited. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,18 +21,18 @@ // 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. +// 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. // // Visit the nodes in the glslang intermediate tree representation to @@ -42,9 +43,26 @@ #include "GlslangToSpv.h" #include "SpvBuilder.h" namespace spv { - #include "GLSL.std.450.h" + #include "GLSL.std.450.h" + #include "GLSL.ext.KHR.h" + #include "GLSL.ext.EXT.h" +#ifdef AMD_EXTENSIONS + #include "GLSL.ext.AMD.h" +#endif +#ifdef NV_EXTENSIONS + #include "GLSL.ext.NV.h" +#endif } +#if ENABLE_OPT + #include "spirv-tools/optimizer.hpp" + #include "message.h" +#endif + +#if ENABLE_OPT +using namespace spvtools; +#endif + // Glslang includes #include "../glslang/MachineIndependent/localintermediate.h" #include "../glslang/MachineIndependent/SymbolTable.h" @@ -61,11 +79,6 @@ namespace spv { namespace { -// For low-order part of the generator's magic number. Bump up -// when there is a change in the style (e.g., if SSA form changes, -// or a different instruction sequence to do something gets used). -const int GeneratorVersion = 1; - namespace { class SpecConstantOpModeGuard { public: @@ -85,7 +98,14 @@ private: spv::Builder* builder_; bool previous_flag_; }; -} + +struct OpDecorations { + spv::Decoration precision; + spv::Decoration noContraction; + spv::Decoration nonUniform; +}; + +} // namespace // // The main holder of information for translating glslang to SPIR-V. @@ -94,8 +114,9 @@ private: // class TGlslangToSpvTraverser : public glslang::TIntermTraverser { public: - TGlslangToSpvTraverser(const glslang::TIntermediate*, spv::SpvBuildLogger* logger); - virtual ~TGlslangToSpvTraverser(); + TGlslangToSpvTraverser(unsigned int spvVersion, const glslang::TIntermediate*, spv::SpvBuildLogger* logger, + glslang::SpvOptions& options); + virtual ~TGlslangToSpvTraverser() { } bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*); bool visitBinary(glslang::TVisit, glslang::TIntermBinary*); @@ -107,16 +128,32 @@ public: bool visitLoop(glslang::TVisit, glslang::TIntermLoop*); bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*); + void finishSpv(); void dumpSpv(std::vector& out); protected: + TGlslangToSpvTraverser(TGlslangToSpvTraverser&); + TGlslangToSpvTraverser& operator=(TGlslangToSpvTraverser&); + + spv::Decoration TranslateInterpolationDecoration(const glslang::TQualifier& qualifier); spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier); + spv::Decoration TranslateNonUniformDecoration(const glslang::TQualifier& qualifier); spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable, bool memberDeclaration); spv::ImageFormat TranslateImageFormat(const glslang::TType& type); + spv::SelectionControlMask TranslateSelectionControl(const glslang::TIntermSelection&) const; + spv::SelectionControlMask TranslateSwitchControl(const glslang::TIntermSwitch&) const; + spv::LoopControlMask TranslateLoopControl(const glslang::TIntermLoop&, unsigned int& dependencyLength) const; + spv::StorageClass TranslateStorageClass(const glslang::TType&); + void addIndirectionIndexCapabilities(const glslang::TType& baseType, const glslang::TType& indexType); spv::Id createSpvVariable(const glslang::TIntermSymbol*); spv::Id getSampledType(const glslang::TSampler&); + spv::Id getInvertedSwizzleType(const glslang::TIntermTyped&); + spv::Id createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped&, spv::Id parentResult); + void convertSwizzle(const glslang::TIntermAggregate&, std::vector& swizzle); spv::Id convertGlslangToSpvType(const glslang::TType& type); - spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking, const glslang::TQualifier&); + spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking, const glslang::TQualifier&, + bool lastBufferBlockMember); + bool filterMember(const glslang::TType& member); spv::Id convertGlslangStructToSpvType(const glslang::TType&, const glslang::TTypeList* glslangStruct, glslang::TLayoutPacking, const glslang::TQualifier&); void decorateStructType(const glslang::TType&, const glslang::TTypeList* glslangStruct, glslang::TLayoutPacking, @@ -124,13 +161,17 @@ protected: spv::Id makeArraySizeId(const glslang::TArraySizes&, int dim); spv::Id accessChainLoad(const glslang::TType& type); void accessChainStore(const glslang::TType& type, spv::Id rvalue); + void multiTypeStore(const glslang::TType&, spv::Id rValue); glslang::TLayoutPacking getExplicitLayout(const glslang::TType& type) const; int getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking, glslang::TLayoutMatrix); int getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking, glslang::TLayoutMatrix); - void updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset, glslang::TLayoutPacking, glslang::TLayoutMatrix); + void updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, + int& nextOffset, glslang::TLayoutPacking, glslang::TLayoutMatrix); void declareUseOfStructMember(const glslang::TTypeList& members, int glslangMember); - bool isShaderEntrypoint(const glslang::TIntermAggregate* node); + bool isShaderEntryPoint(const glslang::TIntermAggregate* node); + bool writableParam(glslang::TStorageQualifier) const; + bool originalParam(glslang::TStorageQualifier, const glslang::TType&, bool implicitThisParam); void makeFunctions(const glslang::TIntermSequence&); void makeGlobalInitializers(const glslang::TIntermSequence&); void visitFunctions(const glslang::TIntermSequence&); @@ -140,28 +181,41 @@ protected: spv::Id createImageTextureFunctionCall(glslang::TIntermOperator* node); spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*); - spv::Id createBinaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison = true); - spv::Id createBinaryMatrixOperation(spv::Op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id left, spv::Id right); - spv::Id createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand,glslang::TBasicType typeProxy); - spv::Id createUnaryMatrixOperation(spv::Op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand,glslang::TBasicType typeProxy); - spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id destTypeId, spv::Id operand, glslang::TBasicType typeProxy); + spv::Id createBinaryOperation(glslang::TOperator op, OpDecorations&, spv::Id typeId, spv::Id left, spv::Id right, + glslang::TBasicType typeProxy, bool reduceComparison = true); + spv::Id createBinaryMatrixOperation(spv::Op, OpDecorations&, spv::Id typeId, spv::Id left, spv::Id right); + spv::Id createUnaryOperation(glslang::TOperator op, OpDecorations&, spv::Id typeId, spv::Id operand, + glslang::TBasicType typeProxy); + spv::Id createUnaryMatrixOperation(spv::Op op, OpDecorations&, spv::Id typeId, spv::Id operand, + glslang::TBasicType typeProxy); + spv::Id createConversion(glslang::TOperator op, OpDecorations&, spv::Id destTypeId, spv::Id operand, + glslang::TBasicType typeProxy); + spv::Id createConversionOperation(glslang::TOperator op, spv::Id operand, int vectorSize); spv::Id makeSmearedConstant(spv::Id constant, int vectorSize); spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy); - spv::Id createInvocationsOperation(glslang::TOperator, spv::Id typeId, spv::Id operand); + spv::Id createInvocationsOperation(glslang::TOperator op, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy); + spv::Id CreateInvocationsVectorOperation(spv::Op op, spv::GroupOperation groupOperation, spv::Id typeId, std::vector& operands); + spv::Id createSubgroupOperation(glslang::TOperator op, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy); spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy); - spv::Id createNoArgOperation(glslang::TOperator op); + spv::Id createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId); spv::Id getSymbolId(const glslang::TIntermSymbol* node); - void addDecoration(spv::Id id, spv::Decoration dec); - void addDecoration(spv::Id id, spv::Decoration dec, unsigned value); - void addMemberDecoration(spv::Id id, int member, spv::Decoration dec); - void addMemberDecoration(spv::Id id, int member, spv::Decoration dec, unsigned value); spv::Id createSpvConstant(const glslang::TIntermTyped&); spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant); bool isTrivialLeaf(const glslang::TIntermTyped* node); bool isTrivial(const glslang::TIntermTyped* node); spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right); +#ifdef AMD_EXTENSIONS + spv::Id getExtBuiltins(const char* name); +#endif + void addPre13Extension(const char* ext) + { + if (builder.getSpvVersion() < glslang::EShTargetSpv_1_3) + builder.addExtension(ext); + } + glslang::SpvOptions& options; spv::Function* shaderEntry; + spv::Function* currentFunction; spv::Instruction* entryPoint; int sequenceDepth; @@ -169,19 +223,22 @@ protected: // There is a 1:1 mapping between a spv builder and a module; this is thread safe spv::Builder builder; - bool inMain; - bool mainTerminated; + bool inEntryPoint; + bool entryPointTerminated; bool linkageOnly; // true when visiting the set of objects in the AST present only for establishing interface, whether or not they were statically used std::set iOSet; // all input/output variables from either static use or declaration of interface const glslang::TIntermediate* glslangIntermediate; spv::Id stdBuiltins; + std::unordered_map extBuiltinMap; std::unordered_map symbolValues; - std::unordered_set constReadOnlyParameters; // set of formal function parameters that have glslang qualifier constReadOnly, so we know they are not local function "const" that are write-once + std::unordered_set rValueParameters; // set of formal function parameters passed as rValues, rather than a pointer std::unordered_map functionMap; std::unordered_map structMap[glslang::ElpCount][glslang::ElmCount]; - std::unordered_map > memberRemapper; // for mapping glslang block indices to spv indices (e.g., due to hidden members) + // for mapping glslang block indices to spv indices (e.g., due to hidden members): + std::unordered_map > memberRemapper; std::stack breakForLoop; // false means break for switch + std::unordered_map counterOriginator; }; // @@ -226,38 +283,6 @@ spv::ExecutionModel TranslateExecutionModel(EShLanguage stage) } } -// Translate glslang type to SPIR-V storage class. -spv::StorageClass TranslateStorageClass(const glslang::TType& type) -{ - if (type.getQualifier().isPipeInput()) - return spv::StorageClassInput; - else if (type.getQualifier().isPipeOutput()) - return spv::StorageClassOutput; - else if (type.getBasicType() == glslang::EbtSampler) - return spv::StorageClassUniformConstant; - else if (type.getBasicType() == glslang::EbtAtomicUint) - return spv::StorageClassAtomicCounter; - else if (type.getQualifier().isUniformOrBuffer()) { - if (type.getQualifier().layoutPushConstant) - return spv::StorageClassPushConstant; - if (type.getBasicType() == glslang::EbtBlock) - return spv::StorageClassUniform; - else - return spv::StorageClassUniformConstant; - // TODO: how are we distinguishing between default and non-default non-writable uniforms? Do default uniforms even exist? - } else { - switch (type.getQualifier().storage) { - case glslang::EvqShared: return spv::StorageClassWorkgroup; break; - case glslang::EvqGlobal: return spv::StorageClassPrivate; - case glslang::EvqConstReadOnly: return spv::StorageClassFunction; - case glslang::EvqTemporary: return spv::StorageClassFunction; - default: - assert(0); - return spv::StorageClassFunction; - } - } -} - // Translate glslang sampler type to SPIR-V dimensionality. spv::Dim TranslateDimensionality(const glslang::TSampler& sampler) { @@ -275,10 +300,10 @@ spv::Dim TranslateDimensionality(const glslang::TSampler& sampler) } } -// Translate glslang type to SPIR-V precision decorations. -spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type) +// Translate glslang precision to SPIR-V precision decorations. +spv::Decoration TranslatePrecisionDecoration(glslang::TPrecisionQualifier glslangPrecision) { - switch (type.getQualifier().precision) { + switch (glslangPrecision) { case glslang::EpqLow: return spv::DecorationRelaxedPrecision; case glslang::EpqMedium: return spv::DecorationRelaxedPrecision; default: @@ -286,13 +311,19 @@ spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type) } } +// Translate glslang type to SPIR-V precision decorations. +spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type) +{ + return TranslatePrecisionDecoration(type.getQualifier().precision); +} + // Translate glslang type to SPIR-V block decorations. -spv::Decoration TranslateBlockDecoration(const glslang::TType& type) +spv::Decoration TranslateBlockDecoration(const glslang::TType& type, bool useStorageBuffer) { if (type.getBasicType() == glslang::EbtBlock) { switch (type.getQualifier().storage) { case glslang::EvqUniform: return spv::DecorationBlock; - case glslang::EvqBuffer: return spv::DecorationBufferBlock; + case glslang::EvqBuffer: return useStorageBuffer ? spv::DecorationBlock : spv::DecorationBufferBlock; case glslang::EvqVaryingIn: return spv::DecorationBlock; case glslang::EvqVaryingOut: return spv::DecorationBlock; default: @@ -362,7 +393,7 @@ spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::T // Translate glslang type to SPIR-V interpolation decorations. // Returns spv::DecorationMax when no decoration // should be applied. -spv::Decoration TranslateInterpolationDecoration(const glslang::TQualifier& qualifier) +spv::Decoration TGlslangToSpvTraverser::TranslateInterpolationDecoration(const glslang::TQualifier& qualifier) { if (qualifier.smooth) // Smooth decoration doesn't exist in SPIR-V 1.0 @@ -371,6 +402,12 @@ spv::Decoration TranslateInterpolationDecoration(const glslang::TQualifier& qual return spv::DecorationNoPerspective; else if (qualifier.flat) return spv::DecorationFlat; +#ifdef AMD_EXTENSIONS + else if (qualifier.explicitInterp) { + builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter); + return spv::DecorationExplicitInterpAMD; + } +#endif else return spv::DecorationMax; } @@ -409,6 +446,17 @@ spv::Decoration TranslateNoContractionDecoration(const glslang::TQualifier& qual return spv::DecorationMax; } +// If glslang type is nonUniform, return SPIR-V NonUniform decoration. +spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(const glslang::TQualifier& qualifier) +{ + if (qualifier.isNonUniform()) { + builder.addExtension("SPV_EXT_descriptor_indexing"); + builder.addCapability(spv::CapabilityShaderNonUniformEXT); + return spv::DecorationNonUniformEXT; + } else + return spv::DecorationMax; +} + // Translate a glslang built-in variable to a SPIR-V built in decoration. Also generate // associated capabilities when required. For some built-in variables, a capability // is generated only when using the variable in an executable instruction, but not when @@ -442,16 +490,23 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI // case glslang::EbvClipDistance: if (!memberDeclaration) - builder.addCapability(spv::CapabilityClipDistance); + builder.addCapability(spv::CapabilityClipDistance); return spv::BuiltInClipDistance; case glslang::EbvCullDistance: if (!memberDeclaration) - builder.addCapability(spv::CapabilityCullDistance); + builder.addCapability(spv::CapabilityCullDistance); return spv::BuiltInCullDistance; case glslang::EbvViewportIndex: builder.addCapability(spv::CapabilityMultiViewport); + if (glslangIntermediate->getStage() == EShLangVertex || + glslangIntermediate->getStage() == EShLangTessControl || + glslangIntermediate->getStage() == EShLangTessEvaluation) { + + builder.addExtension(spv::E_SPV_EXT_shader_viewport_index_layer); + builder.addCapability(spv::CapabilityShaderViewportIndexLayerEXT); + } return spv::BuiltInViewportIndex; case glslang::EbvSampleId: @@ -463,11 +518,17 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI return spv::BuiltInSamplePosition; case glslang::EbvSampleMask: - builder.addCapability(spv::CapabilitySampleRateShading); return spv::BuiltInSampleMask; case glslang::EbvLayer: builder.addCapability(spv::CapabilityGeometry); + if (glslangIntermediate->getStage() == EShLangVertex || + glslangIntermediate->getStage() == EShLangTessControl || + glslangIntermediate->getStage() == EShLangTessEvaluation) { + + builder.addExtension(spv::E_SPV_EXT_shader_viewport_index_layer); + builder.addCapability(spv::CapabilityShaderViewportIndexLayerEXT); + } return spv::BuiltInLayer; case glslang::EbvPosition: return spv::BuiltInPosition; @@ -475,13 +536,32 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI case glslang::EbvInstanceId: return spv::BuiltInInstanceId; case glslang::EbvVertexIndex: return spv::BuiltInVertexIndex; case glslang::EbvInstanceIndex: return spv::BuiltInInstanceIndex; + case glslang::EbvBaseVertex: + addPre13Extension(spv::E_SPV_KHR_shader_draw_parameters); + builder.addCapability(spv::CapabilityDrawParameters); + return spv::BuiltInBaseVertex; + case glslang::EbvBaseInstance: + addPre13Extension(spv::E_SPV_KHR_shader_draw_parameters); + builder.addCapability(spv::CapabilityDrawParameters); + return spv::BuiltInBaseInstance; + case glslang::EbvDrawId: - // TODO: Add SPIR-V builtin ID. - logger->missingFunctionality("shader draw parameters"); - return spv::BuiltInMax; - case glslang::EbvPrimitiveId: return spv::BuiltInPrimitiveId; + addPre13Extension(spv::E_SPV_KHR_shader_draw_parameters); + builder.addCapability(spv::CapabilityDrawParameters); + return spv::BuiltInDrawIndex; + + case glslang::EbvPrimitiveId: + if (glslangIntermediate->getStage() == EShLangFragment) + builder.addCapability(spv::CapabilityGeometry); + return spv::BuiltInPrimitiveId; + + case glslang::EbvFragStencilRef: + builder.addExtension(spv::E_SPV_EXT_shader_stencil_export); + builder.addCapability(spv::CapabilityStencilExportEXT); + return spv::BuiltInFragStencilRefEXT; + case glslang::EbvInvocationId: return spv::BuiltInInvocationId; case glslang::EbvTessLevelInner: return spv::BuiltInTessLevelInner; case glslang::EbvTessLevelOuter: return spv::BuiltInTessLevelOuter; @@ -498,17 +578,160 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI case glslang::EbvLocalInvocationId: return spv::BuiltInLocalInvocationId; case glslang::EbvLocalInvocationIndex: return spv::BuiltInLocalInvocationIndex; case glslang::EbvGlobalInvocationId: return spv::BuiltInGlobalInvocationId; + case glslang::EbvSubGroupSize: + builder.addExtension(spv::E_SPV_KHR_shader_ballot); + builder.addCapability(spv::CapabilitySubgroupBallotKHR); + return spv::BuiltInSubgroupSize; + case glslang::EbvSubGroupInvocation: + builder.addExtension(spv::E_SPV_KHR_shader_ballot); + builder.addCapability(spv::CapabilitySubgroupBallotKHR); + return spv::BuiltInSubgroupLocalInvocationId; + case glslang::EbvSubGroupEqMask: + builder.addExtension(spv::E_SPV_KHR_shader_ballot); + builder.addCapability(spv::CapabilitySubgroupBallotKHR); + return spv::BuiltInSubgroupEqMaskKHR; + case glslang::EbvSubGroupGeMask: + builder.addExtension(spv::E_SPV_KHR_shader_ballot); + builder.addCapability(spv::CapabilitySubgroupBallotKHR); + return spv::BuiltInSubgroupGeMaskKHR; + case glslang::EbvSubGroupGtMask: + builder.addExtension(spv::E_SPV_KHR_shader_ballot); + builder.addCapability(spv::CapabilitySubgroupBallotKHR); + return spv::BuiltInSubgroupGtMaskKHR; + case glslang::EbvSubGroupLeMask: + builder.addExtension(spv::E_SPV_KHR_shader_ballot); + builder.addCapability(spv::CapabilitySubgroupBallotKHR); + return spv::BuiltInSubgroupLeMaskKHR; + case glslang::EbvSubGroupLtMask: - // TODO: Add SPIR-V builtin ID. - logger->missingFunctionality("shader ballot"); + builder.addExtension(spv::E_SPV_KHR_shader_ballot); + builder.addCapability(spv::CapabilitySubgroupBallotKHR); + return spv::BuiltInSubgroupLtMaskKHR; + + case glslang::EbvNumSubgroups: + builder.addCapability(spv::CapabilityGroupNonUniform); + return spv::BuiltInNumSubgroups; + + case glslang::EbvSubgroupID: + builder.addCapability(spv::CapabilityGroupNonUniform); + return spv::BuiltInSubgroupId; + + case glslang::EbvSubgroupSize2: + builder.addCapability(spv::CapabilityGroupNonUniform); + return spv::BuiltInSubgroupSize; + + case glslang::EbvSubgroupInvocation2: + builder.addCapability(spv::CapabilityGroupNonUniform); + return spv::BuiltInSubgroupLocalInvocationId; + + case glslang::EbvSubgroupEqMask2: + builder.addCapability(spv::CapabilityGroupNonUniform); + builder.addCapability(spv::CapabilityGroupNonUniformBallot); + return spv::BuiltInSubgroupEqMask; + + case glslang::EbvSubgroupGeMask2: + builder.addCapability(spv::CapabilityGroupNonUniform); + builder.addCapability(spv::CapabilityGroupNonUniformBallot); + return spv::BuiltInSubgroupGeMask; + + case glslang::EbvSubgroupGtMask2: + builder.addCapability(spv::CapabilityGroupNonUniform); + builder.addCapability(spv::CapabilityGroupNonUniformBallot); + return spv::BuiltInSubgroupGtMask; + + case glslang::EbvSubgroupLeMask2: + builder.addCapability(spv::CapabilityGroupNonUniform); + builder.addCapability(spv::CapabilityGroupNonUniformBallot); + return spv::BuiltInSubgroupLeMask; + + case glslang::EbvSubgroupLtMask2: + builder.addCapability(spv::CapabilityGroupNonUniform); + builder.addCapability(spv::CapabilityGroupNonUniformBallot); + return spv::BuiltInSubgroupLtMask; +#ifdef AMD_EXTENSIONS + case glslang::EbvBaryCoordNoPersp: + builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter); + return spv::BuiltInBaryCoordNoPerspAMD; + + case glslang::EbvBaryCoordNoPerspCentroid: + builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter); + return spv::BuiltInBaryCoordNoPerspCentroidAMD; + + case glslang::EbvBaryCoordNoPerspSample: + builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter); + return spv::BuiltInBaryCoordNoPerspSampleAMD; + + case glslang::EbvBaryCoordSmooth: + builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter); + return spv::BuiltInBaryCoordSmoothAMD; + + case glslang::EbvBaryCoordSmoothCentroid: + builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter); + return spv::BuiltInBaryCoordSmoothCentroidAMD; + + case glslang::EbvBaryCoordSmoothSample: + builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter); + return spv::BuiltInBaryCoordSmoothSampleAMD; + + case glslang::EbvBaryCoordPullModel: + builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter); + return spv::BuiltInBaryCoordPullModelAMD; +#endif + + case glslang::EbvDeviceIndex: + addPre13Extension(spv::E_SPV_KHR_device_group); + builder.addCapability(spv::CapabilityDeviceGroup); + return spv::BuiltInDeviceIndex; + + case glslang::EbvViewIndex: + addPre13Extension(spv::E_SPV_KHR_multiview); + builder.addCapability(spv::CapabilityMultiView); + return spv::BuiltInViewIndex; + +#ifdef NV_EXTENSIONS + case glslang::EbvViewportMaskNV: + if (!memberDeclaration) { + builder.addExtension(spv::E_SPV_NV_viewport_array2); + builder.addCapability(spv::CapabilityShaderViewportMaskNV); + } + return spv::BuiltInViewportMaskNV; + case glslang::EbvSecondaryPositionNV: + if (!memberDeclaration) { + builder.addExtension(spv::E_SPV_NV_stereo_view_rendering); + builder.addCapability(spv::CapabilityShaderStereoViewNV); + } + return spv::BuiltInSecondaryPositionNV; + case glslang::EbvSecondaryViewportMaskNV: + if (!memberDeclaration) { + builder.addExtension(spv::E_SPV_NV_stereo_view_rendering); + builder.addCapability(spv::CapabilityShaderStereoViewNV); + } + return spv::BuiltInSecondaryViewportMaskNV; + case glslang::EbvPositionPerViewNV: + if (!memberDeclaration) { + builder.addExtension(spv::E_SPV_NVX_multiview_per_view_attributes); + builder.addCapability(spv::CapabilityPerViewAttributesNV); + } + return spv::BuiltInPositionPerViewNV; + case glslang::EbvViewportMaskPerViewNV: + if (!memberDeclaration) { + builder.addExtension(spv::E_SPV_NVX_multiview_per_view_attributes); + builder.addCapability(spv::CapabilityPerViewAttributesNV); + } + return spv::BuiltInViewportMaskPerViewNV; + case glslang::EbvFragFullyCoveredNV: + builder.addExtension(spv::E_SPV_EXT_fragment_fully_covered); + builder.addCapability(spv::CapabilityFragmentFullyCoveredEXT); + return spv::BuiltInFullyCoveredEXT; +#endif + default: return spv::BuiltInMax; - default: return spv::BuiltInMax; } } @@ -600,6 +823,122 @@ spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TTy } } +spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(const glslang::TIntermSelection& selectionNode) const +{ + if (selectionNode.getFlatten()) + return spv::SelectionControlFlattenMask; + if (selectionNode.getDontFlatten()) + return spv::SelectionControlDontFlattenMask; + return spv::SelectionControlMaskNone; +} + +spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSwitchControl(const glslang::TIntermSwitch& switchNode) const +{ + if (switchNode.getFlatten()) + return spv::SelectionControlFlattenMask; + if (switchNode.getDontFlatten()) + return spv::SelectionControlDontFlattenMask; + return spv::SelectionControlMaskNone; +} + +// return a non-0 dependency if the dependency argument must be set +spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang::TIntermLoop& loopNode, + unsigned int& dependencyLength) const +{ + spv::LoopControlMask control = spv::LoopControlMaskNone; + + if (loopNode.getDontUnroll()) + control = control | spv::LoopControlDontUnrollMask; + if (loopNode.getUnroll()) + control = control | spv::LoopControlUnrollMask; + if (unsigned(loopNode.getLoopDependency()) == glslang::TIntermLoop::dependencyInfinite) + control = control | spv::LoopControlDependencyInfiniteMask; + else if (loopNode.getLoopDependency() > 0) { + control = control | spv::LoopControlDependencyLengthMask; + dependencyLength = loopNode.getLoopDependency(); + } + + return control; +} + +// Translate glslang type to SPIR-V storage class. +spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::TType& type) +{ + if (type.getQualifier().isPipeInput()) + return spv::StorageClassInput; + if (type.getQualifier().isPipeOutput()) + return spv::StorageClassOutput; + + if (glslangIntermediate->getSource() != glslang::EShSourceHlsl || + type.getQualifier().storage == glslang::EvqUniform) { + if (type.getBasicType() == glslang::EbtAtomicUint) + return spv::StorageClassAtomicCounter; + if (type.containsOpaque()) + return spv::StorageClassUniformConstant; + } + + if (glslangIntermediate->usingStorageBuffer() && type.getQualifier().storage == glslang::EvqBuffer) { + addPre13Extension(spv::E_SPV_KHR_storage_buffer_storage_class); + return spv::StorageClassStorageBuffer; + } + + if (type.getQualifier().isUniformOrBuffer()) { + if (type.getQualifier().layoutPushConstant) + return spv::StorageClassPushConstant; + if (type.getBasicType() == glslang::EbtBlock) + return spv::StorageClassUniform; + return spv::StorageClassUniformConstant; + } + + switch (type.getQualifier().storage) { + case glslang::EvqShared: return spv::StorageClassWorkgroup; + case glslang::EvqGlobal: return spv::StorageClassPrivate; + case glslang::EvqConstReadOnly: return spv::StorageClassFunction; + case glslang::EvqTemporary: return spv::StorageClassFunction; + default: + assert(0); + break; + } + + return spv::StorageClassFunction; +} + +// Add capabilities pertaining to how an array is indexed. +void TGlslangToSpvTraverser::addIndirectionIndexCapabilities(const glslang::TType& baseType, + const glslang::TType& indexType) +{ + if (indexType.getQualifier().isNonUniform()) { + // deal with an asserted non-uniform index + if (baseType.getBasicType() == glslang::EbtSampler) { + if (baseType.getQualifier().hasAttachment()) + builder.addCapability(spv::CapabilityInputAttachmentArrayNonUniformIndexingEXT); + else if (baseType.isImage() && baseType.getSampler().dim == glslang::EsdBuffer) + builder.addCapability(spv::CapabilityStorageTexelBufferArrayNonUniformIndexingEXT); + else if (baseType.isTexture() && baseType.getSampler().dim == glslang::EsdBuffer) + builder.addCapability(spv::CapabilityUniformTexelBufferArrayNonUniformIndexingEXT); + else if (baseType.isImage()) + builder.addCapability(spv::CapabilityStorageImageArrayNonUniformIndexingEXT); + else if (baseType.isTexture()) + builder.addCapability(spv::CapabilitySampledImageArrayNonUniformIndexingEXT); + } else if (baseType.getBasicType() == glslang::EbtBlock) { + if (baseType.getQualifier().storage == glslang::EvqBuffer) + builder.addCapability(spv::CapabilityStorageBufferArrayNonUniformIndexingEXT); + else if (baseType.getQualifier().storage == glslang::EvqUniform) + builder.addCapability(spv::CapabilityUniformBufferArrayNonUniformIndexingEXT); + } + } else { + // assume a dynamically uniform index + if (baseType.getBasicType() == glslang::EbtSampler) { + if (baseType.getQualifier().hasAttachment()) + builder.addCapability(spv::CapabilityInputAttachmentArrayDynamicIndexingEXT); + else if (baseType.isImage() && baseType.getSampler().dim == glslang::EsdBuffer) + builder.addCapability(spv::CapabilityStorageTexelBufferArrayDynamicIndexingEXT); + else if (baseType.isTexture() && baseType.getSampler().dim == glslang::EsdBuffer) + builder.addCapability(spv::CapabilityUniformTexelBufferArrayDynamicIndexingEXT); + } + } +} + // Return whether or not the given type is something that should be tied to a // descriptor set. bool IsDescriptorResource(const glslang::TType& type) @@ -628,6 +967,10 @@ void InheritQualifiers(glslang::TQualifier& child, const glslang::TQualifier& pa child.invariant = true; if (parent.nopersp) child.nopersp = true; +#ifdef AMD_EXTENSIONS + if (parent.explicitInterp) + child.explicitInterp = true; +#endif if (parent.flat) child.flat = true; if (parent.centroid) @@ -648,33 +991,65 @@ void InheritQualifiers(glslang::TQualifier& child, const glslang::TQualifier& pa child.writeonly = true; } -bool HasNonLayoutQualifiers(const glslang::TQualifier& qualifier) +bool HasNonLayoutQualifiers(const glslang::TType& type, const glslang::TQualifier& qualifier) { // This should list qualifiers that simultaneous satisfy: - // - struct members can inherit from a struct declaration - // - affect decorations on the struct members (note smooth does not, and expecting something like volatile to effect the whole object) + // - struct members might inherit from a struct declaration + // (note that non-block structs don't explicitly inherit, + // only implicitly, meaning no decoration involved) + // - affect decorations on the struct members + // (note smooth does not, and expecting something like volatile + // to effect the whole object) // - are not part of the offset/st430/etc or row/column-major layout - return qualifier.invariant || qualifier.hasLocation(); + return qualifier.invariant || (qualifier.hasLocation() && type.getBasicType() == glslang::EbtBlock); } // // Implement the TGlslangToSpvTraverser class. // -TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* glslangIntermediate, spv::SpvBuildLogger* buildLogger) - : TIntermTraverser(true, false, true), shaderEntry(0), sequenceDepth(0), logger(buildLogger), - builder((glslang::GetKhronosToolId() << 16) | GeneratorVersion, logger), - inMain(false), mainTerminated(false), linkageOnly(false), +TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const glslang::TIntermediate* glslangIntermediate, + spv::SpvBuildLogger* buildLogger, glslang::SpvOptions& options) + : TIntermTraverser(true, false, true), + options(options), + shaderEntry(nullptr), currentFunction(nullptr), + sequenceDepth(0), logger(buildLogger), + builder(spvVersion, (glslang::GetKhronosToolId() << 16) | glslang::GetSpirvGeneratorVersion(), logger), + inEntryPoint(false), entryPointTerminated(false), linkageOnly(false), glslangIntermediate(glslangIntermediate) { spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage()); builder.clearAccessChain(); - builder.setSource(TranslateSourceLanguage(glslangIntermediate->getSource(), glslangIntermediate->getProfile()), glslangIntermediate->getVersion()); + builder.setSource(TranslateSourceLanguage(glslangIntermediate->getSource(), glslangIntermediate->getProfile()), + glslangIntermediate->getVersion()); + + if (options.generateDebugInfo) { + builder.setEmitOpLines(); + builder.setSourceFile(glslangIntermediate->getSourceFile()); + + // Set the source shader's text. If for SPV version 1.0, include + // a preamble in comments stating the OpModuleProcessed instructions. + // Otherwise, emit those as actual instructions. + std::string text; + const std::vector& processes = glslangIntermediate->getProcesses(); + for (int p = 0; p < (int)processes.size(); ++p) { + if (glslangIntermediate->getSpv().spv < 0x00010100) { + text.append("// OpModuleProcessed "); + text.append(processes[p]); + text.append("\n"); + } else + builder.addModuleProcessed(processes[p]); + } + if (glslangIntermediate->getSpv().spv < 0x00010100 && (int)processes.size() > 0) + text.append("#line 1\n"); + text.append(glslangIntermediate->getSourceText()); + builder.setSourceText(text); + } stdBuiltins = builder.import("GLSL.std.450"); builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450); - shaderEntry = builder.makeEntrypoint(glslangIntermediate->getEntryPoint().c_str()); - entryPoint = builder.addEntryPoint(executionModel, shaderEntry, glslangIntermediate->getEntryPoint().c_str()); + shaderEntry = builder.makeEntryPoint(glslangIntermediate->getEntryPointName().c_str()); + entryPoint = builder.addEntryPoint(executionModel, shaderEntry, glslangIntermediate->getEntryPointName().c_str()); // Add the source extensions const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions(); @@ -694,14 +1069,20 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* gls builder.addCapability(spv::CapabilityShader); break; + case EShLangTessEvaluation: case EShLangTessControl: builder.addCapability(spv::CapabilityTessellation); - builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices()); - break; - case EShLangTessEvaluation: - builder.addCapability(spv::CapabilityTessellation); - switch (glslangIntermediate->getInputPrimitive()) { + glslang::TLayoutGeometry primitive; + + if (glslangIntermediate->getStage() == EShLangTessControl) { + builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices()); + primitive = glslangIntermediate->getOutputPrimitive(); + } else { + primitive = glslangIntermediate->getInputPrimitive(); + } + + switch (primitive) { case glslang::ElgTriangles: mode = spv::ExecutionModeTriangles; break; case glslang::ElgQuads: mode = spv::ExecutionModeQuads; break; case glslang::ElgIsolines: mode = spv::ExecutionModeIsolines; break; @@ -770,6 +1151,12 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* gls if (glslangIntermediate->getEarlyFragmentTests()) builder.addExecutionMode(shaderEntry, spv::ExecutionModeEarlyFragmentTests); + if (glslangIntermediate->getPostDepthCoverage()) { + builder.addCapability(spv::CapabilitySampleMaskPostDepthCoverage); + builder.addExecutionMode(shaderEntry, spv::ExecutionModePostDepthCoverage); + builder.addExtension(spv::E_SPV_KHR_post_depth_coverage); + } + switch(glslangIntermediate->getDepth()) { case glslang::EldGreater: mode = spv::ExecutionModeDepthGreater; break; case glslang::EldLess: mode = spv::ExecutionModeDepthLess; break; @@ -792,27 +1179,27 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* gls default: break; } - } -// Finish everything and dump -void TGlslangToSpvTraverser::dumpSpv(std::vector& out) +// Finish creating SPV, after the traversal is complete. +void TGlslangToSpvTraverser::finishSpv() { + if (! entryPointTerminated) { + builder.setBuildPoint(shaderEntry->getLastBlock()); + builder.leaveFunction(); + } + // finish off the entry-point SPV instruction by adding the Input/Output for (auto it = iOSet.cbegin(); it != iOSet.cend(); ++it) entryPoint->addIdOperand(*it); builder.eliminateDeadDecorations(); - builder.dump(out); } -TGlslangToSpvTraverser::~TGlslangToSpvTraverser() +// Write the SPV into 'out'. +void TGlslangToSpvTraverser::dumpSpv(std::vector& out) { - if (! mainTerminated) { - spv::Block* lastMainBlock = shaderEntry->getLastBlock(); - builder.setBuildPoint(lastMainBlock); - builder.leaveFunction(); - } + builder.dump(out); } // @@ -843,8 +1230,10 @@ void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol) // Include all "static use" and "linkage only" interface variables on the OpEntryPoint instruction if (builder.isPointer(id)) { spv::StorageClass sc = builder.getStorageClass(id); - if (sc == spv::StorageClassInput || sc == spv::StorageClassOutput) - iOSet.insert(id); + if (sc == spv::StorageClassInput || sc == spv::StorageClassOutput) { + if (!symbol->getType().isStruct() || symbol->getType().getStruct()->size() > 0) + iOSet.insert(id); + } } // Only process non-linkage-only nodes for generating actual static uses @@ -858,21 +1247,54 @@ void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol) // For now, we consider all user variables as being in memory, so they are pointers, // except for - // A) "const in" arguments to a function, which are an intermediate object. + // A) R-Value arguments to a function, which are an intermediate object. // See comments in handleUserFunctionCall(). - // B) Specialization constants (normal constant don't even come in as a variable), + // B) Specialization constants (normal constants don't even come in as a variable), // These are also pure R-values. glslang::TQualifier qualifier = symbol->getQualifier(); - if ((qualifier.storage == glslang::EvqConstReadOnly && constReadOnlyParameters.find(symbol->getId()) != constReadOnlyParameters.end()) || - qualifier.isSpecConstant()) + if (qualifier.isSpecConstant() || rValueParameters.find(symbol->getId()) != rValueParameters.end()) builder.setAccessChainRValue(id); else builder.setAccessChainLValue(id); } + + // Process linkage-only nodes for any special additional interface work. + if (linkageOnly) { + if (glslangIntermediate->getHlslFunctionality1()) { + // Map implicit counter buffers to their originating buffers, which should have been + // seen by now, given earlier pruning of unused counters, and preservation of order + // of declaration. + if (symbol->getType().getQualifier().isUniformOrBuffer()) { + if (!glslangIntermediate->hasCounterBufferName(symbol->getName())) { + // Save possible originating buffers for counter buffers, keyed by + // making the potential counter-buffer name. + std::string keyName = symbol->getName().c_str(); + keyName = glslangIntermediate->addCounterBufferName(keyName); + counterOriginator[keyName] = symbol; + } else { + // Handle a counter buffer, by finding the saved originating buffer. + std::string keyName = symbol->getName().c_str(); + auto it = counterOriginator.find(keyName); + if (it != counterOriginator.end()) { + id = getSymbolId(it->second); + if (id != spv::NoResult) { + spv::Id counterId = getSymbolId(symbol); + if (counterId != spv::NoResult) { + builder.addExtension("SPV_GOOGLE_hlsl_functionality1"); + builder.addDecorationId(id, spv::DecorationHlslCounterBufferGOOGLE, counterId); + } + } + } + } + } + } + } } bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node) { + builder.setLine(node->getLoc().line); + SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder); if (node->getType().getQualifier().isSpecConstant()) spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); @@ -915,8 +1337,10 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T spv::Id leftRValue = accessChainLoad(node->getLeft()->getType()); // do the operation - rValue = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()), - TranslateNoContractionDecoration(node->getType().getQualifier()), + OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()), + TranslateNoContractionDecoration(node->getType().getQualifier()), + TranslateNonUniformDecoration(node->getType().getQualifier()) }; + rValue = createBinaryOperation(node->getOp(), decorations, convertGlslangToSpvType(node->getType()), leftRValue, rValue, node->getType().getBasicType()); @@ -926,7 +1350,7 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T // store the result builder.setAccessChain(lValue); - accessChainStore(node->getType(), rValue); + multiTypeStore(node->getType(), rValue); // assignments are expressions having an rValue after they are evaluated... builder.clearAccessChain(); @@ -991,6 +1415,8 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T node->getRight()->traverse(this); spv::Id index = accessChainLoad(node->getRight()->getType()); + addIndirectionIndexCapabilities(node->getLeft()->getType(), node->getRight()->getType()); + // restore the saved access chain builder.setAccessChain(partial); @@ -1003,13 +1429,14 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T case glslang::EOpVectorSwizzle: { node->getLeft()->traverse(this); - glslang::TIntermSequence& swizzleSequence = node->getRight()->getAsAggregate()->getSequence(); std::vector swizzle; - for (int i = 0; i < (int)swizzleSequence.size(); ++i) - swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst()); + convertSwizzle(*node->getRight()->getAsAggregate(), swizzle); builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType())); } return false; + case glslang::EOpMatrixSwizzle: + logger->missingFunctionality("matrix swizzle"); + return true; case glslang::EOpLogicalOr: case glslang::EOpLogicalAnd: { @@ -1042,8 +1469,10 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T spv::Id right = accessChainLoad(node->getRight()->getType()); // get result - spv::Id result = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()), - TranslateNoContractionDecoration(node->getType().getQualifier()), + OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()), + TranslateNoContractionDecoration(node->getType().getQualifier()), + TranslateNonUniformDecoration(node->getType().getQualifier()) }; + spv::Id result = createBinaryOperation(node->getOp(), decorations, convertGlslangToSpvType(node->getType()), left, right, node->getLeft()->getType().getBasicType()); @@ -1059,6 +1488,8 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node) { + builder.setLine(node->getLoc().line); + SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder); if (node->getType().getQualifier().isSpecConstant()) spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); @@ -1079,10 +1510,15 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI if (node->getOp() == glslang::EOpArrayLength) { // Quite special; won't want to evaluate the operand. + // Currently, the front-end does not allow .length() on an array until it is sized, + // except for the last block membeor of an SSBO. + // TODO: If this changes, link-time sized arrays might show up here, and need their + // size extracted. + // Normal .length() would have been constant folded by the front-end. // So, this has to be block.lastMember.length(). // SPV wants "block" and member number as the operands, go get them. - assert(node->getOperand()->getType().isRuntimeSizedArray()); + glslang::TIntermTyped* block = node->getOperand()->getAsBinaryNode()->getLeft(); block->traverse(this); unsigned int member = node->getOperand()->getAsBinaryNode()->getRight()->getAsConstantUnion()->getConstArray()[0].getUConst(); @@ -1096,8 +1532,18 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI // Start by evaluating the operand + // Does it need a swizzle inversion? If so, evaluation is inverted; + // operate first on the swizzle base, then apply the swizzle. + spv::Id invertedType = spv::NoType; + auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ? invertedType : convertGlslangToSpvType(node->getType()); }; + if (node->getOp() == glslang::EOpInterpolateAtCentroid) + invertedType = getInvertedSwizzleType(*node->getOperand()); + builder.clearAccessChain(); - node->getOperand()->traverse(this); + if (invertedType != spv::NoType) + node->getOperand()->getAsBinaryNode()->getLeft()->traverse(this); + else + node->getOperand()->traverse(this); spv::Id operand = spv::NoResult; @@ -1109,18 +1555,24 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI else operand = accessChainLoad(node->getOperand()->getType()); - spv::Decoration precision = TranslatePrecisionDecoration(node->getType()); - spv::Decoration noContraction = TranslateNoContractionDecoration(node->getType().getQualifier()); + OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()), + TranslateNoContractionDecoration(node->getType().getQualifier()), + TranslateNonUniformDecoration(node->getType().getQualifier()) }; // it could be a conversion if (! result) - result = createConversion(node->getOp(), precision, noContraction, convertGlslangToSpvType(node->getType()), operand, node->getOperand()->getBasicType()); + result = createConversion(node->getOp(), decorations, resultType(), operand, node->getOperand()->getBasicType()); // if not, then possibly an operation if (! result) - result = createUnaryOperation(node->getOp(), precision, noContraction, convertGlslangToSpvType(node->getType()), operand, node->getOperand()->getBasicType()); + result = createUnaryOperation(node->getOp(), decorations, resultType(), operand, node->getOperand()->getBasicType()); if (result) { + if (invertedType) { + result = createInvertedSwizzle(decorations.precision, *node->getOperand(), result); + builder.addDecoration(result, decorations.nonUniform); + } + builder.clearAccessChain(); builder.setAccessChainRValue(result); @@ -1138,6 +1590,14 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI spv::Id one = 0; if (node->getBasicType() == glslang::EbtFloat) one = builder.makeFloatConstant(1.0F); + else if (node->getBasicType() == glslang::EbtDouble) + one = builder.makeDoubleConstant(1.0); + else if (node->getBasicType() == glslang::EbtFloat16) + one = builder.makeFloat16Constant(1.0F); + else if (node->getBasicType() == glslang::EbtInt8 || node->getBasicType() == glslang::EbtUint8) + one = builder.makeInt8Constant(1); + else if (node->getBasicType() == glslang::EbtInt16 || node->getBasicType() == glslang::EbtUint16) + one = builder.makeInt16Constant(1); else if (node->getBasicType() == glslang::EbtInt64 || node->getBasicType() == glslang::EbtUint64) one = builder.makeInt64Constant(1); else @@ -1149,8 +1609,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI else op = glslang::EOpSub; - spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()), - TranslateNoContractionDecoration(node->getType().getQualifier()), + spv::Id result = createBinaryOperation(op, decorations, convertGlslangToSpvType(node->getType()), operand, one, node->getType().getBasicType()); assert(result != spv::NoResult); @@ -1188,6 +1647,8 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); spv::Id result = spv::NoResult; + spv::Id invertedType = spv::NoType; // to use to override the natural type of the node + auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ? invertedType : convertGlslangToSpvType(node->getType()); }; // try texturing result = createImageTextureFunctionCall(node); @@ -1196,7 +1657,11 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt builder.setAccessChainRValue(result); return false; +#ifdef AMD_EXTENSIONS + } else if (node->getOp() == glslang::EOpImageStore || node->getOp() == glslang::EOpImageStoreLod) { +#else } else if (node->getOp() == glslang::EOpImageStore) { +#endif // "imageStore" is a special case, which has no result return false; } @@ -1209,7 +1674,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt assert(node->getOp()); - spv::Decoration precision = TranslatePrecisionDecoration(node->getType()); + spv::Decoration precision = TranslatePrecisionDecoration(node->getOperationPrecision()); switch (node->getOp()) { case glslang::EOpSequence: @@ -1225,11 +1690,11 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt // In all cases, still let the traverser visit the children for us. makeFunctions(node->getAsAggregate()->getSequence()); - // Also, we want all globals initializers to go into the entry of main(), before + // Also, we want all globals initializers to go into the beginning of the entry point, before // anything else gets there, so visit out of order, doing them all now. makeGlobalInitializers(node->getAsAggregate()->getSequence()); - // Initializers are done, don't want to visit again, but functions link objects need to be processed, + // Initializers are done, don't want to visit again, but functions and link objects need to be processed, // so do them manually. visitFunctions(node->getAsAggregate()->getSequence()); @@ -1259,17 +1724,18 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt } case glslang::EOpFunction: if (visit == glslang::EvPreVisit) { - if (isShaderEntrypoint(node)) { - inMain = true; + if (isShaderEntryPoint(node)) { + inEntryPoint = true; builder.setBuildPoint(shaderEntry->getLastBlock()); + currentFunction = shaderEntry; } else { handleFunctionEntry(node); } } else { - if (inMain) - mainTerminated = true; + if (inEntryPoint) + entryPointTerminated = true; builder.leaveFunction(); - inMain = false; + inEntryPoint = false; } return true; @@ -1280,9 +1746,10 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt return false; case glslang::EOpFunctionCall: { + builder.setLine(node->getLoc().line); if (node->isUserDefined()) result = handleUserFunctionCall(node); - //assert(result); // this can happen for bad shaders because the call graph completeness checking is not yet done + // assert(result); // this can happen for bad shaders because the call graph completeness checking is not yet done if (result) { builder.clearAccessChain(); builder.setAccessChainRValue(result); @@ -1309,6 +1776,42 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt case glslang::EOpConstructDMat4x2: case glslang::EOpConstructDMat4x3: case glslang::EOpConstructDMat4x4: + case glslang::EOpConstructIMat2x2: + case glslang::EOpConstructIMat2x3: + case glslang::EOpConstructIMat2x4: + case glslang::EOpConstructIMat3x2: + case glslang::EOpConstructIMat3x3: + case glslang::EOpConstructIMat3x4: + case glslang::EOpConstructIMat4x2: + case glslang::EOpConstructIMat4x3: + case glslang::EOpConstructIMat4x4: + case glslang::EOpConstructUMat2x2: + case glslang::EOpConstructUMat2x3: + case glslang::EOpConstructUMat2x4: + case glslang::EOpConstructUMat3x2: + case glslang::EOpConstructUMat3x3: + case glslang::EOpConstructUMat3x4: + case glslang::EOpConstructUMat4x2: + case glslang::EOpConstructUMat4x3: + case glslang::EOpConstructUMat4x4: + case glslang::EOpConstructBMat2x2: + case glslang::EOpConstructBMat2x3: + case glslang::EOpConstructBMat2x4: + case glslang::EOpConstructBMat3x2: + case glslang::EOpConstructBMat3x3: + case glslang::EOpConstructBMat3x4: + case glslang::EOpConstructBMat4x2: + case glslang::EOpConstructBMat4x3: + case glslang::EOpConstructBMat4x4: + case glslang::EOpConstructF16Mat2x2: + case glslang::EOpConstructF16Mat2x3: + case glslang::EOpConstructF16Mat2x4: + case glslang::EOpConstructF16Mat3x2: + case glslang::EOpConstructF16Mat3x3: + case glslang::EOpConstructF16Mat3x4: + case glslang::EOpConstructF16Mat4x2: + case glslang::EOpConstructF16Mat4x3: + case glslang::EOpConstructF16Mat4x4: isMatrix = true; // fall through case glslang::EOpConstructFloat: @@ -1319,10 +1822,30 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt case glslang::EOpConstructDVec2: case glslang::EOpConstructDVec3: case glslang::EOpConstructDVec4: + case glslang::EOpConstructFloat16: + case glslang::EOpConstructF16Vec2: + case glslang::EOpConstructF16Vec3: + case glslang::EOpConstructF16Vec4: case glslang::EOpConstructBool: case glslang::EOpConstructBVec2: case glslang::EOpConstructBVec3: case glslang::EOpConstructBVec4: + case glslang::EOpConstructInt8: + case glslang::EOpConstructI8Vec2: + case glslang::EOpConstructI8Vec3: + case glslang::EOpConstructI8Vec4: + case glslang::EOpConstructUint8: + case glslang::EOpConstructU8Vec2: + case glslang::EOpConstructU8Vec3: + case glslang::EOpConstructU8Vec4: + case glslang::EOpConstructInt16: + case glslang::EOpConstructI16Vec2: + case glslang::EOpConstructI16Vec3: + case glslang::EOpConstructI16Vec4: + case glslang::EOpConstructUint16: + case glslang::EOpConstructU16Vec2: + case glslang::EOpConstructU16Vec3: + case glslang::EOpConstructU16Vec4: case glslang::EOpConstructInt: case glslang::EOpConstructIVec2: case glslang::EOpConstructIVec3: @@ -1342,21 +1865,21 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt case glslang::EOpConstructStruct: case glslang::EOpConstructTextureSampler: { + builder.setLine(node->getLoc().line); std::vector arguments; translateArguments(*node, arguments); - spv::Id resultTypeId = convertGlslangToSpvType(node->getType()); spv::Id constructed; if (node->getOp() == glslang::EOpConstructTextureSampler) - constructed = builder.createOp(spv::OpSampledImage, resultTypeId, arguments); + constructed = builder.createOp(spv::OpSampledImage, resultType(), arguments); else if (node->getOp() == glslang::EOpConstructStruct || node->getType().isArray()) { std::vector constituents; for (int c = 0; c < (int)arguments.size(); ++c) constituents.push_back(arguments[c]); - constructed = builder.createCompositeConstruct(resultTypeId, constituents); + constructed = builder.createCompositeConstruct(resultType(), constituents); } else if (isMatrix) - constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId); + constructed = builder.createMatrixConstructor(precision, arguments, resultType()); else - constructed = builder.createConstructor(precision, arguments, resultTypeId); + constructed = builder.createConstructor(precision, arguments, resultType()); builder.clearAccessChain(); builder.setAccessChainRValue(constructed); @@ -1385,7 +1908,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt break; } case glslang::EOpMul: - // compontent-wise matrix multiply + // component-wise matrix multiply binOp = glslang::EOpMul; break; case glslang::EOpOuterProduct: @@ -1414,10 +1937,16 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt case glslang::EOpMemoryBarrierImage: case glslang::EOpMemoryBarrierShared: case glslang::EOpGroupMemoryBarrier: + case glslang::EOpDeviceMemoryBarrier: case glslang::EOpAllMemoryBarrierWithGroupSync: - case glslang::EOpGroupMemoryBarrierWithGroupSync: + case glslang::EOpDeviceMemoryBarrierWithGroupSync: case glslang::EOpWorkgroupMemoryBarrier: case glslang::EOpWorkgroupMemoryBarrierWithGroupSync: + case glslang::EOpSubgroupBarrier: + case glslang::EOpSubgroupMemoryBarrier: + case glslang::EOpSubgroupMemoryBarrierBuffer: + case glslang::EOpSubgroupMemoryBarrierImage: + case glslang::EOpSubgroupMemoryBarrierShared: noReturnValue = true; // These all have 0 operands and will naturally finish up in the code below for 0 operands break; @@ -1433,6 +1962,20 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt atomic = true; break; + case glslang::EOpAtomicCounterAdd: + case glslang::EOpAtomicCounterSubtract: + case glslang::EOpAtomicCounterMin: + case glslang::EOpAtomicCounterMax: + case glslang::EOpAtomicCounterAnd: + case glslang::EOpAtomicCounterOr: + case glslang::EOpAtomicCounterXor: + case glslang::EOpAtomicCounterExchange: + case glslang::EOpAtomicCounterCompSwap: + builder.addExtension("SPV_KHR_shader_atomic_counter_ops"); + builder.addCapability(spv::CapabilityAtomicStorageOps); + atomic = true; + break; + default: break; } @@ -1453,8 +1996,12 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt right->traverse(this); spv::Id rightId = accessChainLoad(right->getType()); - result = createBinaryOperation(binOp, precision, TranslateNoContractionDecoration(node->getType().getQualifier()), - convertGlslangToSpvType(node->getType()), leftId, rightId, + builder.setLine(node->getLoc().line); + OpDecorations decorations = { precision, + TranslateNoContractionDecoration(node->getType().getQualifier()), + TranslateNonUniformDecoration(node->getType().getQualifier()) }; + result = createBinaryOperation(binOp, decorations, + resultType(), leftId, rightId, left->getType().getBasicType(), reduceComparison); // code above should only make binOp that exists in createBinaryOperation @@ -1471,9 +2018,6 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt glslang::TIntermSequence& glslangOperands = node->getSequence(); std::vector operands; for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) { - builder.clearAccessChain(); - glslangOperands[arg]->traverse(this); - // special case l-value operands; there are just a few bool lvalue = false; switch (node->getOp()) { @@ -1484,8 +2028,18 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt break; case glslang::EOpInterpolateAtSample: case glslang::EOpInterpolateAtOffset: - if (arg == 0) +#ifdef AMD_EXTENSIONS + case glslang::EOpInterpolateAtVertex: +#endif + if (arg == 0) { lvalue = true; + + // Does it need a swizzle inversion? If so, evaluation is inverted; + // operate first on the swizzle base, then apply the swizzle. + if (glslangOperands[0]->getAsOperator() && + glslangOperands[0]->getAsOperator()->getOp() == glslang::EOpVectorSwizzle) + invertedType = convertGlslangToSpvType(glslangOperands[0]->getAsBinaryNode()->getLeft()->getType()); + } break; case glslang::EOpAtomicAdd: case glslang::EOpAtomicMin: @@ -1495,6 +2049,15 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt case glslang::EOpAtomicXor: case glslang::EOpAtomicExchange: case glslang::EOpAtomicCompSwap: + case glslang::EOpAtomicCounterAdd: + case glslang::EOpAtomicCounterSubtract: + case glslang::EOpAtomicCounterMin: + case glslang::EOpAtomicCounterMax: + case glslang::EOpAtomicCounterAnd: + case glslang::EOpAtomicCounterOr: + case glslang::EOpAtomicCounterXor: + case glslang::EOpAtomicCounterExchange: + case glslang::EOpAtomicCounterCompSwap: if (arg == 0) lvalue = true; break; @@ -1511,32 +2074,46 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt default: break; } + builder.clearAccessChain(); + if (invertedType != spv::NoType && arg == 0) + glslangOperands[0]->getAsBinaryNode()->getLeft()->traverse(this); + else + glslangOperands[arg]->traverse(this); if (lvalue) operands.push_back(builder.accessChainGetLValue()); - else + else { + builder.setLine(node->getLoc().line); operands.push_back(accessChainLoad(glslangOperands[arg]->getAsTyped()->getType())); + } } + builder.setLine(node->getLoc().line); if (atomic) { // Handle all atomics - result = createAtomicOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType()); + result = createAtomicOperation(node->getOp(), precision, resultType(), operands, node->getBasicType()); } else { // Pass through to generic operations. switch (glslangOperands.size()) { case 0: - result = createNoArgOperation(node->getOp()); + result = createNoArgOperation(node->getOp(), precision, resultType()); break; case 1: - result = createUnaryOperation( - node->getOp(), precision, - TranslateNoContractionDecoration(node->getType().getQualifier()), - convertGlslangToSpvType(node->getType()), operands.front(), - glslangOperands[0]->getAsTyped()->getBasicType()); + { + OpDecorations decorations = { precision, + TranslateNoContractionDecoration(node->getType().getQualifier()), + TranslateNonUniformDecoration(node->getType().getQualifier()) }; + result = createUnaryOperation( + node->getOp(), decorations, + resultType(), operands.front(), + glslangOperands[0]->getAsTyped()->getBasicType()); + } break; default: - result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType()); + result = createMiscOperation(node->getOp(), precision, resultType(), operands, node->getBasicType()); break; } + if (invertedType) + result = createInvertedSwizzle(precision, *glslangOperands[0]->getAsBinaryNode(), result); } if (noReturnValue) @@ -1552,49 +2129,159 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt } } +// This path handles both if-then-else and ?: +// The if-then-else has a node type of void, while +// ?: has either a void or a non-void node type +// +// Leaving the result, when not void: +// GLSL only has r-values as the result of a :?, but +// if we have an l-value, that can be more efficient if it will +// become the base of a complex r-value expression, because the +// next layer copies r-values into memory to use the access-chain mechanism bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang::TIntermSelection* node) { - // This path handles both if-then-else and ?: - // The if-then-else has a node type of void, while - // ?: has a non-void node type - spv::Id result = 0; - if (node->getBasicType() != glslang::EbtVoid) { - // don't handle this as just on-the-fly temporaries, because there will be two names - // and better to leave SSA to later passes - result = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(node->getType())); - } + // See if it simple and safe, or required, to execute both sides. + // Crucially, side effects must be either semantically required or avoided, + // and there are performance trade-offs. + // Return true if required or a good idea (and safe) to execute both sides, + // false otherwise. + const auto bothSidesPolicy = [&]() -> bool { + // do we have both sides? + if (node->getTrueBlock() == nullptr || + node->getFalseBlock() == nullptr) + return false; + // required? (unless we write additional code to look for side effects + // and make performance trade-offs if none are present) + if (!node->getShortCircuit()) + return true; + + // if not required to execute both, decide based on performance/practicality... + + // see if OpSelect can handle it + if ((!node->getType().isScalar() && !node->getType().isVector()) || + node->getBasicType() == glslang::EbtVoid) + return false; + + assert(node->getType() == node->getTrueBlock() ->getAsTyped()->getType() && + node->getType() == node->getFalseBlock()->getAsTyped()->getType()); + + // return true if a single operand to ? : is okay for OpSelect + const auto operandOkay = [](glslang::TIntermTyped* node) { + return node->getAsSymbolNode() || node->getType().getQualifier().isConstant(); + }; + + return operandOkay(node->getTrueBlock() ->getAsTyped()) && + operandOkay(node->getFalseBlock()->getAsTyped()); + }; + + spv::Id result = spv::NoResult; // upcoming result selecting between trueValue and falseValue // emit the condition before doing anything with selection node->getCondition()->traverse(this); + spv::Id condition = accessChainLoad(node->getCondition()->getType()); - // make an "if" based on the value created by the condition - spv::Builder::If ifBuilder(accessChainLoad(node->getCondition()->getType()), builder); - - if (node->getTrueBlock()) { - // emit the "then" statement + // Find a way of executing both sides and selecting the right result. + const auto executeBothSides = [&]() -> void { + // execute both sides node->getTrueBlock()->traverse(this); - if (result) - builder.createStore(accessChainLoad(node->getTrueBlock()->getAsTyped()->getType()), result); - } - - if (node->getFalseBlock()) { - ifBuilder.makeBeginElse(); - // emit the "else" statement + spv::Id trueValue = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType()); node->getFalseBlock()->traverse(this); - if (result) - builder.createStore(accessChainLoad(node->getFalseBlock()->getAsTyped()->getType()), result); - } + spv::Id falseValue = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType()); - ifBuilder.makeEndIf(); + builder.setLine(node->getLoc().line); - if (result) { - // GLSL only has r-values as the result of a :?, but - // if we have an l-value, that can be more efficient if it will - // become the base of a complex r-value expression, because the - // next layer copies r-values into memory to use the access-chain mechanism - builder.clearAccessChain(); - builder.setAccessChainLValue(result); - } + // done if void + if (node->getBasicType() == glslang::EbtVoid) + return; + + // emit code to select between trueValue and falseValue + + // see if OpSelect can handle it + if (node->getType().isScalar() || node->getType().isVector()) { + // Emit OpSelect for this selection. + + // smear condition to vector, if necessary (AST is always scalar) + if (builder.isVector(trueValue)) + condition = builder.smearScalar(spv::NoPrecision, condition, + builder.makeVectorType(builder.makeBoolType(), + builder.getNumComponents(trueValue))); + + // OpSelect + result = builder.createTriOp(spv::OpSelect, + convertGlslangToSpvType(node->getType()), condition, + trueValue, falseValue); + + builder.clearAccessChain(); + builder.setAccessChainRValue(result); + } else { + // We need control flow to select the result. + // TODO: Once SPIR-V OpSelect allows arbitrary types, eliminate this path. + result = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(node->getType())); + + // Selection control: + const spv::SelectionControlMask control = TranslateSelectionControl(*node); + + // make an "if" based on the value created by the condition + spv::Builder::If ifBuilder(condition, control, builder); + + // emit the "then" statement + builder.createStore(trueValue, result); + ifBuilder.makeBeginElse(); + // emit the "else" statement + builder.createStore(falseValue, result); + + // finish off the control flow + ifBuilder.makeEndIf(); + + builder.clearAccessChain(); + builder.setAccessChainLValue(result); + } + }; + + // Execute the one side needed, as per the condition + const auto executeOneSide = [&]() { + // Always emit control flow. + if (node->getBasicType() != glslang::EbtVoid) + result = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(node->getType())); + + // Selection control: + const spv::SelectionControlMask control = TranslateSelectionControl(*node); + + // make an "if" based on the value created by the condition + spv::Builder::If ifBuilder(condition, control, builder); + + // emit the "then" statement + if (node->getTrueBlock() != nullptr) { + node->getTrueBlock()->traverse(this); + if (result != spv::NoResult) + builder.createStore(accessChainLoad(node->getTrueBlock()->getAsTyped()->getType()), result); + } + + if (node->getFalseBlock() != nullptr) { + ifBuilder.makeBeginElse(); + // emit the "else" statement + node->getFalseBlock()->traverse(this); + if (result != spv::NoResult) + builder.createStore(accessChainLoad(node->getFalseBlock()->getAsTyped()->getType()), result); + } + + // finish off the control flow + ifBuilder.makeEndIf(); + + if (result != spv::NoResult) { + builder.clearAccessChain(); + builder.setAccessChainLValue(result); + } + }; + + // Try for OpSelect (or a requirement to execute both sides) + if (bothSidesPolicy()) { + SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder); + if (node->getType().getQualifier().isSpecConstant()) + spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); + executeBothSides(); + } else + executeOneSide(); return false; } @@ -1605,6 +2292,9 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T node->getCondition()->traverse(this); spv::Id selector = accessChainLoad(node->getCondition()->getAsTyped()->getType()); + // Selection control: + const spv::SelectionControlMask control = TranslateSwitchControl(*node); + // browse the children to sort out code segments int defaultSegment = -1; std::vector codeSegments; @@ -1630,7 +2320,7 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T // make the switch statement std::vector segmentBlocks; // returned, as the blocks allocated in the call - builder.makeSwitch(selector, (int)codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, segmentBlocks); + builder.makeSwitch(selector, control, (int)codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, segmentBlocks); // emit all the code in the segments breakForLoop.push(false); @@ -1661,22 +2351,27 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn { auto blocks = builder.makeNewLoop(); builder.createBranch(&blocks.head); + + // Loop control: + unsigned int dependencyLength = glslang::TIntermLoop::dependencyInfinite; + const spv::LoopControlMask control = TranslateLoopControl(*node, dependencyLength); + // Spec requires back edges to target header blocks, and every header block // must dominate its merge block. Make a header block first to ensure these // conditions are met. By definition, it will contain OpLoopMerge, followed // by a block-ending branch. But we don't want to put any other body/test // instructions in it, since the body/test may have arbitrary instructions, // including merges of its own. + builder.setLine(node->getLoc().line); builder.setBuildPoint(&blocks.head); - builder.createLoopMerge(&blocks.merge, &blocks.continue_target, spv::LoopControlMaskNone); + builder.createLoopMerge(&blocks.merge, &blocks.continue_target, control, dependencyLength); if (node->testFirst() && node->getTest()) { spv::Block& test = builder.makeNewBlock(); builder.createBranch(&test); builder.setBuildPoint(&test); node->getTest()->traverse(this); - spv::Id condition = - accessChainLoad(node->getTest()->getType()); + spv::Id condition = accessChainLoad(node->getTest()->getType()); builder.createConditionalBranch(condition, &blocks.body, &blocks.merge); builder.setBuildPoint(&blocks.body); @@ -1691,6 +2386,7 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn node->getTerminal()->traverse(this); builder.createBranch(&blocks.head); } else { + builder.setLine(node->getLoc().line); builder.createBranch(&blocks.body); breakForLoop.push(true); @@ -1725,6 +2421,8 @@ bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::T if (node->getExpression()) node->getExpression()->traverse(this); + builder.setLine(node->getLoc().line); + switch (node->getFlowOp()) { case glslang::EOpKill: builder.makeDiscard(); @@ -1739,9 +2437,18 @@ bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::T builder.createLoopContinue(); break; case glslang::EOpReturn: - if (node->getExpression()) - builder.makeReturn(false, accessChainLoad(node->getExpression()->getType())); - else + if (node->getExpression()) { + const glslang::TType& glslangReturnType = node->getExpression()->getType(); + spv::Id returnId = accessChainLoad(glslangReturnType); + if (builder.getTypeId(returnId) != currentFunction->getReturnType()) { + builder.clearAccessChain(); + spv::Id copyId = builder.createVariable(spv::StorageClassFunction, currentFunction->getReturnType()); + builder.setAccessChainLValue(copyId); + multiTypeStore(glslangReturnType, returnId); + returnId = builder.createLoad(copyId); + } + builder.makeReturn(false, returnId); + } else builder.makeReturn(false); builder.clearAccessChain(); @@ -1768,6 +2475,36 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* spv::StorageClass storageClass = TranslateStorageClass(node->getType()); spv::Id spvType = convertGlslangToSpvType(node->getType()); + const bool contains16BitType = node->getType().containsBasicType(glslang::EbtFloat16) || + node->getType().containsBasicType(glslang::EbtInt16) || + node->getType().containsBasicType(glslang::EbtUint16); + if (contains16BitType) { + switch (storageClass) { + case spv::StorageClassInput: + case spv::StorageClassOutput: + addPre13Extension(spv::E_SPV_KHR_16bit_storage); + builder.addCapability(spv::CapabilityStorageInputOutput16); + break; + case spv::StorageClassPushConstant: + addPre13Extension(spv::E_SPV_KHR_16bit_storage); + builder.addCapability(spv::CapabilityStoragePushConstant16); + break; + case spv::StorageClassUniform: + addPre13Extension(spv::E_SPV_KHR_16bit_storage); + if (node->getType().getQualifier().storage == glslang::EvqBuffer) + builder.addCapability(spv::CapabilityStorageUniformBufferBlock16); + else + builder.addCapability(spv::CapabilityStorageUniform16); + break; + case spv::StorageClassStorageBuffer: + addPre13Extension(spv::E_SPV_KHR_16bit_storage); + builder.addCapability(spv::CapabilityStorageUniformBufferBlock16); + break; + default: + break; + } + } + const char* name = node->getName().c_str(); if (glslang::IsAnonymous(name)) name = ""; @@ -1780,6 +2517,12 @@ spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler) { switch (sampler.type) { case glslang::EbtFloat: return builder.makeFloatType(32); +#ifdef AMD_EXTENSIONS + case glslang::EbtFloat16: + builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float_fetch); + builder.addCapability(spv::CapabilityFloat16ImageAMD); + return builder.makeFloatType(16); +#endif case glslang::EbtInt: return builder.makeIntType(32); case glslang::EbtUint: return builder.makeUintType(32); default: @@ -1788,18 +2531,48 @@ spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler) } } +// If node is a swizzle operation, return the type that should be used if +// the swizzle base is first consumed by another operation, before the swizzle +// is applied. +spv::Id TGlslangToSpvTraverser::getInvertedSwizzleType(const glslang::TIntermTyped& node) +{ + if (node.getAsOperator() && + node.getAsOperator()->getOp() == glslang::EOpVectorSwizzle) + return convertGlslangToSpvType(node.getAsBinaryNode()->getLeft()->getType()); + else + return spv::NoType; +} + +// When inverting a swizzle with a parent op, this function +// will apply the swizzle operation to a completed parent operation. +spv::Id TGlslangToSpvTraverser::createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped& node, spv::Id parentResult) +{ + std::vector swizzle; + convertSwizzle(*node.getAsBinaryNode()->getRight()->getAsAggregate(), swizzle); + return builder.createRvalueSwizzle(precision, convertGlslangToSpvType(node.getType()), parentResult, swizzle); +} + +// Convert a glslang AST swizzle node to a swizzle vector for building SPIR-V. +void TGlslangToSpvTraverser::convertSwizzle(const glslang::TIntermAggregate& node, std::vector& swizzle) +{ + const glslang::TIntermSequence& swizzleSequence = node.getSequence(); + for (int i = 0; i < (int)swizzleSequence.size(); ++i) + swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst()); +} + // Convert from a glslang type to an SPV type, by calling into a // recursive version of this function. This establishes the inherited // layout state rooted from the top-level type. spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type) { - return convertGlslangToSpvType(type, getExplicitLayout(type), type.getQualifier()); + return convertGlslangToSpvType(type, getExplicitLayout(type), type.getQualifier(), false); } // Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id. // explicitLayout can be kept the same throughout the hierarchical recursive walk. // Mutually recursive with convertGlslangStructToSpvType(). -spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking explicitLayout, const glslang::TQualifier& qualifier) +spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, + glslang::TLayoutPacking explicitLayout, const glslang::TQualifier& qualifier, bool lastBufferBlockMember) { spv::Id spvType = spv::NoResult; @@ -1814,6 +2587,14 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty case glslang::EbtDouble: spvType = builder.makeFloatType(64); break; + case glslang::EbtFloat16: + builder.addCapability(spv::CapabilityFloat16); +#if AMD_EXTENSIONS + if (builder.getSpvVersion() < glslang::EShTargetSpv_1_3) + builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float); +#endif + spvType = builder.makeFloatType(16); + break; case glslang::EbtBool: // "transparent" bool doesn't exist in SPIR-V. The GLSL convention is // a 32-bit int where non-0 means true. @@ -1822,6 +2603,30 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty else spvType = builder.makeBoolType(); break; + case glslang::EbtInt8: + builder.addCapability(spv::CapabilityInt8); + spvType = builder.makeIntType(8); + break; + case glslang::EbtUint8: + builder.addCapability(spv::CapabilityInt8); + spvType = builder.makeUintType(8); + break; + case glslang::EbtInt16: + builder.addCapability(spv::CapabilityInt16); +#ifdef AMD_EXTENSIONS + if (builder.getSpvVersion() < glslang::EShTargetSpv_1_3) + builder.addExtension(spv::E_SPV_AMD_gpu_shader_int16); +#endif + spvType = builder.makeIntType(16); + break; + case glslang::EbtUint16: + builder.addCapability(spv::CapabilityInt16); +#ifdef AMD_EXTENSIONS + if (builder.getSpvVersion() < glslang::EShTargetSpv_1_3) + builder.addExtension(spv::E_SPV_AMD_gpu_shader_int16); +#endif + spvType = builder.makeUintType(16); + break; case glslang::EbtInt: spvType = builder.makeIntType(32); break; @@ -1829,11 +2634,9 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty spvType = builder.makeUintType(32); break; case glslang::EbtInt64: - builder.addCapability(spv::CapabilityInt64); spvType = builder.makeIntType(64); break; case glslang::EbtUint64: - builder.addCapability(spv::CapabilityInt64); spvType = builder.makeUintType(64); break; case glslang::EbtAtomicUint: @@ -1865,7 +2668,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty // Try to share structs for different layouts, but not yet for other // kinds of qualification (primarily not yet including interpolant qualification). - if (! HasNonLayoutQualifiers(qualifier)) + if (! HasNonLayoutQualifiers(type, qualifier)) spvType = structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers]; if (spvType != spv::NoResult) break; @@ -1899,8 +2702,8 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty // Use a dummy glslang type for querying internal strides of // arrays of arrays, but using just a one-dimensional array. glslang::TType simpleArrayType(type, 0); // deference type of the array - while (simpleArrayType.getArraySizes().getNumDims() > 1) - simpleArrayType.getArraySizes().dereference(); + while (simpleArrayType.getArraySizes()->getNumDims() > 1) + simpleArrayType.getArraySizes()->dereference(); // Will compute the higher-order strides here, rather than making a whole // pile of types and doing repetitive recursion on their contents. @@ -1922,12 +2725,16 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty stride = getArrayStride(type, explicitLayout, qualifier.layoutMatrix); } - // Do the outer dimension, which might not be known for a runtime-sized array - if (type.isRuntimeSizedArray()) { - spvType = builder.makeRuntimeArray(spvType); - } else { - assert(type.getOuterArraySize() > 0); + // Do the outer dimension, which might not be known for a runtime-sized array. + // (Unsized arrays that survive through linking will be runtime-sized arrays) + if (type.isSizedArray()) spvType = builder.makeArrayType(spvType, makeArraySizeId(*type.getArraySizes(), 0), stride); + else { + if (!lastBufferBlockMember) { + builder.addExtension("SPV_EXT_descriptor_indexing"); + builder.addCapability(spv::CapabilityRuntimeDescriptorArrayEXT); + } + spvType = builder.makeRuntimeArray(spvType); } if (stride > 0) builder.addDecoration(spvType, spv::DecorationArrayStride, stride); @@ -1936,6 +2743,32 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty return spvType; } +// TODO: this functionality should exist at a higher level, in creating the AST +// +// Identify interface members that don't have their required extension turned on. +// +bool TGlslangToSpvTraverser::filterMember(const glslang::TType& member) +{ + auto& extensions = glslangIntermediate->getRequestedExtensions(); + + if (member.getFieldName() == "gl_ViewportMask" && + extensions.find("GL_NV_viewport_array2") == extensions.end()) + return true; + if (member.getFieldName() == "gl_SecondaryViewportMaskNV" && + extensions.find("GL_NV_stereo_view_rendering") == extensions.end()) + return true; + if (member.getFieldName() == "gl_SecondaryPositionNV" && + extensions.find("GL_NV_stereo_view_rendering") == extensions.end()) + return true; + if (member.getFieldName() == "gl_PositionPerViewNV" && + extensions.find("GL_NVX_multiview_per_view_attributes") == extensions.end()) + return true; + if (member.getFieldName() == "gl_ViewportMaskPerViewNV" && + extensions.find("GL_NVX_multiview_per_view_attributes") == extensions.end()) + return true; + + return false; +}; // Do full recursive conversion of a glslang structure (or block) type to a SPIR-V Id. // explicitLayout can be kept the same throughout the hierarchical recursive walk. @@ -1948,7 +2781,6 @@ spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TTy // Create a vector of struct types for SPIR-V to consume std::vector spvMembers; int memberDelta = 0; // how much the member's index changes from glslang to SPIR-V, normally 0, except sometimes for blocks - int locationOffset = 0; // for use across struct members, when they are called recursively for (int i = 0; i < (int)glslangMembers->size(); i++) { glslang::TType& glslangMember = *(*glslangMembers)[i].type; if (glslangMember.hiddenMember()) { @@ -1956,26 +2788,30 @@ spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TTy if (type.getBasicType() == glslang::EbtBlock) memberRemapper[glslangMembers][i] = -1; } else { - if (type.getBasicType() == glslang::EbtBlock) + if (type.getBasicType() == glslang::EbtBlock) { memberRemapper[glslangMembers][i] = i - memberDelta; + if (filterMember(glslangMember)) + continue; + } // modify just this child's view of the qualifier glslang::TQualifier memberQualifier = glslangMember.getQualifier(); InheritQualifiers(memberQualifier, qualifier); - // manually inherit location; it's more complex + // manually inherit location if (! memberQualifier.hasLocation() && qualifier.hasLocation()) - memberQualifier.layoutLocation = qualifier.layoutLocation + locationOffset; - if (qualifier.hasLocation()) - locationOffset += glslangIntermediate->computeTypeLocationSize(glslangMember); + memberQualifier.layoutLocation = qualifier.layoutLocation; // recurse - spvMembers.push_back(convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier)); + bool lastBufferBlockMember = qualifier.storage == glslang::EvqBuffer && + i == (int)glslangMembers->size() - 1; + spvMembers.push_back( + convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember)); } } // Make the SPIR-V type spv::Id spvType = builder.makeStructType(spvMembers, type.getTypeName().c_str()); - if (! HasNonLayoutQualifiers(qualifier)) + if (! HasNonLayoutQualifiers(type, qualifier)) structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers] = spvType; // Decorate it @@ -1996,99 +2832,121 @@ void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type, for (int i = 0; i < (int)glslangMembers->size(); i++) { glslang::TType& glslangMember = *(*glslangMembers)[i].type; int member = i; - if (type.getBasicType() == glslang::EbtBlock) + if (type.getBasicType() == glslang::EbtBlock) { member = memberRemapper[glslangMembers][i]; + if (filterMember(glslangMember)) + continue; + } // modify just this child's view of the qualifier glslang::TQualifier memberQualifier = glslangMember.getQualifier(); InheritQualifiers(memberQualifier, qualifier); // using -1 above to indicate a hidden member - if (member >= 0) { - builder.addMemberName(spvType, member, glslangMember.getFieldName().c_str()); - addMemberDecoration(spvType, member, TranslateLayoutDecoration(glslangMember, memberQualifier.layoutMatrix)); - addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangMember)); - // Add interpolation and auxiliary storage decorations only to top-level members of Input and Output storage classes - if (type.getQualifier().storage == glslang::EvqVaryingIn || type.getQualifier().storage == glslang::EvqVaryingOut) { - if (type.getBasicType() == glslang::EbtBlock) { - addMemberDecoration(spvType, member, TranslateInterpolationDecoration(memberQualifier)); - addMemberDecoration(spvType, member, TranslateAuxiliaryStorageDecoration(memberQualifier)); - } + if (member < 0) + continue; + + builder.addMemberName(spvType, member, glslangMember.getFieldName().c_str()); + builder.addMemberDecoration(spvType, member, + TranslateLayoutDecoration(glslangMember, memberQualifier.layoutMatrix)); + builder.addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangMember)); + // Add interpolation and auxiliary storage decorations only to + // top-level members of Input and Output storage classes + if (type.getQualifier().storage == glslang::EvqVaryingIn || + type.getQualifier().storage == glslang::EvqVaryingOut) { + if (type.getBasicType() == glslang::EbtBlock || + glslangIntermediate->getSource() == glslang::EShSourceHlsl) { + builder.addMemberDecoration(spvType, member, TranslateInterpolationDecoration(memberQualifier)); + builder.addMemberDecoration(spvType, member, TranslateAuxiliaryStorageDecoration(memberQualifier)); } - addMemberDecoration(spvType, member, TranslateInvariantDecoration(memberQualifier)); - - if (qualifier.storage == glslang::EvqBuffer) { - std::vector memory; - TranslateMemoryDecoration(memberQualifier, memory); - for (unsigned int i = 0; i < memory.size(); ++i) - addMemberDecoration(spvType, member, memory[i]); - } - - // Compute location decoration; tricky based on whether inheritance is at play and - // what kind of container we have, etc. - // TODO: This algorithm (and it's cousin above doing almost the same thing) should - // probably move to the linker stage of the front end proper, and just have the - // answer sitting already distributed throughout the individual member locations. - int location = -1; // will only decorate if present or inherited - // Ignore member locations if the container is an array, as that's - // ill-specified and decisions have been made to not allow this anyway. - // The object itself must have a location, and that comes out from decorating the object, - // not the type (this code decorates types). - if (! type.isArray()) { - if (memberQualifier.hasLocation()) { // no inheritance, or override of inheritance - // struct members should not have explicit locations - assert(type.getBasicType() != glslang::EbtStruct); - location = memberQualifier.layoutLocation; - } else if (type.getBasicType() != glslang::EbtBlock) { - // If it is a not a Block, (...) Its members are assigned consecutive locations (...) - // The members, and their nested types, must not themselves have Location decorations. - } else if (qualifier.hasLocation()) // inheritance - location = qualifier.layoutLocation + locationOffset; - } - if (location >= 0) - builder.addMemberDecoration(spvType, member, spv::DecorationLocation, location); - - if (qualifier.hasLocation()) // track for upcoming inheritance - locationOffset += glslangIntermediate->computeTypeLocationSize(glslangMember); - - // component, XFB, others - if (glslangMember.getQualifier().hasComponent()) - builder.addMemberDecoration(spvType, member, spv::DecorationComponent, glslangMember.getQualifier().layoutComponent); - if (glslangMember.getQualifier().hasXfbOffset()) - builder.addMemberDecoration(spvType, member, spv::DecorationOffset, glslangMember.getQualifier().layoutXfbOffset); - else if (explicitLayout != glslang::ElpNone) { - // figure out what to do with offset, which is accumulating - int nextOffset; - updateMemberOffset(type, glslangMember, offset, nextOffset, explicitLayout, memberQualifier.layoutMatrix); - if (offset >= 0) - builder.addMemberDecoration(spvType, member, spv::DecorationOffset, offset); - offset = nextOffset; - } - - if (glslangMember.isMatrix() && explicitLayout != glslang::ElpNone) - builder.addMemberDecoration(spvType, member, spv::DecorationMatrixStride, getMatrixStride(glslangMember, explicitLayout, memberQualifier.layoutMatrix)); - - // built-in variable decorations - spv::BuiltIn builtIn = TranslateBuiltInDecoration(glslangMember.getQualifier().builtIn, true); - if (builtIn != spv::BuiltInMax) - addMemberDecoration(spvType, member, spv::DecorationBuiltIn, (int)builtIn); } + builder.addMemberDecoration(spvType, member, TranslateInvariantDecoration(memberQualifier)); + + if (type.getBasicType() == glslang::EbtBlock && + qualifier.storage == glslang::EvqBuffer) { + // Add memory decorations only to top-level members of shader storage block + std::vector memory; + TranslateMemoryDecoration(memberQualifier, memory); + for (unsigned int i = 0; i < memory.size(); ++i) + builder.addMemberDecoration(spvType, member, memory[i]); + } + + // Location assignment was already completed correctly by the front end, + // just track whether a member needs to be decorated. + // Ignore member locations if the container is an array, as that's + // ill-specified and decisions have been made to not allow this. + if (! type.isArray() && memberQualifier.hasLocation()) + builder.addMemberDecoration(spvType, member, spv::DecorationLocation, memberQualifier.layoutLocation); + + if (qualifier.hasLocation()) // track for upcoming inheritance + locationOffset += glslangIntermediate->computeTypeLocationSize( + glslangMember, glslangIntermediate->getStage()); + + // component, XFB, others + if (glslangMember.getQualifier().hasComponent()) + builder.addMemberDecoration(spvType, member, spv::DecorationComponent, + glslangMember.getQualifier().layoutComponent); + if (glslangMember.getQualifier().hasXfbOffset()) + builder.addMemberDecoration(spvType, member, spv::DecorationOffset, + glslangMember.getQualifier().layoutXfbOffset); + else if (explicitLayout != glslang::ElpNone) { + // figure out what to do with offset, which is accumulating + int nextOffset; + updateMemberOffset(type, glslangMember, offset, nextOffset, explicitLayout, memberQualifier.layoutMatrix); + if (offset >= 0) + builder.addMemberDecoration(spvType, member, spv::DecorationOffset, offset); + offset = nextOffset; + } + + if (glslangMember.isMatrix() && explicitLayout != glslang::ElpNone) + builder.addMemberDecoration(spvType, member, spv::DecorationMatrixStride, + getMatrixStride(glslangMember, explicitLayout, memberQualifier.layoutMatrix)); + + // built-in variable decorations + spv::BuiltIn builtIn = TranslateBuiltInDecoration(glslangMember.getQualifier().builtIn, true); + if (builtIn != spv::BuiltInMax) + builder.addMemberDecoration(spvType, member, spv::DecorationBuiltIn, (int)builtIn); + + // nonuniform + builder.addMemberDecoration(spvType, member, TranslateNonUniformDecoration(glslangMember.getQualifier())); + + if (glslangIntermediate->getHlslFunctionality1() && memberQualifier.semanticName != nullptr) { + builder.addExtension("SPV_GOOGLE_hlsl_functionality1"); + builder.addMemberDecoration(spvType, member, (spv::Decoration)spv::DecorationHlslSemanticGOOGLE, + memberQualifier.semanticName); + } + +#ifdef NV_EXTENSIONS + if (builtIn == spv::BuiltInLayer) { + // SPV_NV_viewport_array2 extension + if (glslangMember.getQualifier().layoutViewportRelative){ + builder.addMemberDecoration(spvType, member, (spv::Decoration)spv::DecorationViewportRelativeNV); + builder.addCapability(spv::CapabilityShaderViewportMaskNV); + builder.addExtension(spv::E_SPV_NV_viewport_array2); + } + if (glslangMember.getQualifier().layoutSecondaryViewportRelativeOffset != -2048){ + builder.addMemberDecoration(spvType, member, + (spv::Decoration)spv::DecorationSecondaryViewportRelativeNV, + glslangMember.getQualifier().layoutSecondaryViewportRelativeOffset); + builder.addCapability(spv::CapabilityShaderStereoViewNV); + builder.addExtension(spv::E_SPV_NV_stereo_view_rendering); + } + } + if (glslangMember.getQualifier().layoutPassthrough) { + builder.addMemberDecoration(spvType, member, (spv::Decoration)spv::DecorationPassthroughNV); + builder.addCapability(spv::CapabilityGeometryShaderPassthroughNV); + builder.addExtension(spv::E_SPV_NV_geometry_shader_passthrough); + } +#endif } // Decorate the structure - addDecoration(spvType, TranslateLayoutDecoration(type, qualifier.layoutMatrix)); - addDecoration(spvType, TranslateBlockDecoration(type)); + builder.addDecoration(spvType, TranslateLayoutDecoration(type, qualifier.layoutMatrix)); + builder.addDecoration(spvType, TranslateBlockDecoration(type, glslangIntermediate->usingStorageBuffer())); if (type.getQualifier().hasStream() && glslangIntermediate->isMultiStream()) { builder.addCapability(spv::CapabilityGeometryStreams); builder.addDecoration(spvType, spv::DecorationStream, type.getQualifier().layoutStream); } - if (glslangIntermediate->getXfbMode()) { - builder.addCapability(spv::CapabilityTransformFeedback); - if (type.getQualifier().hasXfbStride()) - builder.addDecoration(spvType, spv::DecorationXfbStride, type.getQualifier().layoutXfbStride); - if (type.getQualifier().hasXfbBuffer()) - builder.addDecoration(spvType, spv::DecorationXfbBuffer, type.getQualifier().layoutXfbBuffer); - } } // Turn the expression forming the array size into an id. @@ -2119,7 +2977,8 @@ spv::Id TGlslangToSpvTraverser::makeArraySizeId(const glslang::TArraySizes& arra spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type) { spv::Id nominalTypeId = builder.accessChainGetInferredType(); - spv::Id loadedId = builder.accessChainLoad(TranslatePrecisionDecoration(type), nominalTypeId); + spv::Id loadedId = builder.accessChainLoad(TranslatePrecisionDecoration(type), + TranslateNonUniformDecoration(type.getQualifier()), nominalTypeId); // Need to convert to abstract types when necessary if (type.getBasicType() == glslang::EbtBool) { @@ -2142,6 +3001,8 @@ spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type) // Wrap the builder's accessChainStore to: // - do conversion of concrete to abstract type +// +// Implicitly uses the existing builder.accessChain as the storage target. void TGlslangToSpvTraverser::accessChainStore(const glslang::TType& type, spv::Id rvalue) { // Need to convert to abstract types when necessary @@ -2152,25 +3013,101 @@ void TGlslangToSpvTraverser::accessChainStore(const glslang::TType& type, spv::I // Conversion for bool spv::Id boolType = builder.makeBoolType(); if (nominalTypeId != boolType) { + // keep these outside arguments, for determinant order-of-evaluation + spv::Id one = builder.makeUintConstant(1); spv::Id zero = builder.makeUintConstant(0); - spv::Id one = builder.makeUintConstant(1); rvalue = builder.createTriOp(spv::OpSelect, nominalTypeId, rvalue, one, zero); - } + } else if (builder.getTypeId(rvalue) != boolType) + rvalue = builder.createBinOp(spv::OpINotEqual, boolType, rvalue, builder.makeUintConstant(0)); } else if (builder.isVectorType(nominalTypeId)) { // Conversion for bvec int vecSize = builder.getNumTypeComponents(nominalTypeId); spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize); if (nominalTypeId != bvecType) { + // keep these outside arguments, for determinant order-of-evaluation + spv::Id one = makeSmearedConstant(builder.makeUintConstant(1), vecSize); spv::Id zero = makeSmearedConstant(builder.makeUintConstant(0), vecSize); - spv::Id one = makeSmearedConstant(builder.makeUintConstant(1), vecSize); rvalue = builder.createTriOp(spv::OpSelect, nominalTypeId, rvalue, one, zero); - } + } else if (builder.getTypeId(rvalue) != bvecType) + rvalue = builder.createBinOp(spv::OpINotEqual, bvecType, rvalue, + makeSmearedConstant(builder.makeUintConstant(0), vecSize)); } } builder.accessChainStore(rvalue); } +// For storing when types match at the glslang level, but not might match at the +// SPIR-V level. +// +// This especially happens when a single glslang type expands to multiple +// SPIR-V types, like a struct that is used in a member-undecorated way as well +// as in a member-decorated way. +// +// NOTE: This function can handle any store request; if it's not special it +// simplifies to a simple OpStore. +// +// Implicitly uses the existing builder.accessChain as the storage target. +void TGlslangToSpvTraverser::multiTypeStore(const glslang::TType& type, spv::Id rValue) +{ + // we only do the complex path here if it's an aggregate + if (! type.isStruct() && ! type.isArray()) { + accessChainStore(type, rValue); + return; + } + + // and, it has to be a case of type aliasing + spv::Id rType = builder.getTypeId(rValue); + spv::Id lValue = builder.accessChainGetLValue(); + spv::Id lType = builder.getContainedTypeId(builder.getTypeId(lValue)); + if (lType == rType) { + accessChainStore(type, rValue); + return; + } + + // Recursively (as needed) copy an aggregate type to a different aggregate type, + // where the two types were the same type in GLSL. This requires member + // by member copy, recursively. + + // If an array, copy element by element. + if (type.isArray()) { + glslang::TType glslangElementType(type, 0); + spv::Id elementRType = builder.getContainedTypeId(rType); + for (int index = 0; index < type.getOuterArraySize(); ++index) { + // get the source member + spv::Id elementRValue = builder.createCompositeExtract(rValue, elementRType, index); + + // set up the target storage + builder.clearAccessChain(); + builder.setAccessChainLValue(lValue); + builder.accessChainPush(builder.makeIntConstant(index)); + + // store the member + multiTypeStore(glslangElementType, elementRValue); + } + } else { + assert(type.isStruct()); + + // loop over structure members + const glslang::TTypeList& members = *type.getStruct(); + for (int m = 0; m < (int)members.size(); ++m) { + const glslang::TType& glslangMemberType = *members[m].type; + + // get the source member + spv::Id memberRType = builder.getContainedTypeId(rType, m); + spv::Id memberRValue = builder.createCompositeExtract(rValue, memberRType, m); + + // set up the target storage + builder.clearAccessChain(); + builder.setAccessChainLValue(lValue); + builder.accessChainPush(builder.makeIntConstant(m)); + + // store the member + multiTypeStore(glslangMemberType, memberRValue); + } + } +} + // Decide whether or not this type should be // decorated with offsets and strides, and if so // whether std140 or std430 rules should be applied. @@ -2226,7 +3163,7 @@ int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, gl // 'currentOffset' should be passed in already initialized, ready to modify, and reflecting // the migration of data from nextOffset -> currentOffset. It should be -1 on the first call. // -1 means a non-forced member offset (no decoration needed). -void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& /*structType*/, const glslang::TType& memberType, int& currentOffset, int& nextOffset, +void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout) { // this will get a positive value when deemed necessary @@ -2258,7 +3195,27 @@ void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& /*structTy int memberSize; int dummyStride; int memberAlignment = glslangIntermediate->getBaseAlignment(memberType, memberSize, dummyStride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor); + + // Adjust alignment for HLSL rules + // TODO: make this consistent in early phases of code: + // adjusting this late means inconsistencies with earlier code, which for reflection is an issue + // Until reflection is brought in sync with these adjustments, don't apply to $Global, + // which is the most likely to rely on reflection, and least likely to rely implicit layouts + if (glslangIntermediate->usingHlslOFfsets() && + ! memberType.isArray() && memberType.isVector() && structType.getTypeName().compare("$Global") != 0) { + int dummySize; + int componentAlignment = glslangIntermediate->getBaseAlignmentScalar(memberType, dummySize); + if (componentAlignment <= 4) + memberAlignment = componentAlignment; + } + + // Bump up to member alignment glslang::RoundToPow2(currentOffset, memberAlignment); + + // Bump up to vec4 if there is a bad straddle + if (glslangIntermediate->improperStraddle(memberType, memberSize, currentOffset)) + glslang::RoundToPow2(currentOffset, 16); + nextOffset = currentOffset + memberSize; } @@ -2270,6 +3227,13 @@ void TGlslangToSpvTraverser::declareUseOfStructMember(const glslang::TTypeList& case glslang::EbvClipDistance: case glslang::EbvCullDistance: case glslang::EbvPointSize: +#ifdef NV_EXTENSIONS + case glslang::EbvViewportMaskNV: + case glslang::EbvSecondaryPositionNV: + case glslang::EbvSecondaryViewportMaskNV: + case glslang::EbvPositionPerViewNV: + case glslang::EbvViewportMaskPerViewNV: +#endif // Generate the associated capability. Delegate to TranslateBuiltInDecoration. // Alternately, we could just call this for any glslang built-in, since the // capability already guards against duplicates. @@ -2281,57 +3245,92 @@ void TGlslangToSpvTraverser::declareUseOfStructMember(const glslang::TTypeList& } } -bool TGlslangToSpvTraverser::isShaderEntrypoint(const glslang::TIntermAggregate* node) +bool TGlslangToSpvTraverser::isShaderEntryPoint(const glslang::TIntermAggregate* node) { - // have to ignore mangling and just look at the base name - size_t firstOpen = node->getName().find('('); - return node->getName().compare(0, firstOpen, glslangIntermediate->getEntryPoint().c_str()) == 0; + return node->getName().compare(glslangIntermediate->getEntryPointMangledName().c_str()) == 0; +} + +// Does parameter need a place to keep writes, separate from the original? +// Assumes called after originalParam(), which filters out block/buffer/opaque-based +// qualifiers such that we should have only in/out/inout/constreadonly here. +bool TGlslangToSpvTraverser::writableParam(glslang::TStorageQualifier qualifier) const +{ + assert(qualifier == glslang::EvqIn || + qualifier == glslang::EvqOut || + qualifier == glslang::EvqInOut || + qualifier == glslang::EvqConstReadOnly); + return qualifier != glslang::EvqConstReadOnly; +} + +// Is parameter pass-by-original? +bool TGlslangToSpvTraverser::originalParam(glslang::TStorageQualifier qualifier, const glslang::TType& paramType, + bool implicitThisParam) +{ + if (implicitThisParam) // implicit this + return true; + if (glslangIntermediate->getSource() == glslang::EShSourceHlsl) + return paramType.getBasicType() == glslang::EbtBlock; + return paramType.containsOpaque() || // sampler, etc. + (paramType.getBasicType() == glslang::EbtBlock && qualifier == glslang::EvqBuffer); // SSBO } // Make all the functions, skeletally, without actually visiting their bodies. void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions) { + const auto getParamDecorations = [](std::vector& decorations, const glslang::TType& type) { + spv::Decoration paramPrecision = TranslatePrecisionDecoration(type); + if (paramPrecision != spv::NoPrecision) + decorations.push_back(paramPrecision); + TranslateMemoryDecoration(type.getQualifier(), decorations); + }; + for (int f = 0; f < (int)glslFunctions.size(); ++f) { glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate(); - if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction || isShaderEntrypoint(glslFunction)) + if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction || isShaderEntryPoint(glslFunction)) continue; // We're on a user function. Set up the basic interface for the function now, - // so that it's available to call. - // Translating the body will happen later. + // so that it's available to call. Translating the body will happen later. // // Typically (except for a "const in" parameter), an address will be passed to the // function. What it is an address of varies: // - // - "in" parameters not marked as "const" can be written to without modifying the argument, - // so that write needs to be to a copy, hence the address of a copy works. + // - "in" parameters not marked as "const" can be written to without modifying the calling + // argument so that write needs to be to a copy, hence the address of a copy works. // // - "const in" parameters can just be the r-value, as no writes need occur. // - // - "out" and "inout" arguments can't be done as direct pointers, because GLSL has - // copy-in/copy-out semantics. They can be handled though with a pointer to a copy. + // - "out" and "inout" arguments can't be done as pointers to the calling argument, because + // GLSL has copy-in/copy-out semantics. They can be handled though with a pointer to a copy. std::vector paramTypes; - std::vector paramPrecisions; + std::vector> paramDecorations; // list of decorations per parameter glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence(); + bool implicitThis = (int)parameters.size() > 0 && parameters[0]->getAsSymbolNode()->getName() == + glslangIntermediate->implicitThisName; + + paramDecorations.resize(parameters.size()); for (int p = 0; p < (int)parameters.size(); ++p) { const glslang::TType& paramType = parameters[p]->getAsTyped()->getType(); spv::Id typeId = convertGlslangToSpvType(paramType); - if (paramType.isOpaque()) + if (originalParam(paramType.getQualifier().storage, paramType, implicitThis && p == 0)) typeId = builder.makePointer(TranslateStorageClass(paramType), typeId); - else if (paramType.getQualifier().storage != glslang::EvqConstReadOnly) + else if (writableParam(paramType.getQualifier().storage)) typeId = builder.makePointer(spv::StorageClassFunction, typeId); else - constReadOnlyParameters.insert(parameters[p]->getAsSymbolNode()->getId()); - paramPrecisions.push_back(TranslatePrecisionDecoration(paramType)); + rValueParameters.insert(parameters[p]->getAsSymbolNode()->getId()); + getParamDecorations(paramDecorations[p], paramType); paramTypes.push_back(typeId); } spv::Block* functionBlock; spv::Function *function = builder.makeFunctionEntry(TranslatePrecisionDecoration(glslFunction->getType()), convertGlslangToSpvType(glslFunction->getType()), - glslFunction->getName().c_str(), paramTypes, paramPrecisions, &functionBlock); + glslFunction->getName().c_str(), paramTypes, + paramDecorations, &functionBlock); + if (implicitThis) + function->setImplicitThis(); // Track function to emit/call later functionMap[glslFunction->getName().c_str()] = function; @@ -2354,7 +3353,7 @@ void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequen if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() != glslang::EOpLinkerObjects) { // We're on a top-level node that's not a function. Treat as an initializer, whose - // code goes into the beginning of main. + // code goes into the beginning of the entry point. initializer->traverse(this); } } @@ -2365,7 +3364,7 @@ void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glsl { for (int f = 0; f < (int)glslFunctions.size(); ++f) { glslang::TIntermAggregate* node = glslFunctions[f]->getAsAggregate(); - if (node && (node->getOp() == glslang::EOpFunction || node->getOp() == glslang ::EOpLinkerObjects)) + if (node && (node->getOp() == glslang::EOpFunction || node->getOp() == glslang::EOpLinkerObjects)) node->traverse(this); } } @@ -2374,8 +3373,8 @@ void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate { // SPIR-V functions should already be in the functionMap from the prepass // that called makeFunctions(). - spv::Function* function = functionMap[node->getName().c_str()]; - spv::Block* functionBlock = function->getEntryBlock(); + currentFunction = functionMap[node->getName().c_str()]; + spv::Block* functionBlock = currentFunction->getEntryBlock(); builder.setBuildPoint(functionBlock); } @@ -2385,9 +3384,15 @@ void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& glslang::TSampler sampler = {}; bool cubeCompare = false; +#ifdef AMD_EXTENSIONS + bool f16ShadowCompare = false; +#endif if (node.isTexture() || node.isImage()) { sampler = glslangArguments[0]->getAsTyped()->getType().getSampler(); cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow; +#ifdef AMD_EXTENSIONS + f16ShadowCompare = sampler.shadow && glslangArguments[1]->getAsTyped()->getType().getBasicType() == glslang::EbtFloat16; +#endif } for (int i = 0; i < (int)glslangArguments.size(); ++i) { @@ -2412,6 +3417,21 @@ void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& if ((sampler.ms && i == 3) || (! sampler.ms && i == 2)) lvalue = true; break; +#ifdef AMD_EXTENSIONS + case glslang::EOpSparseTexture: + if (((cubeCompare || f16ShadowCompare) && i == 3) || (! (cubeCompare || f16ShadowCompare) && i == 2)) + lvalue = true; + break; + case glslang::EOpSparseTextureClamp: + if (((cubeCompare || f16ShadowCompare) && i == 4) || (! (cubeCompare || f16ShadowCompare) && i == 3)) + lvalue = true; + break; + case glslang::EOpSparseTextureLod: + case glslang::EOpSparseTextureOffset: + if ((f16ShadowCompare && i == 4) || (! f16ShadowCompare && i == 3)) + lvalue = true; + break; +#else case glslang::EOpSparseTexture: if ((cubeCompare && i == 3) || (! cubeCompare && i == 2)) lvalue = true; @@ -2425,6 +3445,7 @@ void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& if (i == 3) lvalue = true; break; +#endif case glslang::EOpSparseTextureFetch: if ((sampler.dim != glslang::EsdRect && i == 3) || (sampler.dim == glslang::EsdRect && i == 2)) lvalue = true; @@ -2433,6 +3454,23 @@ void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& if ((sampler.dim != glslang::EsdRect && i == 4) || (sampler.dim == glslang::EsdRect && i == 3)) lvalue = true; break; +#ifdef AMD_EXTENSIONS + case glslang::EOpSparseTextureLodOffset: + case glslang::EOpSparseTextureGrad: + case glslang::EOpSparseTextureOffsetClamp: + if ((f16ShadowCompare && i == 5) || (! f16ShadowCompare && i == 4)) + lvalue = true; + break; + case glslang::EOpSparseTextureGradOffset: + case glslang::EOpSparseTextureGradClamp: + if ((f16ShadowCompare && i == 6) || (! f16ShadowCompare && i == 5)) + lvalue = true; + break; + case glslang::EOpSparseTextureGradOffsetClamp: + if ((f16ShadowCompare && i == 7) || (! f16ShadowCompare && i == 6)) + lvalue = true; + break; +#else case glslang::EOpSparseTextureLodOffset: case glslang::EOpSparseTextureGrad: case glslang::EOpSparseTextureOffsetClamp: @@ -2448,7 +3486,8 @@ void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& if (i == 6) lvalue = true; break; - case glslang::EOpSparseTextureGather: +#endif + case glslang::EOpSparseTextureGather: if ((sampler.shadow && i == 3) || (! sampler.shadow && i == 2)) lvalue = true; break; @@ -2457,6 +3496,21 @@ void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& if ((sampler.shadow && i == 4) || (! sampler.shadow && i == 3)) lvalue = true; break; +#ifdef AMD_EXTENSIONS + case glslang::EOpSparseTextureGatherLod: + if (i == 3) + lvalue = true; + break; + case glslang::EOpSparseTextureGatherLodOffset: + case glslang::EOpSparseTextureGatherLodOffsets: + if (i == 4) + lvalue = true; + break; + case glslang::EOpSparseImageLoadLod: + if (i == 3) + lvalue = true; + break; +#endif default: break; } @@ -2477,19 +3531,26 @@ void TGlslangToSpvTraverser::translateArguments(glslang::TIntermUnary& node, std spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermOperator* node) { - if (! node->isImage() && ! node->isTexture()) { + if (! node->isImage() && ! node->isTexture()) return spv::NoResult; - } + + builder.setLine(node->getLoc().line); // Process a GLSL texturing op (will be SPV image) const glslang::TSampler sampler = node->getAsAggregate() ? node->getAsAggregate()->getSequence()[0]->getAsTyped()->getType().getSampler() : node->getAsUnaryNode()->getOperand()->getAsTyped()->getType().getSampler(); +#ifdef AMD_EXTENSIONS + bool f16ShadowCompare = (sampler.shadow && node->getAsAggregate()) + ? node->getAsAggregate()->getSequence()[1]->getAsTyped()->getType().getBasicType() == glslang::EbtFloat16 + : false; +#endif + std::vector arguments; if (node->getAsAggregate()) translateArguments(*node->getAsAggregate(), arguments); else translateArguments(*node->getAsUnaryNode(), arguments); - spv::Decoration precision = TranslatePrecisionDecoration(node->getType()); + spv::Decoration precision = TranslatePrecisionDecoration(node->getOperationPrecision()); spv::Builder::TextureParameters params = { }; params.sampler = arguments[0]; @@ -2497,27 +3558,30 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO glslang::TCrackedTextureOp cracked; node->crackTexture(sampler, cracked); + const bool isUnsignedResult = node->getType().getBasicType() == glslang::EbtUint; + // Check for queries if (cracked.query) { - // a sampled image needs to have the image extracted first - if (builder.isSampledImage(params.sampler)) + // OpImageQueryLod works on a sampled image, for other queries the image has to be extracted first + if (node->getOp() != glslang::EOpTextureQueryLod && builder.isSampledImage(params.sampler)) params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler); + switch (node->getOp()) { case glslang::EOpImageQuerySize: case glslang::EOpTextureQuerySize: if (arguments.size() > 1) { params.lod = arguments[1]; - return builder.createTextureQueryCall(spv::OpImageQuerySizeLod, params); + return builder.createTextureQueryCall(spv::OpImageQuerySizeLod, params, isUnsignedResult); } else - return builder.createTextureQueryCall(spv::OpImageQuerySize, params); + return builder.createTextureQueryCall(spv::OpImageQuerySize, params, isUnsignedResult); case glslang::EOpImageQuerySamples: case glslang::EOpTextureQuerySamples: - return builder.createTextureQueryCall(spv::OpImageQuerySamples, params); + return builder.createTextureQueryCall(spv::OpImageQuerySamples, params, isUnsignedResult); case glslang::EOpTextureQueryLod: params.coords = arguments[1]; - return builder.createTextureQueryCall(spv::OpImageQueryLod, params); + return builder.createTextureQueryCall(spv::OpImageQueryLod, params, isUnsignedResult); case glslang::EOpTextureQueryLevels: - return builder.createTextureQueryCall(spv::OpImageQueryLevels, params); + return builder.createTextureQueryCall(spv::OpImageQueryLevels, params, isUnsignedResult); case glslang::EOpSparseTexelsResident: return builder.createUnaryOp(spv::OpImageSparseTexelsResident, builder.makeBoolType(), arguments[0]); default: @@ -2526,6 +3590,20 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO } } + int components = node->getType().getVectorSize(); + + if (node->getOp() == glslang::EOpTextureFetch) { + // These must produce 4 components, per SPIR-V spec. We'll add a conversion constructor if needed. + // This will only happen through the HLSL path for operator[], so we do not have to handle e.g. + // the EOpTexture/Proj/Lod/etc family. It would be harmless to do so, but would need more logic + // here around e.g. which ones return scalars or other types. + components = 4; + } + + glslang::TType returnType(node->getType().getBasicType(), glslang::EvqTemporary, components); + + auto resultType = [&returnType,this]{ return convertGlslangToSpvType(returnType); }; + // Check for image functions other than queries if (node->isImage()) { std::vector operands; @@ -2546,30 +3624,69 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO operands.push_back(spv::ImageOperandsSampleMask); operands.push_back(*(opIt++)); } - return builder.createOp(spv::OpImageRead, convertGlslangToSpvType(node->getType()), operands); + spv::Id result = builder.createOp(spv::OpImageRead, resultType(), operands); + builder.setPrecision(result, precision); + return result; } operands.push_back(*(opIt++)); +#ifdef AMD_EXTENSIONS + if (node->getOp() == glslang::EOpImageLoad || node->getOp() == glslang::EOpImageLoadLod) { +#else if (node->getOp() == glslang::EOpImageLoad) { +#endif if (sampler.ms) { operands.push_back(spv::ImageOperandsSampleMask); operands.push_back(*opIt); +#ifdef AMD_EXTENSIONS + } else if (cracked.lod) { + builder.addExtension(spv::E_SPV_AMD_shader_image_load_store_lod); + builder.addCapability(spv::CapabilityImageReadWriteLodAMD); + + operands.push_back(spv::ImageOperandsLodMask); + operands.push_back(*opIt); +#endif } if (builder.getImageTypeFormat(builder.getImageType(operands.front())) == spv::ImageFormatUnknown) builder.addCapability(spv::CapabilityStorageImageReadWithoutFormat); - return builder.createOp(spv::OpImageRead, convertGlslangToSpvType(node->getType()), operands); + + std::vector result( 1, builder.createOp(spv::OpImageRead, resultType(), operands) ); + builder.setPrecision(result[0], precision); + + // If needed, add a conversion constructor to the proper size. + if (components != node->getType().getVectorSize()) + result[0] = builder.createConstructor(precision, result, convertGlslangToSpvType(node->getType())); + + return result[0]; +#ifdef AMD_EXTENSIONS + } else if (node->getOp() == glslang::EOpImageStore || node->getOp() == glslang::EOpImageStoreLod) { +#else } else if (node->getOp() == glslang::EOpImageStore) { +#endif if (sampler.ms) { operands.push_back(*(opIt + 1)); operands.push_back(spv::ImageOperandsSampleMask); operands.push_back(*opIt); +#ifdef AMD_EXTENSIONS + } else if (cracked.lod) { + builder.addExtension(spv::E_SPV_AMD_shader_image_load_store_lod); + builder.addCapability(spv::CapabilityImageReadWriteLodAMD); + + operands.push_back(*(opIt + 1)); + operands.push_back(spv::ImageOperandsLodMask); + operands.push_back(*opIt); +#endif } else operands.push_back(*opIt); builder.createNoResultOp(spv::OpImageWrite, operands); if (builder.getImageTypeFormat(builder.getImageType(operands.front())) == spv::ImageFormatUnknown) builder.addCapability(spv::CapabilityStorageImageWriteWithoutFormat); return spv::NoResult; +#ifdef AMD_EXTENSIONS + } else if (node->getOp() == glslang::EOpSparseImageLoad || node->getOp() == glslang::EOpSparseImageLoadLod) { +#else } else if (node->getOp() == glslang::EOpSparseImageLoad) { +#endif builder.addCapability(spv::CapabilitySparseResidency); if (builder.getImageTypeFormat(builder.getImageType(operands.front())) == spv::ImageFormatUnknown) builder.addCapability(spv::CapabilityStorageImageReadWithoutFormat); @@ -2577,11 +3694,19 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO if (sampler.ms) { operands.push_back(spv::ImageOperandsSampleMask); operands.push_back(*opIt++); +#ifdef AMD_EXTENSIONS + } else if (cracked.lod) { + builder.addExtension(spv::E_SPV_AMD_shader_image_load_store_lod); + builder.addCapability(spv::CapabilityImageReadWriteLodAMD); + + operands.push_back(spv::ImageOperandsLodMask); + operands.push_back(*opIt++); +#endif } // Create the return type that was a special structure spv::Id texelOut = *opIt; - spv::Id typeId0 = convertGlslangToSpvType(node->getType()); + spv::Id typeId0 = resultType(); spv::Id typeId1 = builder.getDerefTypeId(texelOut); spv::Id resultTypeId = builder.makeStructResultType(typeId0, typeId1); @@ -2597,7 +3722,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO // as the first source operand, is required by SPIR-V atomic operations. operands.push_back(sampler.ms ? *(opIt++) : builder.makeUintConstant(0)); // For non-MS, the value should be 0 - spv::Id resultTypeId = builder.makePointer(spv::StorageClassImage, convertGlslangToSpvType(node->getType())); + spv::Id resultTypeId = builder.makePointer(spv::StorageClassImage, resultType()); spv::Id pointer = builder.createOp(spv::OpImageTexelPointer, resultTypeId, operands); std::vector operands; @@ -2605,20 +3730,74 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO for (; opIt != arguments.end(); ++opIt) operands.push_back(*opIt); - return createAtomicOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType()); + return createAtomicOperation(node->getOp(), precision, resultType(), operands, node->getBasicType()); } } +#ifdef AMD_EXTENSIONS + // Check for fragment mask functions other than queries + if (cracked.fragMask) { + assert(sampler.ms); + + auto opIt = arguments.begin(); + std::vector operands; + + // Extract the image if necessary + if (builder.isSampledImage(params.sampler)) + params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler); + + operands.push_back(params.sampler); + ++opIt; + + if (sampler.isSubpass()) { + // add on the (0,0) coordinate + spv::Id zero = builder.makeIntConstant(0); + std::vector comps; + comps.push_back(zero); + comps.push_back(zero); + operands.push_back(builder.makeCompositeConstant(builder.makeVectorType(builder.makeIntType(32), 2), comps)); + } + + for (; opIt != arguments.end(); ++opIt) + operands.push_back(*opIt); + + spv::Op fragMaskOp = spv::OpNop; + if (node->getOp() == glslang::EOpFragmentMaskFetch) + fragMaskOp = spv::OpFragmentMaskFetchAMD; + else if (node->getOp() == glslang::EOpFragmentFetch) + fragMaskOp = spv::OpFragmentFetchAMD; + + builder.addExtension(spv::E_SPV_AMD_shader_fragment_mask); + builder.addCapability(spv::CapabilityFragmentMaskAMD); + return builder.createOp(fragMaskOp, resultType(), operands); + } +#endif + // Check for texture functions other than queries bool sparse = node->isSparseTexture(); bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow; // check for bias argument bool bias = false; +#ifdef AMD_EXTENSIONS + if (! cracked.lod && ! cracked.grad && ! cracked.fetch && ! cubeCompare) { +#else if (! cracked.lod && ! cracked.gather && ! cracked.grad && ! cracked.fetch && ! cubeCompare) { +#endif int nonBiasArgCount = 2; +#ifdef AMD_EXTENSIONS + if (cracked.gather) + ++nonBiasArgCount; // comp argument should be present when bias argument is present + + if (f16ShadowCompare) + ++nonBiasArgCount; +#endif if (cracked.offset) ++nonBiasArgCount; +#ifdef AMD_EXTENSIONS + else if (cracked.offsets) + ++nonBiasArgCount; +#endif if (cracked.grad) nonBiasArgCount += 2; if (cracked.lodClamp) @@ -2630,6 +3809,24 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO bias = true; } + // See if the sampler param should really be just the SPV image part + if (cracked.fetch) { + // a fetch needs to have the image extracted first + if (builder.isSampledImage(params.sampler)) + params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler); + } + +#ifdef AMD_EXTENSIONS + if (cracked.gather) { + const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions(); + if (bias || cracked.lod || + sourceExtensions.find(glslang::E_GL_AMD_texture_gather_bias_lod) != sourceExtensions.end()) { + builder.addExtension(spv::E_SPV_AMD_texture_gather_bias_lod); + builder.addCapability(spv::CapabilityImageGatherBiasLodAMD); + } + } +#endif + // set the rest of the arguments params.coords = arguments[1]; @@ -2637,7 +3834,11 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO bool noImplicitLod = false; // sort out where Dref is coming from +#ifdef AMD_EXTENSIONS + if (cubeCompare || f16ShadowCompare) { +#else if (cubeCompare) { +#endif params.Dref = arguments[2]; ++extraArgs; } else if (sampler.shadow && cracked.gather) { @@ -2656,7 +3857,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO // lod if (cracked.lod) { - params.lod = arguments[2]; + params.lod = arguments[2 + extraArgs]; ++extraArgs; } else if (glslangIntermediate->getStage() != EShLangFragment) { // we need to invent the default lod for an explicit lod instruction for a non-fragment stage @@ -2665,7 +3866,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO // multisample if (sampler.ms) { - params.sample = arguments[2]; // For MS, "sample" should be specified + params.sample = arguments[2 + extraArgs]; // For MS, "sample" should be specified ++extraArgs; } @@ -2697,21 +3898,20 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO ++extraArgs; } - // bias - if (bias) { - params.bias = arguments[2 + extraArgs]; - ++extraArgs; - } - // gather component if (cracked.gather && ! sampler.shadow) { // default component is 0, if missing, otherwise an argument if (2 + extraArgs < (int)arguments.size()) { params.component = arguments[2 + extraArgs]; ++extraArgs; - } else { + } else params.component = builder.makeIntConstant(0); - } + } + + // bias + if (bias) { + params.bias = arguments[2 + extraArgs]; + ++extraArgs; } // projective component (might not to move) @@ -2730,7 +3930,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO } // copy the projective coordinate if we have to if (projTargetComp != projSourceComp) { - spv::Id projComp = builder.createCompositeExtract(params.coords, + spv::Id projComp = builder.createCompositeExtract(params.coords, builder.getScalarTypeId(builder.getTypeId(params.coords)), projSourceComp); params.coords = builder.createCompositeInsert(projComp, params.coords, @@ -2738,7 +3938,14 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO } } - return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), sparse, cracked.fetch, cracked.proj, cracked.gather, noImplicitLod, params); + std::vector result( 1, + builder.createTextureCall(precision, resultType(), sparse, cracked.fetch, cracked.proj, cracked.gather, noImplicitLod, params) + ); + + if (components != node->getType().getVectorSize()) + result[0] = builder.createConstructor(precision, result, convertGlslangToSpvType(node->getType())); + + return result[0]; } spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node) @@ -2759,18 +3966,18 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg // 3. Make the call // 4. Copy back the results - // 1. Evaluate the arguments + // 1. Evaluate the arguments and their types std::vector lValues; std::vector rValues; std::vector argTypes; for (int a = 0; a < (int)glslangArgs.size(); ++a) { - const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType(); + argTypes.push_back(&glslangArgs[a]->getAsTyped()->getType()); // build l-value builder.clearAccessChain(); glslangArgs[a]->traverse(this); - argTypes.push_back(¶mType); - // keep outputs as and opaque objects l-values, evaluate input-only as r-values - if (qualifiers[a] != glslang::EvqConstReadOnly || paramType.isOpaque()) { + // keep outputs and pass-by-originals as l-values, evaluate others as r-values + if (originalParam(qualifiers[a], *argTypes[a], function->hasImplicitThis() && a == 0) || + writableParam(qualifiers[a])) { // save l-value lValues.push_back(builder.getAccessChain()); } else { @@ -2787,24 +3994,33 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg int rValueCount = 0; std::vector spvArgs; for (int a = 0; a < (int)glslangArgs.size(); ++a) { - const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType(); spv::Id arg; - if (paramType.isOpaque()) { + if (originalParam(qualifiers[a], *argTypes[a], function->hasImplicitThis() && a == 0)) { builder.setAccessChain(lValues[lValueCount]); arg = builder.accessChainGetLValue(); ++lValueCount; - } else if (qualifiers[a] != glslang::EvqConstReadOnly) { + } else if (writableParam(qualifiers[a])) { // need space to hold the copy - arg = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(paramType), "param"); + arg = builder.createVariable(spv::StorageClassFunction, builder.getContainedTypeId(function->getParamType(a)), "param"); if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) { // need to copy the input into output space builder.setAccessChain(lValues[lValueCount]); spv::Id copy = accessChainLoad(*argTypes[a]); - builder.createStore(copy, arg); + builder.clearAccessChain(); + builder.setAccessChainLValue(arg); + multiTypeStore(*argTypes[a], copy); } ++lValueCount; } else { - arg = rValues[rValueCount]; + // process r-value, which involves a copy for a type mismatch + if (function->getParamType(a) != convertGlslangToSpvType(*argTypes[a])) { + spv::Id argCopy = builder.createVariable(spv::StorageClassFunction, function->getParamType(a), "arg"); + builder.clearAccessChain(); + builder.setAccessChainLValue(argCopy); + multiTypeStore(*argTypes[a], rValues[rValueCount]); + arg = builder.createLoad(argCopy); + } else + arg = rValues[rValueCount]; ++rValueCount; } spvArgs.push_back(arg); @@ -2817,11 +4033,13 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg // 4. Copy back out an "out" arguments. lValueCount = 0; for (int a = 0; a < (int)glslangArgs.size(); ++a) { - if (qualifiers[a] != glslang::EvqConstReadOnly) { + if (originalParam(qualifiers[a], *argTypes[a], function->hasImplicitThis() && a == 0)) + ++lValueCount; + else if (writableParam(qualifiers[a])) { if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) { spv::Id copy = builder.createLoad(spvArgs[a]); builder.setAccessChain(lValues[lValueCount]); - accessChainStore(glslangArgs[a]->getAsTyped()->getType(), copy); + multiTypeStore(*argTypes[a], copy); } ++lValueCount; } @@ -2831,13 +4049,12 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg } // Translate AST operation to SPV operation, already having SPV-based operands/types. -spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv::Decoration precision, - spv::Decoration noContraction, +spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, OpDecorations& decorations, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison) { - bool isUnsigned = typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64; - bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble; + bool isUnsigned = isTypeUnsignedInt(typeProxy); + bool isFloat = isTypeFloat(typeProxy); bool isBool = typeProxy == glslang::EbtBool; spv::Op binOp = spv::OpNop; @@ -2969,15 +4186,16 @@ spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv if (binOp != spv::OpNop) { assert(comparison == false); if (builder.isMatrix(left) || builder.isMatrix(right)) - return createBinaryMatrixOperation(binOp, precision, noContraction, typeId, left, right); + return createBinaryMatrixOperation(binOp, decorations, typeId, left, right); // No matrix involved; make both operands be the same number of components, if needed if (needMatchingVectors) - builder.promoteScalar(precision, left, right); + builder.promoteScalar(decorations.precision, left, right); spv::Id result = builder.createBinOp(binOp, typeId, left, right); - addDecoration(result, noContraction); - return builder.setPrecision(result, precision); + builder.addDecoration(result, decorations.noContraction); + builder.addDecoration(result, decorations.nonUniform); + return builder.setPrecision(result, decorations.precision); } if (! comparison) @@ -2985,10 +4203,11 @@ spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv // Handle comparison instructions - if (reduceComparison && (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) { - assert(op == glslang::EOpEqual || op == glslang::EOpNotEqual); - - return builder.createCompositeCompare(precision, left, right, op == glslang::EOpEqual); + if (reduceComparison && (op == glslang::EOpEqual || op == glslang::EOpNotEqual) + && (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) { + spv::Id result = builder.createCompositeCompare(decorations.precision, left, right, op == glslang::EOpEqual); + builder.addDecoration(result, decorations.nonUniform); + return result; } switch (op) { @@ -3048,8 +4267,9 @@ spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv if (binOp != spv::OpNop) { spv::Id result = builder.createBinOp(binOp, typeId, left, right); - addDecoration(result, noContraction); - return builder.setPrecision(result, precision); + builder.addDecoration(result, decorations.noContraction); + builder.addDecoration(result, decorations.nonUniform); + return builder.setPrecision(result, decorations.precision); } return 0; @@ -3069,7 +4289,8 @@ spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv // matrix op scalar op in {+, -, /} // scalar op matrix op in {+, -, /} // -spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id left, spv::Id right) +spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, OpDecorations& decorations, spv::Id typeId, + spv::Id left, spv::Id right) { bool firstClass = true; @@ -3078,7 +4299,8 @@ spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Dec case spv::OpFDiv: if (builder.isMatrix(left) && builder.isScalar(right)) { // turn matrix / scalar into a multiply... - right = builder.createBinOp(spv::OpFDiv, builder.getTypeId(right), builder.makeFloatConstant(1.0F), right); + spv::Id resultType = builder.getTypeId(right); + right = builder.createBinOp(spv::OpFDiv, resultType, builder.makeFpConstant(resultType, 1.0), right); op = spv::OpMatrixTimesScalar; } else firstClass = false; @@ -3107,8 +4329,9 @@ spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Dec if (firstClass) { spv::Id result = builder.createBinOp(op, typeId, left, right); - addDecoration(result, noContraction); - return builder.setPrecision(result, precision); + builder.addDecoration(result, decorations.noContraction); + builder.addDecoration(result, decorations.nonUniform); + return builder.setPrecision(result, decorations.precision); } // Handle component-wise +, -, *, %, and / for all combinations of type. @@ -3135,9 +4358,9 @@ spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Dec std::vector results; spv::Id smearVec = spv::NoResult; if (builder.isScalar(left)) - smearVec = builder.smearScalar(precision, left, vecType); + smearVec = builder.smearScalar(decorations.precision, left, vecType); else if (builder.isScalar(right)) - smearVec = builder.smearScalar(precision, right, vecType); + smearVec = builder.smearScalar(decorations.precision, right, vecType); // do each vector op for (unsigned int c = 0; c < numCols; ++c) { @@ -3146,12 +4369,15 @@ spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Dec spv::Id leftVec = leftMat ? builder.createCompositeExtract( left, vecType, indexes) : smearVec; spv::Id rightVec = rightMat ? builder.createCompositeExtract(right, vecType, indexes) : smearVec; spv::Id result = builder.createBinOp(op, vecType, leftVec, rightVec); - addDecoration(result, noContraction); - results.push_back(builder.setPrecision(result, precision)); + builder.addDecoration(result, decorations.noContraction); + builder.addDecoration(result, decorations.nonUniform); + results.push_back(builder.setPrecision(result, decorations.precision)); } // put the pieces together - return builder.setPrecision(builder.createCompositeConstruct(typeId, results), precision); + spv::Id result = builder.setPrecision(builder.createCompositeConstruct(typeId, results), decorations.precision); + builder.addDecoration(result, decorations.nonUniform); + return result; } default: assert(0); @@ -3159,19 +4385,21 @@ spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Dec } } -spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand, glslang::TBasicType typeProxy) +spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDecorations& decorations, spv::Id typeId, + spv::Id operand, glslang::TBasicType typeProxy) { spv::Op unaryOp = spv::OpNop; + int extBuiltins = -1; int libCall = -1; - bool isUnsigned = typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64; - bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble; + bool isUnsigned = isTypeUnsignedInt(typeProxy); + bool isFloat = isTypeFloat(typeProxy); switch (op) { case glslang::EOpNegative: if (isFloat) { unaryOp = spv::OpFNegate; if (builder.isMatrixType(typeId)) - return createUnaryMatrixOperation(unaryOp, precision, noContraction, typeId, operand, typeProxy); + return createUnaryMatrixOperation(unaryOp, decorations, typeId, operand, typeProxy); } else unaryOp = spv::OpSNegate; break; @@ -3301,6 +4529,10 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv: case glslang::EOpDoubleBitsToUint64: case glslang::EOpInt64BitsToDouble: case glslang::EOpUint64BitsToDouble: + case glslang::EOpFloat16BitsToInt16: + case glslang::EOpFloat16BitsToUint16: + case glslang::EOpInt16BitsToFloat16: + case glslang::EOpUint16BitsToFloat16: unaryOp = spv::OpBitcast; break; @@ -3345,8 +4577,23 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv: case glslang::EOpUnpackInt2x32: case glslang::EOpPackUint2x32: case glslang::EOpUnpackUint2x32: - logger->missingFunctionality("shader int64"); - libCall = spv::GLSLstd450Bad; // TODO: This is a placeholder. + case glslang::EOpPack16: + case glslang::EOpPack32: + case glslang::EOpPack64: + case glslang::EOpUnpack32: + case glslang::EOpUnpack16: + case glslang::EOpUnpack8: + case glslang::EOpPackInt2x16: + case glslang::EOpUnpackInt2x16: + case glslang::EOpPackUint2x16: + case glslang::EOpUnpackUint2x16: + case glslang::EOpPackInt4x16: + case glslang::EOpUnpackInt4x16: + case glslang::EOpPackUint4x16: + case glslang::EOpUnpackUint4x16: + case glslang::EOpPackFloat2x16: + case glslang::EOpUnpackFloat2x16: + unaryOp = spv::OpBitcast; break; case glslang::EOpDPdx: @@ -3383,6 +4630,10 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv: unaryOp = spv::OpFwidthCoarse; break; case glslang::EOpInterpolateAtCentroid: +#ifdef AMD_EXTENSIONS + if (typeProxy == glslang::EbtFloat16) + builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float); +#endif builder.addCapability(spv::CapabilityInterpolationFunction); libCall = spv::GLSLstd450InterpolateAtCentroid; break; @@ -3413,7 +4664,7 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv: // Handle all of the atomics in one place, in createAtomicOperation() std::vector operands; operands.push_back(operand); - return createAtomicOperation(op, precision, typeId, operands, typeProxy); + return createAtomicOperation(op, decorations.precision, typeId, operands, typeProxy); } case glslang::EOpBitFieldReverse: @@ -3434,15 +4685,96 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv: case glslang::EOpBallot: case glslang::EOpReadFirstInvocation: - logger->missingFunctionality("shader ballot"); - libCall = spv::GLSLstd450Bad; - break; - case glslang::EOpAnyInvocation: case glslang::EOpAllInvocations: case glslang::EOpAllInvocationsEqual: - return createInvocationsOperation(op, typeId, operand); +#ifdef AMD_EXTENSIONS + case glslang::EOpMinInvocations: + case glslang::EOpMaxInvocations: + case glslang::EOpAddInvocations: + case glslang::EOpMinInvocationsNonUniform: + case glslang::EOpMaxInvocationsNonUniform: + case glslang::EOpAddInvocationsNonUniform: + case glslang::EOpMinInvocationsInclusiveScan: + case glslang::EOpMaxInvocationsInclusiveScan: + case glslang::EOpAddInvocationsInclusiveScan: + case glslang::EOpMinInvocationsInclusiveScanNonUniform: + case glslang::EOpMaxInvocationsInclusiveScanNonUniform: + case glslang::EOpAddInvocationsInclusiveScanNonUniform: + case glslang::EOpMinInvocationsExclusiveScan: + case glslang::EOpMaxInvocationsExclusiveScan: + case glslang::EOpAddInvocationsExclusiveScan: + case glslang::EOpMinInvocationsExclusiveScanNonUniform: + case glslang::EOpMaxInvocationsExclusiveScanNonUniform: + case glslang::EOpAddInvocationsExclusiveScanNonUniform: +#endif + { + std::vector operands; + operands.push_back(operand); + return createInvocationsOperation(op, typeId, operands, typeProxy); + } + case glslang::EOpSubgroupAll: + case glslang::EOpSubgroupAny: + case glslang::EOpSubgroupAllEqual: + case glslang::EOpSubgroupBroadcastFirst: + case glslang::EOpSubgroupBallot: + case glslang::EOpSubgroupInverseBallot: + case glslang::EOpSubgroupBallotBitCount: + case glslang::EOpSubgroupBallotInclusiveBitCount: + case glslang::EOpSubgroupBallotExclusiveBitCount: + case glslang::EOpSubgroupBallotFindLSB: + case glslang::EOpSubgroupBallotFindMSB: + case glslang::EOpSubgroupAdd: + case glslang::EOpSubgroupMul: + case glslang::EOpSubgroupMin: + case glslang::EOpSubgroupMax: + case glslang::EOpSubgroupAnd: + case glslang::EOpSubgroupOr: + case glslang::EOpSubgroupXor: + case glslang::EOpSubgroupInclusiveAdd: + case glslang::EOpSubgroupInclusiveMul: + case glslang::EOpSubgroupInclusiveMin: + case glslang::EOpSubgroupInclusiveMax: + case glslang::EOpSubgroupInclusiveAnd: + case glslang::EOpSubgroupInclusiveOr: + case glslang::EOpSubgroupInclusiveXor: + case glslang::EOpSubgroupExclusiveAdd: + case glslang::EOpSubgroupExclusiveMul: + case glslang::EOpSubgroupExclusiveMin: + case glslang::EOpSubgroupExclusiveMax: + case glslang::EOpSubgroupExclusiveAnd: + case glslang::EOpSubgroupExclusiveOr: + case glslang::EOpSubgroupExclusiveXor: + case glslang::EOpSubgroupQuadSwapHorizontal: + case glslang::EOpSubgroupQuadSwapVertical: + case glslang::EOpSubgroupQuadSwapDiagonal: { + std::vector operands; + operands.push_back(operand); + return createSubgroupOperation(op, typeId, operands, typeProxy); + } +#ifdef AMD_EXTENSIONS + case glslang::EOpMbcnt: + extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot); + libCall = spv::MbcntAMD; + break; + case glslang::EOpCubeFaceIndex: + extBuiltins = getExtBuiltins(spv::E_SPV_AMD_gcn_shader); + libCall = spv::CubeFaceIndexAMD; + break; + + case glslang::EOpCubeFaceCoord: + extBuiltins = getExtBuiltins(spv::E_SPV_AMD_gcn_shader); + libCall = spv::CubeFaceCoordAMD; + break; +#endif +#ifdef NV_EXTENSIONS + case glslang::EOpSubgroupPartition: + builder.addExtension(spv::E_SPV_NV_shader_subgroup_partitioned); + builder.addCapability(spv::CapabilityGroupNonUniformPartitionedNV); + unaryOp = spv::OpGroupNonUniformPartitionNV; + break; +#endif default: return 0; } @@ -3451,17 +4783,19 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv: if (libCall >= 0) { std::vector args; args.push_back(operand); - id = builder.createBuiltinCall(typeId, stdBuiltins, libCall, args); + id = builder.createBuiltinCall(typeId, extBuiltins >= 0 ? extBuiltins : stdBuiltins, libCall, args); } else { id = builder.createUnaryOp(unaryOp, typeId, operand); } - addDecoration(id, noContraction); - return builder.setPrecision(id, precision); + builder.addDecoration(id, decorations.noContraction); + builder.addDecoration(id, decorations.nonUniform); + return builder.setPrecision(id, decorations.precision); } // Create a unary operation on a matrix -spv::Id TGlslangToSpvTraverser::createUnaryMatrixOperation(spv::Op op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand, glslang::TBasicType /* typeProxy */) +spv::Id TGlslangToSpvTraverser::createUnaryMatrixOperation(spv::Op op, OpDecorations& decorations, spv::Id typeId, + spv::Id operand, glslang::TBasicType /* typeProxy */) { // Handle unary operations vector by vector. // The result type is the same type as the original type. @@ -3483,30 +4817,162 @@ spv::Id TGlslangToSpvTraverser::createUnaryMatrixOperation(spv::Op op, spv::Deco indexes.push_back(c); spv::Id srcVec = builder.createCompositeExtract(operand, srcVecType, indexes); spv::Id destVec = builder.createUnaryOp(op, destVecType, srcVec); - addDecoration(destVec, noContraction); - results.push_back(builder.setPrecision(destVec, precision)); + builder.addDecoration(destVec, decorations.noContraction); + builder.addDecoration(destVec, decorations.nonUniform); + results.push_back(builder.setPrecision(destVec, decorations.precision)); } // put the pieces together - return builder.setPrecision(builder.createCompositeConstruct(typeId, results), precision); + spv::Id result = builder.setPrecision(builder.createCompositeConstruct(typeId, results), decorations.precision); + builder.addDecoration(result, decorations.nonUniform); + return result; } -spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id destType, spv::Id operand, glslang::TBasicType typeProxy) +spv::Id TGlslangToSpvTraverser::createConversionOperation(glslang::TOperator op, spv::Id operand, int vectorSize) +{ + spv::Op convOp = spv::OpNop; + spv::Id type = 0; + + spv::Id result = 0; + + switch(op) { + case glslang::EOpConvInt8ToUint16: + convOp = spv::OpSConvert; + type = builder.makeIntType(16); + break; + case glslang::EOpConvInt8ToUint: + convOp = spv::OpSConvert; + type = builder.makeIntType(32); + break; + case glslang::EOpConvInt8ToUint64: + convOp = spv::OpSConvert; + type = builder.makeIntType(64); + break; + case glslang::EOpConvInt16ToUint8: + convOp = spv::OpSConvert; + type = builder.makeIntType(8); + break; + case glslang::EOpConvInt16ToUint: + convOp = spv::OpSConvert; + type = builder.makeIntType(32); + break; + case glslang::EOpConvInt16ToUint64: + convOp = spv::OpSConvert; + type = builder.makeIntType(64); + break; + case glslang::EOpConvIntToUint8: + convOp = spv::OpSConvert; + type = builder.makeIntType(8); + break; + case glslang::EOpConvIntToUint16: + convOp = spv::OpSConvert; + type = builder.makeIntType(16); + break; + case glslang::EOpConvIntToUint64: + convOp = spv::OpSConvert; + type = builder.makeIntType(64); + break; + case glslang::EOpConvInt64ToUint8: + convOp = spv::OpSConvert; + type = builder.makeIntType(8); + break; + case glslang::EOpConvInt64ToUint16: + convOp = spv::OpSConvert; + type = builder.makeIntType(16); + break; + case glslang::EOpConvInt64ToUint: + convOp = spv::OpSConvert; + type = builder.makeIntType(32); + break; + case glslang::EOpConvUint8ToInt16: + convOp = spv::OpUConvert; + type = builder.makeIntType(16); + break; + case glslang::EOpConvUint8ToInt: + convOp = spv::OpUConvert; + type = builder.makeIntType(32); + break; + case glslang::EOpConvUint8ToInt64: + convOp = spv::OpUConvert; + type = builder.makeIntType(64); + break; + case glslang::EOpConvUint16ToInt8: + convOp = spv::OpUConvert; + type = builder.makeIntType(8); + break; + case glslang::EOpConvUint16ToInt: + convOp = spv::OpUConvert; + type = builder.makeIntType(32); + break; + case glslang::EOpConvUint16ToInt64: + convOp = spv::OpUConvert; + type = builder.makeIntType(64); + break; + case glslang::EOpConvUintToInt8: + convOp = spv::OpUConvert; + type = builder.makeIntType(8); + break; + case glslang::EOpConvUintToInt16: + convOp = spv::OpUConvert; + type = builder.makeIntType(16); + break; + case glslang::EOpConvUintToInt64: + convOp = spv::OpUConvert; + type = builder.makeIntType(64); + break; + case glslang::EOpConvUint64ToInt8: + convOp = spv::OpUConvert; + type = builder.makeIntType(8); + break; + case glslang::EOpConvUint64ToInt16: + convOp = spv::OpUConvert; + type = builder.makeIntType(16); + break; + case glslang::EOpConvUint64ToInt: + convOp = spv::OpUConvert; + type = builder.makeIntType(32); + break; + + default: + assert(false && "Default missing"); + break; + } + + if (vectorSize > 0) + type = builder.makeVectorType(type, vectorSize); + + result = builder.createUnaryOp(convOp, type, operand); + return result; +} + +spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, OpDecorations& decorations, spv::Id destType, + spv::Id operand, glslang::TBasicType typeProxy) { spv::Op convOp = spv::OpNop; spv::Id zero = 0; spv::Id one = 0; - spv::Id type = 0; int vectorSize = builder.isVectorType(destType) ? builder.getNumTypeComponents(destType) : 0; switch (op) { + case glslang::EOpConvInt8ToBool: + case glslang::EOpConvUint8ToBool: + zero = builder.makeUint8Constant(0); + zero = makeSmearedConstant(zero, vectorSize); + return builder.createBinOp(spv::OpINotEqual, destType, operand, zero); + case glslang::EOpConvInt16ToBool: + case glslang::EOpConvUint16ToBool: + zero = builder.makeUint16Constant(0); + zero = makeSmearedConstant(zero, vectorSize); + return builder.createBinOp(spv::OpINotEqual, destType, operand, zero); case glslang::EOpConvIntToBool: case glslang::EOpConvUintToBool: + zero = builder.makeUintConstant(0); + zero = makeSmearedConstant(zero, vectorSize); + return builder.createBinOp(spv::OpINotEqual, destType, operand, zero); case glslang::EOpConvInt64ToBool: case glslang::EOpConvUint64ToBool: - zero = (op == glslang::EOpConvInt64ToBool || - op == glslang::EOpConvUint64ToBool) ? builder.makeUint64Constant(0) : builder.makeUintConstant(0); + zero = builder.makeUint64Constant(0); zero = makeSmearedConstant(zero, vectorSize); return builder.createBinOp(spv::OpINotEqual, destType, operand, zero); @@ -3520,65 +4986,158 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Dec zero = makeSmearedConstant(zero, vectorSize); return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero); + case glslang::EOpConvFloat16ToBool: + zero = builder.makeFloat16Constant(0.0F); + zero = makeSmearedConstant(zero, vectorSize); + return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero); + case glslang::EOpConvBoolToFloat: convOp = spv::OpSelect; - zero = builder.makeFloatConstant(0.0); - one = builder.makeFloatConstant(1.0); + zero = builder.makeFloatConstant(0.0F); + one = builder.makeFloatConstant(1.0F); break; + case glslang::EOpConvBoolToDouble: convOp = spv::OpSelect; zero = builder.makeDoubleConstant(0.0); one = builder.makeDoubleConstant(1.0); break; - case glslang::EOpConvBoolToInt: - case glslang::EOpConvBoolToInt64: - zero = (op == glslang::EOpConvBoolToInt64) ? builder.makeInt64Constant(0) : builder.makeIntConstant(0); - one = (op == glslang::EOpConvBoolToInt64) ? builder.makeInt64Constant(1) : builder.makeIntConstant(1); + + case glslang::EOpConvBoolToFloat16: convOp = spv::OpSelect; + zero = builder.makeFloat16Constant(0.0F); + one = builder.makeFloat16Constant(1.0F); break; - case glslang::EOpConvBoolToUint: - case glslang::EOpConvBoolToUint64: - zero = (op == glslang::EOpConvBoolToUint64) ? builder.makeUint64Constant(0) : builder.makeUintConstant(0); - one = (op == glslang::EOpConvBoolToUint64) ? builder.makeUint64Constant(1) : builder.makeUintConstant(1); + + case glslang::EOpConvBoolToInt8: + zero = builder.makeInt8Constant(0); + one = builder.makeInt8Constant(1); convOp = spv::OpSelect; break; + case glslang::EOpConvBoolToUint8: + zero = builder.makeUint8Constant(0); + one = builder.makeUint8Constant(1); + convOp = spv::OpSelect; + break; + + case glslang::EOpConvBoolToInt16: + zero = builder.makeInt16Constant(0); + one = builder.makeInt16Constant(1); + convOp = spv::OpSelect; + break; + + case glslang::EOpConvBoolToUint16: + zero = builder.makeUint16Constant(0); + one = builder.makeUint16Constant(1); + convOp = spv::OpSelect; + break; + + case glslang::EOpConvBoolToInt: + case glslang::EOpConvBoolToInt64: + if (op == glslang::EOpConvBoolToInt64) + zero = builder.makeInt64Constant(0); + else + zero = builder.makeIntConstant(0); + + if (op == glslang::EOpConvBoolToInt64) + one = builder.makeInt64Constant(1); + else + one = builder.makeIntConstant(1); + + convOp = spv::OpSelect; + break; + + case glslang::EOpConvBoolToUint: + case glslang::EOpConvBoolToUint64: + if (op == glslang::EOpConvBoolToUint64) + zero = builder.makeUint64Constant(0); + else + zero = builder.makeUintConstant(0); + + if (op == glslang::EOpConvBoolToUint64) + one = builder.makeUint64Constant(1); + else + one = builder.makeUintConstant(1); + + convOp = spv::OpSelect; + break; + + case glslang::EOpConvInt8ToFloat16: + case glslang::EOpConvInt8ToFloat: + case glslang::EOpConvInt8ToDouble: + case glslang::EOpConvInt16ToFloat16: + case glslang::EOpConvInt16ToFloat: + case glslang::EOpConvInt16ToDouble: + case glslang::EOpConvIntToFloat16: case glslang::EOpConvIntToFloat: case glslang::EOpConvIntToDouble: case glslang::EOpConvInt64ToFloat: case glslang::EOpConvInt64ToDouble: + case glslang::EOpConvInt64ToFloat16: convOp = spv::OpConvertSToF; break; + case glslang::EOpConvUint8ToFloat16: + case glslang::EOpConvUint8ToFloat: + case glslang::EOpConvUint8ToDouble: + case glslang::EOpConvUint16ToFloat16: + case glslang::EOpConvUint16ToFloat: + case glslang::EOpConvUint16ToDouble: + case glslang::EOpConvUintToFloat16: case glslang::EOpConvUintToFloat: case glslang::EOpConvUintToDouble: case glslang::EOpConvUint64ToFloat: case glslang::EOpConvUint64ToDouble: + case glslang::EOpConvUint64ToFloat16: convOp = spv::OpConvertUToF; break; case glslang::EOpConvDoubleToFloat: case glslang::EOpConvFloatToDouble: + case glslang::EOpConvDoubleToFloat16: + case glslang::EOpConvFloat16ToDouble: + case glslang::EOpConvFloatToFloat16: + case glslang::EOpConvFloat16ToFloat: convOp = spv::OpFConvert; if (builder.isMatrixType(destType)) - return createUnaryMatrixOperation(convOp, precision, noContraction, destType, operand, typeProxy); + return createUnaryMatrixOperation(convOp, decorations, destType, operand, typeProxy); break; + case glslang::EOpConvFloat16ToInt8: + case glslang::EOpConvFloatToInt8: + case glslang::EOpConvDoubleToInt8: + case glslang::EOpConvFloat16ToInt16: + case glslang::EOpConvFloatToInt16: + case glslang::EOpConvDoubleToInt16: + case glslang::EOpConvFloat16ToInt: case glslang::EOpConvFloatToInt: case glslang::EOpConvDoubleToInt: + case glslang::EOpConvFloat16ToInt64: case glslang::EOpConvFloatToInt64: case glslang::EOpConvDoubleToInt64: convOp = spv::OpConvertFToS; break; + case glslang::EOpConvUint8ToInt8: + case glslang::EOpConvInt8ToUint8: + case glslang::EOpConvUint16ToInt16: + case glslang::EOpConvInt16ToUint16: case glslang::EOpConvUintToInt: case glslang::EOpConvIntToUint: case glslang::EOpConvUint64ToInt64: case glslang::EOpConvInt64ToUint64: if (builder.isInSpecConstCodeGenMode()) { // Build zero scalar or vector for OpIAdd. - zero = (op == glslang::EOpConvUintToInt64 || - op == glslang::EOpConvIntToUint64) ? builder.makeUint64Constant(0) : builder.makeUintConstant(0); + if(op == glslang::EOpConvUint8ToInt8 || op == glslang::EOpConvInt8ToUint8) { + zero = builder.makeUint8Constant(0); + } else if (op == glslang::EOpConvUint16ToInt16 || op == glslang::EOpConvInt16ToUint16) { + zero = builder.makeUint16Constant(0); + } else if (op == glslang::EOpConvUint64ToInt64 || op == glslang::EOpConvInt64ToUint64) { + zero = builder.makeUint64Constant(0); + } else { + zero = builder.makeUintConstant(0); + } zero = makeSmearedConstant(zero, vectorSize); // Use OpIAdd, instead of OpBitcast to do the conversion when // generating for OpSpecConstantOp instruction. @@ -3588,59 +5147,117 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Dec convOp = spv::OpBitcast; break; + case glslang::EOpConvFloat16ToUint8: + case glslang::EOpConvFloatToUint8: + case glslang::EOpConvDoubleToUint8: + case glslang::EOpConvFloat16ToUint16: + case glslang::EOpConvFloatToUint16: + case glslang::EOpConvDoubleToUint16: + case glslang::EOpConvFloat16ToUint: case glslang::EOpConvFloatToUint: case glslang::EOpConvDoubleToUint: case glslang::EOpConvFloatToUint64: case glslang::EOpConvDoubleToUint64: + case glslang::EOpConvFloat16ToUint64: convOp = spv::OpConvertFToU; break; + case glslang::EOpConvInt8ToInt16: + case glslang::EOpConvInt8ToInt: + case glslang::EOpConvInt8ToInt64: + case glslang::EOpConvInt16ToInt8: + case glslang::EOpConvInt16ToInt: + case glslang::EOpConvInt16ToInt64: + case glslang::EOpConvIntToInt8: + case glslang::EOpConvIntToInt16: case glslang::EOpConvIntToInt64: + case glslang::EOpConvInt64ToInt8: + case glslang::EOpConvInt64ToInt16: case glslang::EOpConvInt64ToInt: convOp = spv::OpSConvert; break; + case glslang::EOpConvUint8ToUint16: + case glslang::EOpConvUint8ToUint: + case glslang::EOpConvUint8ToUint64: + case glslang::EOpConvUint16ToUint8: + case glslang::EOpConvUint16ToUint: + case glslang::EOpConvUint16ToUint64: + case glslang::EOpConvUintToUint8: + case glslang::EOpConvUintToUint16: case glslang::EOpConvUintToUint64: + case glslang::EOpConvUint64ToUint8: + case glslang::EOpConvUint64ToUint16: case glslang::EOpConvUint64ToUint: convOp = spv::OpUConvert; break; + case glslang::EOpConvInt8ToUint16: + case glslang::EOpConvInt8ToUint: + case glslang::EOpConvInt8ToUint64: + case glslang::EOpConvInt16ToUint8: + case glslang::EOpConvInt16ToUint: + case glslang::EOpConvInt16ToUint64: + case glslang::EOpConvIntToUint8: + case glslang::EOpConvIntToUint16: case glslang::EOpConvIntToUint64: + case glslang::EOpConvInt64ToUint8: + case glslang::EOpConvInt64ToUint16: case glslang::EOpConvInt64ToUint: - case glslang::EOpConvUint64ToInt: + case glslang::EOpConvUint8ToInt16: + case glslang::EOpConvUint8ToInt: + case glslang::EOpConvUint8ToInt64: + case glslang::EOpConvUint16ToInt8: + case glslang::EOpConvUint16ToInt: + case glslang::EOpConvUint16ToInt64: + case glslang::EOpConvUintToInt8: + case glslang::EOpConvUintToInt16: case glslang::EOpConvUintToInt64: + case glslang::EOpConvUint64ToInt8: + case glslang::EOpConvUint64ToInt16: + case glslang::EOpConvUint64ToInt: // OpSConvert/OpUConvert + OpBitCast - switch (op) { - case glslang::EOpConvIntToUint64: - convOp = spv::OpSConvert; - type = builder.makeIntType(64); - break; - case glslang::EOpConvInt64ToUint: - convOp = spv::OpSConvert; - type = builder.makeIntType(32); - break; - case glslang::EOpConvUint64ToInt: - convOp = spv::OpUConvert; - type = builder.makeUintType(32); - break; - case glslang::EOpConvUintToInt64: - convOp = spv::OpUConvert; - type = builder.makeUintType(64); - break; - default: - assert(0); - break; - } - - if (vectorSize > 0) - type = builder.makeVectorType(type, vectorSize); - - operand = builder.createUnaryOp(convOp, type, operand); + operand = createConversionOperation(op, operand, vectorSize); if (builder.isInSpecConstCodeGenMode()) { // Build zero scalar or vector for OpIAdd. - zero = (op == glslang::EOpConvIntToUint64 || - op == glslang::EOpConvUintToInt64) ? builder.makeUint64Constant(0) : builder.makeUintConstant(0); + switch(op) { + case glslang::EOpConvInt16ToUint8: + case glslang::EOpConvIntToUint8: + case glslang::EOpConvInt64ToUint8: + case glslang::EOpConvUint16ToInt8: + case glslang::EOpConvUintToInt8: + case glslang::EOpConvUint64ToInt8: + zero = builder.makeUint8Constant(0); + break; + case glslang::EOpConvInt8ToUint16: + case glslang::EOpConvIntToUint16: + case glslang::EOpConvInt64ToUint16: + case glslang::EOpConvUint8ToInt16: + case glslang::EOpConvUintToInt16: + case glslang::EOpConvUint64ToInt16: + zero = builder.makeUint16Constant(0); + break; + case glslang::EOpConvInt8ToUint: + case glslang::EOpConvInt16ToUint: + case glslang::EOpConvInt64ToUint: + case glslang::EOpConvUint8ToInt: + case glslang::EOpConvUint16ToInt: + case glslang::EOpConvUint64ToInt: + zero = builder.makeUintConstant(0); + break; + case glslang::EOpConvInt8ToUint64: + case glslang::EOpConvInt16ToUint64: + case glslang::EOpConvIntToUint64: + case glslang::EOpConvUint8ToInt64: + case glslang::EOpConvUint16ToInt64: + case glslang::EOpConvUintToInt64: + zero = builder.makeUint64Constant(0); + break; + default: + assert(false && "Default missing"); + break; + } zero = makeSmearedConstant(zero, vectorSize); // Use OpIAdd, instead of OpBitcast to do the conversion when // generating for OpSpecConstantOp instruction. @@ -3664,7 +5281,9 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Dec } else result = builder.createUnaryOp(convOp, destType, operand); - return builder.setPrecision(result, precision); + result = builder.setPrecision(result, decorations.precision); + builder.addDecoration(result, decorations.nonUniform); + return result; } spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vectorSize) @@ -3687,34 +5306,45 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv switch (op) { case glslang::EOpAtomicAdd: case glslang::EOpImageAtomicAdd: + case glslang::EOpAtomicCounterAdd: opCode = spv::OpAtomicIAdd; break; + case glslang::EOpAtomicCounterSubtract: + opCode = spv::OpAtomicISub; + break; case glslang::EOpAtomicMin: case glslang::EOpImageAtomicMin: - opCode = typeProxy == glslang::EbtUint ? spv::OpAtomicUMin : spv::OpAtomicSMin; + case glslang::EOpAtomicCounterMin: + opCode = (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) ? spv::OpAtomicUMin : spv::OpAtomicSMin; break; case glslang::EOpAtomicMax: case glslang::EOpImageAtomicMax: - opCode = typeProxy == glslang::EbtUint ? spv::OpAtomicUMax : spv::OpAtomicSMax; + case glslang::EOpAtomicCounterMax: + opCode = (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) ? spv::OpAtomicUMax : spv::OpAtomicSMax; break; case glslang::EOpAtomicAnd: case glslang::EOpImageAtomicAnd: + case glslang::EOpAtomicCounterAnd: opCode = spv::OpAtomicAnd; break; case glslang::EOpAtomicOr: case glslang::EOpImageAtomicOr: + case glslang::EOpAtomicCounterOr: opCode = spv::OpAtomicOr; break; case glslang::EOpAtomicXor: case glslang::EOpImageAtomicXor: + case glslang::EOpAtomicCounterXor: opCode = spv::OpAtomicXor; break; case glslang::EOpAtomicExchange: case glslang::EOpImageAtomicExchange: + case glslang::EOpAtomicCounterExchange: opCode = spv::OpAtomicExchange; break; case glslang::EOpAtomicCompSwap: case glslang::EOpImageAtomicCompSwap: + case glslang::EOpAtomicCounterCompSwap: opCode = spv::OpAtomicCompareExchange; break; case glslang::EOpAtomicCounterIncrement: @@ -3731,11 +5361,15 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv break; } + if (typeProxy == glslang::EbtInt64 || typeProxy == glslang::EbtUint64) + builder.addCapability(spv::CapabilityInt64Atomics); + // Sort out the operands // - mapping from glslang -> SPV // - there are extra SPV operands with no glslang source // - compare-exchange swaps the value and comparator // - compare-exchange has an extra memory semantics + // - EOpAtomicCounterDecrement needs a post decrement std::vector spvAtomicOperands; // hold the spv operands auto opIt = operands.begin(); // walk the glslang operands spvAtomicOperands.push_back(*(opIt++)); @@ -3754,48 +5388,639 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv for (; opIt != operands.end(); ++opIt) spvAtomicOperands.push_back(*opIt); - return builder.createOp(opCode, typeId, spvAtomicOperands); + spv::Id resultId = builder.createOp(opCode, typeId, spvAtomicOperands); + + // GLSL and HLSL atomic-counter decrement return post-decrement value, + // while SPIR-V returns pre-decrement value. Translate between these semantics. + if (op == glslang::EOpAtomicCounterDecrement) + resultId = builder.createBinOp(spv::OpISub, typeId, resultId, builder.makeIntConstant(1)); + + return resultId; } // Create group invocation operations. -spv::Id TGlslangToSpvTraverser::createInvocationsOperation(glslang::TOperator op, spv::Id typeId, spv::Id operand) +spv::Id TGlslangToSpvTraverser::createInvocationsOperation(glslang::TOperator op, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy) { - builder.addCapability(spv::CapabilityGroups); + bool isUnsigned = isTypeUnsignedInt(typeProxy); + bool isFloat = isTypeFloat(typeProxy); - std::vector operands; - operands.push_back(builder.makeUintConstant(spv::ScopeSubgroup)); - operands.push_back(operand); + spv::Op opCode = spv::OpNop; + std::vector spvGroupOperands; + spv::GroupOperation groupOperation = spv::GroupOperationMax; + + if (op == glslang::EOpBallot || op == glslang::EOpReadFirstInvocation || + op == glslang::EOpReadInvocation) { + builder.addExtension(spv::E_SPV_KHR_shader_ballot); + builder.addCapability(spv::CapabilitySubgroupBallotKHR); + } else if (op == glslang::EOpAnyInvocation || + op == glslang::EOpAllInvocations || + op == glslang::EOpAllInvocationsEqual) { + builder.addExtension(spv::E_SPV_KHR_subgroup_vote); + builder.addCapability(spv::CapabilitySubgroupVoteKHR); + } else { + builder.addCapability(spv::CapabilityGroups); +#ifdef AMD_EXTENSIONS + if (op == glslang::EOpMinInvocationsNonUniform || + op == glslang::EOpMaxInvocationsNonUniform || + op == glslang::EOpAddInvocationsNonUniform || + op == glslang::EOpMinInvocationsInclusiveScanNonUniform || + op == glslang::EOpMaxInvocationsInclusiveScanNonUniform || + op == glslang::EOpAddInvocationsInclusiveScanNonUniform || + op == glslang::EOpMinInvocationsExclusiveScanNonUniform || + op == glslang::EOpMaxInvocationsExclusiveScanNonUniform || + op == glslang::EOpAddInvocationsExclusiveScanNonUniform) + builder.addExtension(spv::E_SPV_AMD_shader_ballot); +#endif + + spvGroupOperands.push_back(builder.makeUintConstant(spv::ScopeSubgroup)); +#ifdef AMD_EXTENSIONS + switch (op) { + case glslang::EOpMinInvocations: + case glslang::EOpMaxInvocations: + case glslang::EOpAddInvocations: + case glslang::EOpMinInvocationsNonUniform: + case glslang::EOpMaxInvocationsNonUniform: + case glslang::EOpAddInvocationsNonUniform: + groupOperation = spv::GroupOperationReduce; + spvGroupOperands.push_back(groupOperation); + break; + case glslang::EOpMinInvocationsInclusiveScan: + case glslang::EOpMaxInvocationsInclusiveScan: + case glslang::EOpAddInvocationsInclusiveScan: + case glslang::EOpMinInvocationsInclusiveScanNonUniform: + case glslang::EOpMaxInvocationsInclusiveScanNonUniform: + case glslang::EOpAddInvocationsInclusiveScanNonUniform: + groupOperation = spv::GroupOperationInclusiveScan; + spvGroupOperands.push_back(groupOperation); + break; + case glslang::EOpMinInvocationsExclusiveScan: + case glslang::EOpMaxInvocationsExclusiveScan: + case glslang::EOpAddInvocationsExclusiveScan: + case glslang::EOpMinInvocationsExclusiveScanNonUniform: + case glslang::EOpMaxInvocationsExclusiveScanNonUniform: + case glslang::EOpAddInvocationsExclusiveScanNonUniform: + groupOperation = spv::GroupOperationExclusiveScan; + spvGroupOperands.push_back(groupOperation); + break; + default: + break; + } +#endif + } + + for (auto opIt = operands.begin(); opIt != operands.end(); ++opIt) + spvGroupOperands.push_back(*opIt); switch (op) { case glslang::EOpAnyInvocation: + opCode = spv::OpSubgroupAnyKHR; + break; case glslang::EOpAllInvocations: - return builder.createOp(op == glslang::EOpAnyInvocation ? spv::OpGroupAny : spv::OpGroupAll, typeId, operands); - + opCode = spv::OpSubgroupAllKHR; + break; case glslang::EOpAllInvocationsEqual: + opCode = spv::OpSubgroupAllEqualKHR; + break; + case glslang::EOpReadInvocation: + opCode = spv::OpSubgroupReadInvocationKHR; + if (builder.isVectorType(typeId)) + return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands); + break; + case glslang::EOpReadFirstInvocation: + opCode = spv::OpSubgroupFirstInvocationKHR; + break; + case glslang::EOpBallot: { - spv::Id groupAll = builder.createOp(spv::OpGroupAll, typeId, operands); - spv::Id groupAny = builder.createOp(spv::OpGroupAny, typeId, operands); + // NOTE: According to the spec, the result type of "OpSubgroupBallotKHR" must be a 4 component vector of 32 + // bit integer types. The GLSL built-in function "ballotARB()" assumes the maximum number of invocations in + // a subgroup is 64. Thus, we have to convert uvec4.xy to uint64_t as follow: + // + // result = Bitcast(SubgroupBallotKHR(Predicate).xy) + // + spv::Id uintType = builder.makeUintType(32); + spv::Id uvec4Type = builder.makeVectorType(uintType, 4); + spv::Id result = builder.createOp(spv::OpSubgroupBallotKHR, uvec4Type, spvGroupOperands); - return builder.createBinOp(spv::OpLogicalOr, typeId, groupAll, - builder.createUnaryOp(spv::OpLogicalNot, typeId, groupAny)); + std::vector components; + components.push_back(builder.createCompositeExtract(result, uintType, 0)); + components.push_back(builder.createCompositeExtract(result, uintType, 1)); + + spv::Id uvec2Type = builder.makeVectorType(uintType, 2); + return builder.createUnaryOp(spv::OpBitcast, typeId, + builder.createCompositeConstruct(uvec2Type, components)); } + +#ifdef AMD_EXTENSIONS + case glslang::EOpMinInvocations: + case glslang::EOpMaxInvocations: + case glslang::EOpAddInvocations: + case glslang::EOpMinInvocationsInclusiveScan: + case glslang::EOpMaxInvocationsInclusiveScan: + case glslang::EOpAddInvocationsInclusiveScan: + case glslang::EOpMinInvocationsExclusiveScan: + case glslang::EOpMaxInvocationsExclusiveScan: + case glslang::EOpAddInvocationsExclusiveScan: + if (op == glslang::EOpMinInvocations || + op == glslang::EOpMinInvocationsInclusiveScan || + op == glslang::EOpMinInvocationsExclusiveScan) { + if (isFloat) + opCode = spv::OpGroupFMin; + else { + if (isUnsigned) + opCode = spv::OpGroupUMin; + else + opCode = spv::OpGroupSMin; + } + } else if (op == glslang::EOpMaxInvocations || + op == glslang::EOpMaxInvocationsInclusiveScan || + op == glslang::EOpMaxInvocationsExclusiveScan) { + if (isFloat) + opCode = spv::OpGroupFMax; + else { + if (isUnsigned) + opCode = spv::OpGroupUMax; + else + opCode = spv::OpGroupSMax; + } + } else { + if (isFloat) + opCode = spv::OpGroupFAdd; + else + opCode = spv::OpGroupIAdd; + } + + if (builder.isVectorType(typeId)) + return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands); + + break; + case glslang::EOpMinInvocationsNonUniform: + case glslang::EOpMaxInvocationsNonUniform: + case glslang::EOpAddInvocationsNonUniform: + case glslang::EOpMinInvocationsInclusiveScanNonUniform: + case glslang::EOpMaxInvocationsInclusiveScanNonUniform: + case glslang::EOpAddInvocationsInclusiveScanNonUniform: + case glslang::EOpMinInvocationsExclusiveScanNonUniform: + case glslang::EOpMaxInvocationsExclusiveScanNonUniform: + case glslang::EOpAddInvocationsExclusiveScanNonUniform: + if (op == glslang::EOpMinInvocationsNonUniform || + op == glslang::EOpMinInvocationsInclusiveScanNonUniform || + op == glslang::EOpMinInvocationsExclusiveScanNonUniform) { + if (isFloat) + opCode = spv::OpGroupFMinNonUniformAMD; + else { + if (isUnsigned) + opCode = spv::OpGroupUMinNonUniformAMD; + else + opCode = spv::OpGroupSMinNonUniformAMD; + } + } + else if (op == glslang::EOpMaxInvocationsNonUniform || + op == glslang::EOpMaxInvocationsInclusiveScanNonUniform || + op == glslang::EOpMaxInvocationsExclusiveScanNonUniform) { + if (isFloat) + opCode = spv::OpGroupFMaxNonUniformAMD; + else { + if (isUnsigned) + opCode = spv::OpGroupUMaxNonUniformAMD; + else + opCode = spv::OpGroupSMaxNonUniformAMD; + } + } + else { + if (isFloat) + opCode = spv::OpGroupFAddNonUniformAMD; + else + opCode = spv::OpGroupIAddNonUniformAMD; + } + + if (builder.isVectorType(typeId)) + return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands); + + break; +#endif default: logger->missingFunctionality("invocation operation"); return spv::NoResult; } + + assert(opCode != spv::OpNop); + return builder.createOp(opCode, typeId, spvGroupOperands); +} + +// Create group invocation operations on a vector +spv::Id TGlslangToSpvTraverser::CreateInvocationsVectorOperation(spv::Op op, spv::GroupOperation groupOperation, spv::Id typeId, std::vector& operands) +{ +#ifdef AMD_EXTENSIONS + assert(op == spv::OpGroupFMin || op == spv::OpGroupUMin || op == spv::OpGroupSMin || + op == spv::OpGroupFMax || op == spv::OpGroupUMax || op == spv::OpGroupSMax || + op == spv::OpGroupFAdd || op == spv::OpGroupIAdd || op == spv::OpGroupBroadcast || + op == spv::OpSubgroupReadInvocationKHR || + op == spv::OpGroupFMinNonUniformAMD || op == spv::OpGroupUMinNonUniformAMD || op == spv::OpGroupSMinNonUniformAMD || + op == spv::OpGroupFMaxNonUniformAMD || op == spv::OpGroupUMaxNonUniformAMD || op == spv::OpGroupSMaxNonUniformAMD || + op == spv::OpGroupFAddNonUniformAMD || op == spv::OpGroupIAddNonUniformAMD); +#else + assert(op == spv::OpGroupFMin || op == spv::OpGroupUMin || op == spv::OpGroupSMin || + op == spv::OpGroupFMax || op == spv::OpGroupUMax || op == spv::OpGroupSMax || + op == spv::OpGroupFAdd || op == spv::OpGroupIAdd || op == spv::OpGroupBroadcast || + op == spv::OpSubgroupReadInvocationKHR); +#endif + + // Handle group invocation operations scalar by scalar. + // The result type is the same type as the original type. + // The algorithm is to: + // - break the vector into scalars + // - apply the operation to each scalar + // - make a vector out the scalar results + + // get the types sorted out + int numComponents = builder.getNumComponents(operands[0]); + spv::Id scalarType = builder.getScalarTypeId(builder.getTypeId(operands[0])); + std::vector results; + + // do each scalar op + for (int comp = 0; comp < numComponents; ++comp) { + std::vector indexes; + indexes.push_back(comp); + spv::Id scalar = builder.createCompositeExtract(operands[0], scalarType, indexes); + std::vector spvGroupOperands; + if (op == spv::OpSubgroupReadInvocationKHR) { + spvGroupOperands.push_back(scalar); + spvGroupOperands.push_back(operands[1]); + } else if (op == spv::OpGroupBroadcast) { + spvGroupOperands.push_back(builder.makeUintConstant(spv::ScopeSubgroup)); + spvGroupOperands.push_back(scalar); + spvGroupOperands.push_back(operands[1]); + } else { + spvGroupOperands.push_back(builder.makeUintConstant(spv::ScopeSubgroup)); + spvGroupOperands.push_back(groupOperation); + spvGroupOperands.push_back(scalar); + } + + results.push_back(builder.createOp(op, scalarType, spvGroupOperands)); + } + + // put the pieces together + return builder.createCompositeConstruct(typeId, results); +} + +// Create subgroup invocation operations. +spv::Id TGlslangToSpvTraverser::createSubgroupOperation(glslang::TOperator op, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy) +{ + // Add the required capabilities. + switch (op) { + case glslang::EOpSubgroupElect: + builder.addCapability(spv::CapabilityGroupNonUniform); + break; + case glslang::EOpSubgroupAll: + case glslang::EOpSubgroupAny: + case glslang::EOpSubgroupAllEqual: + builder.addCapability(spv::CapabilityGroupNonUniform); + builder.addCapability(spv::CapabilityGroupNonUniformVote); + break; + case glslang::EOpSubgroupBroadcast: + case glslang::EOpSubgroupBroadcastFirst: + case glslang::EOpSubgroupBallot: + case glslang::EOpSubgroupInverseBallot: + case glslang::EOpSubgroupBallotBitExtract: + case glslang::EOpSubgroupBallotBitCount: + case glslang::EOpSubgroupBallotInclusiveBitCount: + case glslang::EOpSubgroupBallotExclusiveBitCount: + case glslang::EOpSubgroupBallotFindLSB: + case glslang::EOpSubgroupBallotFindMSB: + builder.addCapability(spv::CapabilityGroupNonUniform); + builder.addCapability(spv::CapabilityGroupNonUniformBallot); + break; + case glslang::EOpSubgroupShuffle: + case glslang::EOpSubgroupShuffleXor: + builder.addCapability(spv::CapabilityGroupNonUniform); + builder.addCapability(spv::CapabilityGroupNonUniformShuffle); + break; + case glslang::EOpSubgroupShuffleUp: + case glslang::EOpSubgroupShuffleDown: + builder.addCapability(spv::CapabilityGroupNonUniform); + builder.addCapability(spv::CapabilityGroupNonUniformShuffleRelative); + break; + case glslang::EOpSubgroupAdd: + case glslang::EOpSubgroupMul: + case glslang::EOpSubgroupMin: + case glslang::EOpSubgroupMax: + case glslang::EOpSubgroupAnd: + case glslang::EOpSubgroupOr: + case glslang::EOpSubgroupXor: + case glslang::EOpSubgroupInclusiveAdd: + case glslang::EOpSubgroupInclusiveMul: + case glslang::EOpSubgroupInclusiveMin: + case glslang::EOpSubgroupInclusiveMax: + case glslang::EOpSubgroupInclusiveAnd: + case glslang::EOpSubgroupInclusiveOr: + case glslang::EOpSubgroupInclusiveXor: + case glslang::EOpSubgroupExclusiveAdd: + case glslang::EOpSubgroupExclusiveMul: + case glslang::EOpSubgroupExclusiveMin: + case glslang::EOpSubgroupExclusiveMax: + case glslang::EOpSubgroupExclusiveAnd: + case glslang::EOpSubgroupExclusiveOr: + case glslang::EOpSubgroupExclusiveXor: + builder.addCapability(spv::CapabilityGroupNonUniform); + builder.addCapability(spv::CapabilityGroupNonUniformArithmetic); + break; + case glslang::EOpSubgroupClusteredAdd: + case glslang::EOpSubgroupClusteredMul: + case glslang::EOpSubgroupClusteredMin: + case glslang::EOpSubgroupClusteredMax: + case glslang::EOpSubgroupClusteredAnd: + case glslang::EOpSubgroupClusteredOr: + case glslang::EOpSubgroupClusteredXor: + builder.addCapability(spv::CapabilityGroupNonUniform); + builder.addCapability(spv::CapabilityGroupNonUniformClustered); + break; + case glslang::EOpSubgroupQuadBroadcast: + case glslang::EOpSubgroupQuadSwapHorizontal: + case glslang::EOpSubgroupQuadSwapVertical: + case glslang::EOpSubgroupQuadSwapDiagonal: + builder.addCapability(spv::CapabilityGroupNonUniform); + builder.addCapability(spv::CapabilityGroupNonUniformQuad); + break; +#ifdef NV_EXTENSIONS + case glslang::EOpSubgroupPartitionedAdd: + case glslang::EOpSubgroupPartitionedMul: + case glslang::EOpSubgroupPartitionedMin: + case glslang::EOpSubgroupPartitionedMax: + case glslang::EOpSubgroupPartitionedAnd: + case glslang::EOpSubgroupPartitionedOr: + case glslang::EOpSubgroupPartitionedXor: + case glslang::EOpSubgroupPartitionedInclusiveAdd: + case glslang::EOpSubgroupPartitionedInclusiveMul: + case glslang::EOpSubgroupPartitionedInclusiveMin: + case glslang::EOpSubgroupPartitionedInclusiveMax: + case glslang::EOpSubgroupPartitionedInclusiveAnd: + case glslang::EOpSubgroupPartitionedInclusiveOr: + case glslang::EOpSubgroupPartitionedInclusiveXor: + case glslang::EOpSubgroupPartitionedExclusiveAdd: + case glslang::EOpSubgroupPartitionedExclusiveMul: + case glslang::EOpSubgroupPartitionedExclusiveMin: + case glslang::EOpSubgroupPartitionedExclusiveMax: + case glslang::EOpSubgroupPartitionedExclusiveAnd: + case glslang::EOpSubgroupPartitionedExclusiveOr: + case glslang::EOpSubgroupPartitionedExclusiveXor: + builder.addExtension(spv::E_SPV_NV_shader_subgroup_partitioned); + builder.addCapability(spv::CapabilityGroupNonUniformPartitionedNV); + break; +#endif + default: assert(0 && "Unhandled subgroup operation!"); + } + + const bool isUnsigned = typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64; + const bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble; + const bool isBool = typeProxy == glslang::EbtBool; + + spv::Op opCode = spv::OpNop; + + // Figure out which opcode to use. + switch (op) { + case glslang::EOpSubgroupElect: opCode = spv::OpGroupNonUniformElect; break; + case glslang::EOpSubgroupAll: opCode = spv::OpGroupNonUniformAll; break; + case glslang::EOpSubgroupAny: opCode = spv::OpGroupNonUniformAny; break; + case glslang::EOpSubgroupAllEqual: opCode = spv::OpGroupNonUniformAllEqual; break; + case glslang::EOpSubgroupBroadcast: opCode = spv::OpGroupNonUniformBroadcast; break; + case glslang::EOpSubgroupBroadcastFirst: opCode = spv::OpGroupNonUniformBroadcastFirst; break; + case glslang::EOpSubgroupBallot: opCode = spv::OpGroupNonUniformBallot; break; + case glslang::EOpSubgroupInverseBallot: opCode = spv::OpGroupNonUniformInverseBallot; break; + case glslang::EOpSubgroupBallotBitExtract: opCode = spv::OpGroupNonUniformBallotBitExtract; break; + case glslang::EOpSubgroupBallotBitCount: + case glslang::EOpSubgroupBallotInclusiveBitCount: + case glslang::EOpSubgroupBallotExclusiveBitCount: opCode = spv::OpGroupNonUniformBallotBitCount; break; + case glslang::EOpSubgroupBallotFindLSB: opCode = spv::OpGroupNonUniformBallotFindLSB; break; + case glslang::EOpSubgroupBallotFindMSB: opCode = spv::OpGroupNonUniformBallotFindMSB; break; + case glslang::EOpSubgroupShuffle: opCode = spv::OpGroupNonUniformShuffle; break; + case glslang::EOpSubgroupShuffleXor: opCode = spv::OpGroupNonUniformShuffleXor; break; + case glslang::EOpSubgroupShuffleUp: opCode = spv::OpGroupNonUniformShuffleUp; break; + case glslang::EOpSubgroupShuffleDown: opCode = spv::OpGroupNonUniformShuffleDown; break; + case glslang::EOpSubgroupAdd: + case glslang::EOpSubgroupInclusiveAdd: + case glslang::EOpSubgroupExclusiveAdd: + case glslang::EOpSubgroupClusteredAdd: +#ifdef NV_EXTENSIONS + case glslang::EOpSubgroupPartitionedAdd: + case glslang::EOpSubgroupPartitionedInclusiveAdd: + case glslang::EOpSubgroupPartitionedExclusiveAdd: +#endif + if (isFloat) { + opCode = spv::OpGroupNonUniformFAdd; + } else { + opCode = spv::OpGroupNonUniformIAdd; + } + break; + case glslang::EOpSubgroupMul: + case glslang::EOpSubgroupInclusiveMul: + case glslang::EOpSubgroupExclusiveMul: + case glslang::EOpSubgroupClusteredMul: +#ifdef NV_EXTENSIONS + case glslang::EOpSubgroupPartitionedMul: + case glslang::EOpSubgroupPartitionedInclusiveMul: + case glslang::EOpSubgroupPartitionedExclusiveMul: +#endif + if (isFloat) { + opCode = spv::OpGroupNonUniformFMul; + } else { + opCode = spv::OpGroupNonUniformIMul; + } + break; + case glslang::EOpSubgroupMin: + case glslang::EOpSubgroupInclusiveMin: + case glslang::EOpSubgroupExclusiveMin: + case glslang::EOpSubgroupClusteredMin: +#ifdef NV_EXTENSIONS + case glslang::EOpSubgroupPartitionedMin: + case glslang::EOpSubgroupPartitionedInclusiveMin: + case glslang::EOpSubgroupPartitionedExclusiveMin: +#endif + if (isFloat) { + opCode = spv::OpGroupNonUniformFMin; + } else if (isUnsigned) { + opCode = spv::OpGroupNonUniformUMin; + } else { + opCode = spv::OpGroupNonUniformSMin; + } + break; + case glslang::EOpSubgroupMax: + case glslang::EOpSubgroupInclusiveMax: + case glslang::EOpSubgroupExclusiveMax: + case glslang::EOpSubgroupClusteredMax: +#ifdef NV_EXTENSIONS + case glslang::EOpSubgroupPartitionedMax: + case glslang::EOpSubgroupPartitionedInclusiveMax: + case glslang::EOpSubgroupPartitionedExclusiveMax: +#endif + if (isFloat) { + opCode = spv::OpGroupNonUniformFMax; + } else if (isUnsigned) { + opCode = spv::OpGroupNonUniformUMax; + } else { + opCode = spv::OpGroupNonUniformSMax; + } + break; + case glslang::EOpSubgroupAnd: + case glslang::EOpSubgroupInclusiveAnd: + case glslang::EOpSubgroupExclusiveAnd: + case glslang::EOpSubgroupClusteredAnd: +#ifdef NV_EXTENSIONS + case glslang::EOpSubgroupPartitionedAnd: + case glslang::EOpSubgroupPartitionedInclusiveAnd: + case glslang::EOpSubgroupPartitionedExclusiveAnd: +#endif + if (isBool) { + opCode = spv::OpGroupNonUniformLogicalAnd; + } else { + opCode = spv::OpGroupNonUniformBitwiseAnd; + } + break; + case glslang::EOpSubgroupOr: + case glslang::EOpSubgroupInclusiveOr: + case glslang::EOpSubgroupExclusiveOr: + case glslang::EOpSubgroupClusteredOr: +#ifdef NV_EXTENSIONS + case glslang::EOpSubgroupPartitionedOr: + case glslang::EOpSubgroupPartitionedInclusiveOr: + case glslang::EOpSubgroupPartitionedExclusiveOr: +#endif + if (isBool) { + opCode = spv::OpGroupNonUniformLogicalOr; + } else { + opCode = spv::OpGroupNonUniformBitwiseOr; + } + break; + case glslang::EOpSubgroupXor: + case glslang::EOpSubgroupInclusiveXor: + case glslang::EOpSubgroupExclusiveXor: + case glslang::EOpSubgroupClusteredXor: +#ifdef NV_EXTENSIONS + case glslang::EOpSubgroupPartitionedXor: + case glslang::EOpSubgroupPartitionedInclusiveXor: + case glslang::EOpSubgroupPartitionedExclusiveXor: +#endif + if (isBool) { + opCode = spv::OpGroupNonUniformLogicalXor; + } else { + opCode = spv::OpGroupNonUniformBitwiseXor; + } + break; + case glslang::EOpSubgroupQuadBroadcast: opCode = spv::OpGroupNonUniformQuadBroadcast; break; + case glslang::EOpSubgroupQuadSwapHorizontal: + case glslang::EOpSubgroupQuadSwapVertical: + case glslang::EOpSubgroupQuadSwapDiagonal: opCode = spv::OpGroupNonUniformQuadSwap; break; + default: assert(0 && "Unhandled subgroup operation!"); + } + + std::vector spvGroupOperands; + + // Every operation begins with the Execution Scope operand. + spvGroupOperands.push_back(builder.makeUintConstant(spv::ScopeSubgroup)); + + // Next, for all operations that use a Group Operation, push that as an operand. + switch (op) { + default: break; + case glslang::EOpSubgroupBallotBitCount: + case glslang::EOpSubgroupAdd: + case glslang::EOpSubgroupMul: + case glslang::EOpSubgroupMin: + case glslang::EOpSubgroupMax: + case glslang::EOpSubgroupAnd: + case glslang::EOpSubgroupOr: + case glslang::EOpSubgroupXor: + spvGroupOperands.push_back(spv::GroupOperationReduce); + break; + case glslang::EOpSubgroupBallotInclusiveBitCount: + case glslang::EOpSubgroupInclusiveAdd: + case glslang::EOpSubgroupInclusiveMul: + case glslang::EOpSubgroupInclusiveMin: + case glslang::EOpSubgroupInclusiveMax: + case glslang::EOpSubgroupInclusiveAnd: + case glslang::EOpSubgroupInclusiveOr: + case glslang::EOpSubgroupInclusiveXor: + spvGroupOperands.push_back(spv::GroupOperationInclusiveScan); + break; + case glslang::EOpSubgroupBallotExclusiveBitCount: + case glslang::EOpSubgroupExclusiveAdd: + case glslang::EOpSubgroupExclusiveMul: + case glslang::EOpSubgroupExclusiveMin: + case glslang::EOpSubgroupExclusiveMax: + case glslang::EOpSubgroupExclusiveAnd: + case glslang::EOpSubgroupExclusiveOr: + case glslang::EOpSubgroupExclusiveXor: + spvGroupOperands.push_back(spv::GroupOperationExclusiveScan); + break; + case glslang::EOpSubgroupClusteredAdd: + case glslang::EOpSubgroupClusteredMul: + case glslang::EOpSubgroupClusteredMin: + case glslang::EOpSubgroupClusteredMax: + case glslang::EOpSubgroupClusteredAnd: + case glslang::EOpSubgroupClusteredOr: + case glslang::EOpSubgroupClusteredXor: + spvGroupOperands.push_back(spv::GroupOperationClusteredReduce); + break; +#ifdef NV_EXTENSIONS + case glslang::EOpSubgroupPartitionedAdd: + case glslang::EOpSubgroupPartitionedMul: + case glslang::EOpSubgroupPartitionedMin: + case glslang::EOpSubgroupPartitionedMax: + case glslang::EOpSubgroupPartitionedAnd: + case glslang::EOpSubgroupPartitionedOr: + case glslang::EOpSubgroupPartitionedXor: + spvGroupOperands.push_back(spv::GroupOperationPartitionedReduceNV); + break; + case glslang::EOpSubgroupPartitionedInclusiveAdd: + case glslang::EOpSubgroupPartitionedInclusiveMul: + case glslang::EOpSubgroupPartitionedInclusiveMin: + case glslang::EOpSubgroupPartitionedInclusiveMax: + case glslang::EOpSubgroupPartitionedInclusiveAnd: + case glslang::EOpSubgroupPartitionedInclusiveOr: + case glslang::EOpSubgroupPartitionedInclusiveXor: + spvGroupOperands.push_back(spv::GroupOperationPartitionedInclusiveScanNV); + break; + case glslang::EOpSubgroupPartitionedExclusiveAdd: + case glslang::EOpSubgroupPartitionedExclusiveMul: + case glslang::EOpSubgroupPartitionedExclusiveMin: + case glslang::EOpSubgroupPartitionedExclusiveMax: + case glslang::EOpSubgroupPartitionedExclusiveAnd: + case glslang::EOpSubgroupPartitionedExclusiveOr: + case glslang::EOpSubgroupPartitionedExclusiveXor: + spvGroupOperands.push_back(spv::GroupOperationPartitionedExclusiveScanNV); + break; +#endif + } + + // Push back the operands next. + for (auto opIt : operands) { + spvGroupOperands.push_back(opIt); + } + + // Some opcodes have additional operands. + switch (op) { + default: break; + case glslang::EOpSubgroupQuadSwapHorizontal: spvGroupOperands.push_back(builder.makeUintConstant(0)); break; + case glslang::EOpSubgroupQuadSwapVertical: spvGroupOperands.push_back(builder.makeUintConstant(1)); break; + case glslang::EOpSubgroupQuadSwapDiagonal: spvGroupOperands.push_back(builder.makeUintConstant(2)); break; + } + + return builder.createOp(opCode, typeId, spvGroupOperands); } spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy) { - bool isUnsigned = typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64; - bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble; + bool isUnsigned = isTypeUnsignedInt(typeProxy); + bool isFloat = isTypeFloat(typeProxy); spv::Op opCode = spv::OpNop; + int extBuiltins = -1; int libCall = -1; size_t consumedOperands = operands.size(); spv::Id typeId0 = 0; if (consumedOperands > 0) typeId0 = builder.getTypeId(operands[0]); + spv::Id typeId1 = 0; + if (consumedOperands > 1) + typeId1 = builder.getTypeId(operands[1]); spv::Id frexpIntType = 0; switch (op) { @@ -3876,10 +6101,18 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv:: libCall = spv::GLSLstd450Refract; break; case glslang::EOpInterpolateAtSample: +#ifdef AMD_EXTENSIONS + if (typeProxy == glslang::EbtFloat16) + builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float); +#endif builder.addCapability(spv::CapabilityInterpolationFunction); libCall = spv::GLSLstd450InterpolateAtSample; break; case glslang::EOpInterpolateAtOffset: +#ifdef AMD_EXTENSIONS + if (typeProxy == glslang::EbtFloat16) + builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float); +#endif builder.addCapability(spv::CapabilityInterpolationFunction); libCall = spv::GLSLstd450InterpolateAtOffset; break; @@ -3917,22 +6150,125 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv:: libCall = spv::GLSLstd450Fma; break; case glslang::EOpFrexp: - libCall = spv::GLSLstd450FrexpStruct; - if (builder.getNumComponents(operands[0]) == 1) - frexpIntType = builder.makeIntegerType(32, true); - else - frexpIntType = builder.makeVectorType(builder.makeIntegerType(32, true), builder.getNumComponents(operands[0])); - typeId = builder.makeStructResultType(typeId0, frexpIntType); - consumedOperands = 1; + { + libCall = spv::GLSLstd450FrexpStruct; + assert(builder.isPointerType(typeId1)); + typeId1 = builder.getContainedTypeId(typeId1); + int width = builder.getScalarTypeWidth(typeId1); +#ifdef AMD_EXTENSIONS + if (width == 16) + // Using 16-bit exp operand, enable extension SPV_AMD_gpu_shader_int16 + builder.addExtension(spv::E_SPV_AMD_gpu_shader_int16); +#endif + if (builder.getNumComponents(operands[0]) == 1) + frexpIntType = builder.makeIntegerType(width, true); + else + frexpIntType = builder.makeVectorType(builder.makeIntegerType(width, true), builder.getNumComponents(operands[0])); + typeId = builder.makeStructResultType(typeId0, frexpIntType); + consumedOperands = 1; + } break; case glslang::EOpLdexp: libCall = spv::GLSLstd450Ldexp; break; case glslang::EOpReadInvocation: - logger->missingFunctionality("shader ballot"); - libCall = spv::GLSLstd450Bad; + return createInvocationsOperation(op, typeId, operands, typeProxy); + + case glslang::EOpSubgroupBroadcast: + case glslang::EOpSubgroupBallotBitExtract: + case glslang::EOpSubgroupShuffle: + case glslang::EOpSubgroupShuffleXor: + case glslang::EOpSubgroupShuffleUp: + case glslang::EOpSubgroupShuffleDown: + case glslang::EOpSubgroupClusteredAdd: + case glslang::EOpSubgroupClusteredMul: + case glslang::EOpSubgroupClusteredMin: + case glslang::EOpSubgroupClusteredMax: + case glslang::EOpSubgroupClusteredAnd: + case glslang::EOpSubgroupClusteredOr: + case glslang::EOpSubgroupClusteredXor: + case glslang::EOpSubgroupQuadBroadcast: +#ifdef NV_EXTENSIONS + case glslang::EOpSubgroupPartitionedAdd: + case glslang::EOpSubgroupPartitionedMul: + case glslang::EOpSubgroupPartitionedMin: + case glslang::EOpSubgroupPartitionedMax: + case glslang::EOpSubgroupPartitionedAnd: + case glslang::EOpSubgroupPartitionedOr: + case glslang::EOpSubgroupPartitionedXor: + case glslang::EOpSubgroupPartitionedInclusiveAdd: + case glslang::EOpSubgroupPartitionedInclusiveMul: + case glslang::EOpSubgroupPartitionedInclusiveMin: + case glslang::EOpSubgroupPartitionedInclusiveMax: + case glslang::EOpSubgroupPartitionedInclusiveAnd: + case glslang::EOpSubgroupPartitionedInclusiveOr: + case glslang::EOpSubgroupPartitionedInclusiveXor: + case glslang::EOpSubgroupPartitionedExclusiveAdd: + case glslang::EOpSubgroupPartitionedExclusiveMul: + case glslang::EOpSubgroupPartitionedExclusiveMin: + case glslang::EOpSubgroupPartitionedExclusiveMax: + case glslang::EOpSubgroupPartitionedExclusiveAnd: + case glslang::EOpSubgroupPartitionedExclusiveOr: + case glslang::EOpSubgroupPartitionedExclusiveXor: +#endif + return createSubgroupOperation(op, typeId, operands, typeProxy); + +#ifdef AMD_EXTENSIONS + case glslang::EOpSwizzleInvocations: + extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot); + libCall = spv::SwizzleInvocationsAMD; break; + case glslang::EOpSwizzleInvocationsMasked: + extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot); + libCall = spv::SwizzleInvocationsMaskedAMD; + break; + case glslang::EOpWriteInvocation: + extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot); + libCall = spv::WriteInvocationAMD; + break; + + case glslang::EOpMin3: + extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax); + if (isFloat) + libCall = spv::FMin3AMD; + else { + if (isUnsigned) + libCall = spv::UMin3AMD; + else + libCall = spv::SMin3AMD; + } + break; + case glslang::EOpMax3: + extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax); + if (isFloat) + libCall = spv::FMax3AMD; + else { + if (isUnsigned) + libCall = spv::UMax3AMD; + else + libCall = spv::SMax3AMD; + } + break; + case glslang::EOpMid3: + extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax); + if (isFloat) + libCall = spv::FMid3AMD; + else { + if (isUnsigned) + libCall = spv::UMid3AMD; + else + libCall = spv::SMid3AMD; + } + break; + + case glslang::EOpInterpolateAtVertex: + if (typeProxy == glslang::EbtFloat16) + builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float); + extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_explicit_vertex_parameter); + libCall = spv::InterpolateAtVertexAMD; + break; +#endif default: return 0; @@ -3944,7 +6280,7 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv:: // Construct the call arguments, without modifying the original operands vector. // We might need the remaining arguments, e.g. in the EOpFrexp case. std::vector callArguments(operands.begin(), operands.begin() + consumedOperands); - id = builder.createBuiltinCall(typeId, stdBuiltins, libCall, callArguments); + id = builder.createBuiltinCall(typeId, extBuiltins >= 0 ? extBuiltins : stdBuiltins, libCall, callArguments); } else { switch (consumedOperands) { case 0: @@ -3979,9 +6315,18 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv:: builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]); break; case glslang::EOpFrexp: - assert(operands.size() == 2); - builder.createStore(builder.createCompositeExtract(id, frexpIntType, 1), operands[1]); - id = builder.createCompositeExtract(id, typeId0, 0); + { + assert(operands.size() == 2); + if (builder.isFloatType(builder.getScalarTypeId(typeId1))) { + // "exp" is floating-point type (from HLSL intrinsic) + spv::Id member1 = builder.createCompositeExtract(id, frexpIntType, 1); + member1 = builder.createUnaryOp(spv::OpConvertSToF, typeId1, member1); + builder.createStore(member1, operands[1]); + } else + // "exp" is integer type (from GLSL built-in function) + builder.createStore(builder.createCompositeExtract(id, frexpIntType, 1), operands[1]); + id = builder.createCompositeExtract(id, typeId0, 0); + } break; default: break; @@ -3990,8 +6335,8 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv:: return builder.setPrecision(id, precision); } -// Intrinsics with no arguments, no return value, and no precision. -spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op) +// Intrinsics with no arguments (or no return value, and no precision). +spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId) { // TODO: get the barrier operands correct @@ -4003,41 +6348,98 @@ spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op) builder.createNoResultOp(spv::OpEndPrimitive); return 0; case glslang::EOpBarrier: - builder.createControlBarrier(spv::ScopeDevice, spv::ScopeDevice, spv::MemorySemanticsMaskNone); + if (glslangIntermediate->getStage() == EShLangTessControl) { + builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeInvocation, spv::MemorySemanticsMaskNone); + // TODO: prefer the following, when available: + // builder.createControlBarrier(spv::ScopePatch, spv::ScopePatch, + // spv::MemorySemanticsPatchMask | + // spv::MemorySemanticsAcquireReleaseMask); + } else { + builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeWorkgroup, + spv::MemorySemanticsWorkgroupMemoryMask | + spv::MemorySemanticsAcquireReleaseMask); + } return 0; case glslang::EOpMemoryBarrier: - builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsAllMemory); + builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsAllMemory | + spv::MemorySemanticsAcquireReleaseMask); return 0; case glslang::EOpMemoryBarrierAtomicCounter: - builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsAtomicCounterMemoryMask); + builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsAtomicCounterMemoryMask | + spv::MemorySemanticsAcquireReleaseMask); return 0; case glslang::EOpMemoryBarrierBuffer: - builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsUniformMemoryMask); + builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsUniformMemoryMask | + spv::MemorySemanticsAcquireReleaseMask); return 0; case glslang::EOpMemoryBarrierImage: - builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsImageMemoryMask); + builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsImageMemoryMask | + spv::MemorySemanticsAcquireReleaseMask); return 0; case glslang::EOpMemoryBarrierShared: - builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsWorkgroupMemoryMask); + builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsWorkgroupMemoryMask | + spv::MemorySemanticsAcquireReleaseMask); return 0; case glslang::EOpGroupMemoryBarrier: - builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsCrossWorkgroupMemoryMask); + builder.createMemoryBarrier(spv::ScopeWorkgroup, spv::MemorySemanticsAllMemory | + spv::MemorySemanticsAcquireReleaseMask); return 0; case glslang::EOpAllMemoryBarrierWithGroupSync: - // Control barrier with non-"None" semantic is also a memory barrier. - builder.createControlBarrier(spv::ScopeDevice, spv::ScopeDevice, spv::MemorySemanticsAllMemory); + builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeDevice, + spv::MemorySemanticsAllMemory | + spv::MemorySemanticsAcquireReleaseMask); return 0; - case glslang::EOpGroupMemoryBarrierWithGroupSync: - // Control barrier with non-"None" semantic is also a memory barrier. - builder.createControlBarrier(spv::ScopeDevice, spv::ScopeDevice, spv::MemorySemanticsCrossWorkgroupMemoryMask); + case glslang::EOpDeviceMemoryBarrier: + builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsUniformMemoryMask | + spv::MemorySemanticsImageMemoryMask | + spv::MemorySemanticsAcquireReleaseMask); + return 0; + case glslang::EOpDeviceMemoryBarrierWithGroupSync: + builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeDevice, spv::MemorySemanticsUniformMemoryMask | + spv::MemorySemanticsImageMemoryMask | + spv::MemorySemanticsAcquireReleaseMask); return 0; case glslang::EOpWorkgroupMemoryBarrier: - builder.createMemoryBarrier(spv::ScopeWorkgroup, spv::MemorySemanticsWorkgroupMemoryMask); + builder.createMemoryBarrier(spv::ScopeWorkgroup, spv::MemorySemanticsWorkgroupMemoryMask | + spv::MemorySemanticsAcquireReleaseMask); return 0; case glslang::EOpWorkgroupMemoryBarrierWithGroupSync: - // Control barrier with non-"None" semantic is also a memory barrier. - builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeWorkgroup, spv::MemorySemanticsWorkgroupMemoryMask); + builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeWorkgroup, + spv::MemorySemanticsWorkgroupMemoryMask | + spv::MemorySemanticsAcquireReleaseMask); return 0; + case glslang::EOpSubgroupBarrier: + builder.createControlBarrier(spv::ScopeSubgroup, spv::ScopeSubgroup, spv::MemorySemanticsAllMemory | + spv::MemorySemanticsAcquireReleaseMask); + return spv::NoResult; + case glslang::EOpSubgroupMemoryBarrier: + builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsAllMemory | + spv::MemorySemanticsAcquireReleaseMask); + return spv::NoResult; + case glslang::EOpSubgroupMemoryBarrierBuffer: + builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsUniformMemoryMask | + spv::MemorySemanticsAcquireReleaseMask); + return spv::NoResult; + case glslang::EOpSubgroupMemoryBarrierImage: + builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsImageMemoryMask | + spv::MemorySemanticsAcquireReleaseMask); + return spv::NoResult; + case glslang::EOpSubgroupMemoryBarrierShared: + builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsWorkgroupMemoryMask | + spv::MemorySemanticsAcquireReleaseMask); + return spv::NoResult; + case glslang::EOpSubgroupElect: { + std::vector operands; + return createSubgroupOperation(op, typeId, operands, glslang::EbtVoid); + } +#ifdef AMD_EXTENSIONS + case glslang::EOpTime: + { + std::vector args; // Dummy arguments + spv::Id id = builder.createBuiltinCall(typeId, getExtBuiltins(spv::E_SPV_AMD_gcn_shader), spv::TimeAMD, args); + return builder.setPrecision(id, precision); + } +#endif default: logger->missingFunctionality("unknown operation with no arguments"); return 0; @@ -4058,24 +6460,15 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol symbolValues[symbol->getId()] = id; if (symbol->getBasicType() != glslang::EbtBlock) { - addDecoration(id, TranslatePrecisionDecoration(symbol->getType())); - addDecoration(id, TranslateInterpolationDecoration(symbol->getType().getQualifier())); - addDecoration(id, TranslateAuxiliaryStorageDecoration(symbol->getType().getQualifier())); + builder.addDecoration(id, TranslatePrecisionDecoration(symbol->getType())); + builder.addDecoration(id, TranslateInterpolationDecoration(symbol->getType().getQualifier())); + builder.addDecoration(id, TranslateAuxiliaryStorageDecoration(symbol->getType().getQualifier())); if (symbol->getType().getQualifier().hasSpecConstantId()) - addDecoration(id, spv::DecorationSpecId, symbol->getType().getQualifier().layoutSpecConstantId); + builder.addDecoration(id, spv::DecorationSpecId, symbol->getType().getQualifier().layoutSpecConstantId); if (symbol->getQualifier().hasIndex()) builder.addDecoration(id, spv::DecorationIndex, symbol->getQualifier().layoutIndex); if (symbol->getQualifier().hasComponent()) builder.addDecoration(id, spv::DecorationComponent, symbol->getQualifier().layoutComponent); - if (glslangIntermediate->getXfbMode()) { - builder.addCapability(spv::CapabilityTransformFeedback); - if (symbol->getQualifier().hasXfbStride()) - builder.addDecoration(id, spv::DecorationXfbStride, symbol->getQualifier().layoutXfbStride); - if (symbol->getQualifier().hasXfbBuffer()) - builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer); - if (symbol->getQualifier().hasXfbOffset()) - builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutXfbOffset); - } // atomic counters use this: if (symbol->getQualifier().hasOffset()) builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutOffset); @@ -4083,7 +6476,7 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol if (symbol->getQualifier().hasLocation()) builder.addDecoration(id, spv::DecorationLocation, symbol->getQualifier().layoutLocation); - addDecoration(id, TranslateInvariantDecoration(symbol->getType().getQualifier())); + builder.addDecoration(id, TranslateInvariantDecoration(symbol->getType().getQualifier())); if (symbol->getQualifier().hasStream() && glslangIntermediate->isMultiStream()) { builder.addCapability(spv::CapabilityGeometryStreams); builder.addDecoration(id, spv::DecorationStream, symbol->getQualifier().layoutStream); @@ -4102,53 +6495,75 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol builder.addCapability(spv::CapabilityTransformFeedback); if (symbol->getQualifier().hasXfbStride()) builder.addDecoration(id, spv::DecorationXfbStride, symbol->getQualifier().layoutXfbStride); - if (symbol->getQualifier().hasXfbBuffer()) + if (symbol->getQualifier().hasXfbBuffer()) { builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer); + unsigned stride = glslangIntermediate->getXfbStride(symbol->getQualifier().layoutXfbBuffer); + if (stride != glslang::TQualifier::layoutXfbStrideEnd) + builder.addDecoration(id, spv::DecorationXfbStride, stride); + } + if (symbol->getQualifier().hasXfbOffset()) + builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutXfbOffset); } if (symbol->getType().isImage()) { std::vector memory; TranslateMemoryDecoration(symbol->getType().getQualifier(), memory); for (unsigned int i = 0; i < memory.size(); ++i) - addDecoration(id, memory[i]); + builder.addDecoration(id, memory[i]); } // built-in variable decorations spv::BuiltIn builtIn = TranslateBuiltInDecoration(symbol->getQualifier().builtIn, false); if (builtIn != spv::BuiltInMax) - addDecoration(id, spv::DecorationBuiltIn, (int)builtIn); + builder.addDecoration(id, spv::DecorationBuiltIn, (int)builtIn); + + // nonuniform + builder.addDecoration(id, TranslateNonUniformDecoration(symbol->getType().getQualifier())); + +#ifdef NV_EXTENSIONS + if (builtIn == spv::BuiltInSampleMask) { + spv::Decoration decoration; + // GL_NV_sample_mask_override_coverage extension + if (glslangIntermediate->getLayoutOverrideCoverage()) + decoration = (spv::Decoration)spv::DecorationOverrideCoverageNV; + else + decoration = (spv::Decoration)spv::DecorationMax; + builder.addDecoration(id, decoration); + if (decoration != spv::DecorationMax) { + builder.addExtension(spv::E_SPV_NV_sample_mask_override_coverage); + } + } + else if (builtIn == spv::BuiltInLayer) { + // SPV_NV_viewport_array2 extension + if (symbol->getQualifier().layoutViewportRelative) { + builder.addDecoration(id, (spv::Decoration)spv::DecorationViewportRelativeNV); + builder.addCapability(spv::CapabilityShaderViewportMaskNV); + builder.addExtension(spv::E_SPV_NV_viewport_array2); + } + if (symbol->getQualifier().layoutSecondaryViewportRelativeOffset != -2048) { + builder.addDecoration(id, (spv::Decoration)spv::DecorationSecondaryViewportRelativeNV, + symbol->getQualifier().layoutSecondaryViewportRelativeOffset); + builder.addCapability(spv::CapabilityShaderStereoViewNV); + builder.addExtension(spv::E_SPV_NV_stereo_view_rendering); + } + } + + if (symbol->getQualifier().layoutPassthrough) { + builder.addDecoration(id, spv::DecorationPassthroughNV); + builder.addCapability(spv::CapabilityGeometryShaderPassthroughNV); + builder.addExtension(spv::E_SPV_NV_geometry_shader_passthrough); + } +#endif + + if (glslangIntermediate->getHlslFunctionality1() && symbol->getType().getQualifier().semanticName != nullptr) { + builder.addExtension("SPV_GOOGLE_hlsl_functionality1"); + builder.addDecoration(id, (spv::Decoration)spv::DecorationHlslSemanticGOOGLE, + symbol->getType().getQualifier().semanticName); + } return id; } -// If 'dec' is valid, add no-operand decoration to an object -void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec) -{ - if (dec != spv::DecorationMax) - builder.addDecoration(id, dec); -} - -// If 'dec' is valid, add a one-operand decoration to an object -void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec, unsigned value) -{ - if (dec != spv::DecorationMax) - builder.addDecoration(id, dec, value); -} - -// If 'dec' is valid, add a no-operand decoration to a struct member -void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::Decoration dec) -{ - if (dec != spv::DecorationMax) - builder.addMemberDecoration(id, (unsigned)member, dec); -} - -// If 'dec' is valid, add a one-operand decoration to a struct member -void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::Decoration dec, unsigned value) -{ - if (dec != spv::DecorationMax) - builder.addMemberDecoration(id, (unsigned)member, dec, value); -} - // Make a full tree of instructions to build a SPIR-V specialization constant, // or regular constant if possible. // @@ -4181,8 +6596,10 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TIntermTyped& n for (int dim = 0; dim < 3; ++dim) { bool specConst = (glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet); dimConstId.push_back(builder.makeUintConstant(glslangIntermediate->getLocalSize(dim), specConst)); - if (specConst) - addDecoration(dimConstId.back(), spv::DecorationSpecId, glslangIntermediate->getLocalSizeSpecId(dim)); + if (specConst) { + builder.addDecoration(dimConstId.back(), spv::DecorationSpecId, + glslangIntermediate->getLocalSizeSpecId(dim)); + } } return builder.makeCompositeConstant(builder.makeVectorType(builder.makeUintType(32), 3), dimConstId, true); } @@ -4198,7 +6615,9 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TIntermTyped& n return accessChainLoad(sub_tree->getType()); } else if (auto* const_union_array = &sn->getConstArray()){ int nextConst = 0; - return createSpvConstantFromConstUnionArray(sn->getType(), *const_union_array, nextConst, true); + spv::Id id = createSpvConstantFromConstUnionArray(sn->getType(), *const_union_array, nextConst, true); + builder.addName(id, sn->getName().c_str()); + return id; } } @@ -4239,6 +6658,18 @@ spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glsla for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) { bool zero = nextConst >= consts.size(); switch (glslangType.getBasicType()) { + case glslang::EbtInt8: + spvConsts.push_back(builder.makeInt8Constant(zero ? 0 : consts[nextConst].getI8Const())); + break; + case glslang::EbtUint8: + spvConsts.push_back(builder.makeUint8Constant(zero ? 0 : consts[nextConst].getU8Const())); + break; + case glslang::EbtInt16: + spvConsts.push_back(builder.makeInt16Constant(zero ? 0 : consts[nextConst].getI16Const())); + break; + case glslang::EbtUint16: + spvConsts.push_back(builder.makeUint16Constant(zero ? 0 : consts[nextConst].getU16Const())); + break; case glslang::EbtInt: spvConsts.push_back(builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst())); break; @@ -4257,6 +6688,9 @@ spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glsla case glslang::EbtDouble: spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst())); break; + case glslang::EbtFloat16: + spvConsts.push_back(builder.makeFloat16Constant(zero ? 0.0F : (float)consts[nextConst].getDConst())); + break; case glslang::EbtBool: spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst())); break; @@ -4271,6 +6705,18 @@ spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glsla bool zero = nextConst >= consts.size(); spv::Id scalar = 0; switch (glslangType.getBasicType()) { + case glslang::EbtInt8: + scalar = builder.makeInt8Constant(zero ? 0 : consts[nextConst].getI8Const(), specConstant); + break; + case glslang::EbtUint8: + scalar = builder.makeUint8Constant(zero ? 0 : consts[nextConst].getU8Const(), specConstant); + break; + case glslang::EbtInt16: + scalar = builder.makeInt16Constant(zero ? 0 : consts[nextConst].getI16Const(), specConstant); + break; + case glslang::EbtUint16: + scalar = builder.makeUint16Constant(zero ? 0 : consts[nextConst].getU16Const(), specConstant); + break; case glslang::EbtInt: scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst(), specConstant); break; @@ -4289,6 +6735,9 @@ spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glsla case glslang::EbtDouble: scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst(), specConstant); break; + case glslang::EbtFloat16: + scalar = builder.makeFloat16Constant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant); + break; case glslang::EbtBool: scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst(), specConstant); break; @@ -4335,13 +6784,18 @@ bool TGlslangToSpvTraverser::isTrivialLeaf(const glslang::TIntermTyped* node) } // A node is trivial if it is a single operation with no side effects. -// Error on the side of saying non-trivial. +// HLSL (and/or vectors) are always trivial, as it does not short circuit. +// Otherwise, error on the side of saying non-trivial. // Return true if trivial. bool TGlslangToSpvTraverser::isTrivial(const glslang::TIntermTyped* node) { if (node == nullptr) return false; + // count non scalars as trivial, as well as anything coming from HLSL + if (! node->getType().isScalarOrVec1() || glslangIntermediate->getSource() == glslang::EShSourceHlsl) + return true; + // symbols and constants are trivial if (isTrivialLeaf(node)) return true; @@ -4412,7 +6866,7 @@ spv::Id TGlslangToSpvTraverser::createShortCircuit(glslang::TOperator op, glslan leftId = builder.createUnaryOp(spv::OpLogicalNot, boolTypeId, leftId); // make an "if" based on the left value - spv::Builder::If ifBuilder(leftId, builder); + spv::Builder::If ifBuilder(leftId, spv::SelectionControlMaskNone, builder); // emit right operand as the "then" part of the "if" builder.clearAccessChain(); @@ -4430,6 +6884,22 @@ spv::Id TGlslangToSpvTraverser::createShortCircuit(glslang::TOperator op, glslan return builder.createOp(spv::OpPhi, boolTypeId, phiOperands); } +#ifdef AMD_EXTENSIONS +// Return type Id of the imported set of extended instructions corresponds to the name. +// Import this set if it has not been imported yet. +spv::Id TGlslangToSpvTraverser::getExtBuiltins(const char* name) +{ + if (extBuiltinMap.find(name) != extBuiltinMap.end()) + return extBuiltinMap[name]; + else { + builder.addExtension(name); + spv::Id extBuiltins = builder.import(name); + extBuiltinMap[name] = extBuiltins; + return extBuiltins; + } +} +#endif + }; // end anonymous namespace namespace glslang { @@ -4442,11 +6912,27 @@ void GetSpirvVersion(std::string& version) version = buf; } +// For low-order part of the generator's magic number. Bump up +// when there is a change in the style (e.g., if SSA form changes, +// or a different instruction sequence to do something gets used). +int GetSpirvGeneratorVersion() +{ + // return 1; // start + // return 2; // EOpAtomicCounterDecrement gets a post decrement, to map between GLSL -> SPIR-V + // return 3; // change/correct barrier-instruction operands, to match memory model group decisions + // return 4; // some deeper access chains: for dynamic vector component, and local Boolean component + // return 5; // make OpArrayLength result type be an int with signedness of 0 + return 6; // revert version 5 change, which makes a different (new) kind of incorrect code, + // versions 4 and 6 each generate OpArrayLength as it has long been done +} + // Write SPIR-V out to a binary file void OutputSpvBin(const std::vector& spirv, const char* baseName) { std::ofstream out; out.open(baseName, std::ios::binary | std::ios::out); + if (out.fail()) + printf("ERROR: Failed to open file: %s\n", baseName); for (int i = 0; i < (int)spirv.size(); ++i) { unsigned int word = spirv[i]; out.write((const char*)&word, 4); @@ -4455,11 +6941,19 @@ void OutputSpvBin(const std::vector& spirv, const char* baseName) } // Write SPIR-V out to a text file with 32-bit hexadecimal words -void OutputSpvHex(const std::vector& spirv, const char* baseName) +void OutputSpvHex(const std::vector& spirv, const char* baseName, const char* varName) { std::ofstream out; out.open(baseName, std::ios::binary | std::ios::out); - out << "\t// " GLSLANG_REVISION " " GLSLANG_DATE << std::endl; + if (out.fail()) + printf("ERROR: Failed to open file: %s\n", baseName); + out << "\t// " << + glslang::GetSpirvGeneratorVersion() << "." << GLSLANG_MINOR_VERSION << "." << GLSLANG_PATCH_LEVEL << + std::endl; + if (varName != nullptr) { + out << "\t #pragma once" << std::endl; + out << "const uint32_t " << varName << "[] = {" << std::endl; + } const int WORDS_PER_LINE = 8; for (int i = 0; i < (int)spirv.size(); i += WORDS_PER_LINE) { out << "\t"; @@ -4472,33 +6966,90 @@ void OutputSpvHex(const std::vector& spirv, const char* baseName) } out << std::endl; } + if (varName != nullptr) { + out << "};"; + } out.close(); } // // Set up the glslang traversal // -void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector& spirv) +void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector& spirv, SpvOptions* options) { spv::SpvBuildLogger logger; - GlslangToSpv(intermediate, spirv, &logger); + GlslangToSpv(intermediate, spirv, &logger, options); } -void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector& spirv, spv::SpvBuildLogger* logger) +void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector& spirv, + spv::SpvBuildLogger* logger, SpvOptions* options) { TIntermNode* root = intermediate.getTreeRoot(); if (root == 0) return; + glslang::SpvOptions defaultOptions; + if (options == nullptr) + options = &defaultOptions; + glslang::GetThreadPoolAllocator().push(); - TGlslangToSpvTraverser it(&intermediate, logger); - + TGlslangToSpvTraverser it(intermediate.getSpv().spv, &intermediate, logger, *options); root->traverse(&it); - + it.finishSpv(); it.dumpSpv(spirv); +#if ENABLE_OPT + // If from HLSL, run spirv-opt to "legalize" the SPIR-V for Vulkan + // eg. forward and remove memory writes of opaque types. + if ((intermediate.getSource() == EShSourceHlsl || + options->optimizeSize) && + !options->disableOptimizer) { + spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2; + + spvtools::Optimizer optimizer(target_env); + optimizer.SetMessageConsumer([](spv_message_level_t level, + const char* source, + const spv_position_t& position, + const char* message) { + std::cerr << StringifyMessage(level, source, position, message) + << std::endl; + }); + + optimizer.RegisterPass(CreateMergeReturnPass()); + optimizer.RegisterPass(CreateInlineExhaustivePass()); + optimizer.RegisterPass(CreateEliminateDeadFunctionsPass()); + optimizer.RegisterPass(CreateScalarReplacementPass()); + optimizer.RegisterPass(CreateLocalAccessChainConvertPass()); + optimizer.RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()); + optimizer.RegisterPass(CreateLocalSingleStoreElimPass()); + optimizer.RegisterPass(CreateSimplificationPass()); + optimizer.RegisterPass(CreateAggressiveDCEPass()); + optimizer.RegisterPass(CreateVectorDCEPass()); + optimizer.RegisterPass(CreateDeadInsertElimPass()); + optimizer.RegisterPass(CreateAggressiveDCEPass()); + optimizer.RegisterPass(CreateDeadBranchElimPass()); + optimizer.RegisterPass(CreateBlockMergePass()); + optimizer.RegisterPass(CreateLocalMultiStoreElimPass()); + optimizer.RegisterPass(CreateIfConversionPass()); + optimizer.RegisterPass(CreateSimplificationPass()); + optimizer.RegisterPass(CreateAggressiveDCEPass()); + optimizer.RegisterPass(CreateVectorDCEPass()); + optimizer.RegisterPass(CreateDeadInsertElimPass()); + if (options->optimizeSize) { + optimizer.RegisterPass(CreateRedundancyEliminationPass()); + // TODO(greg-lunarg): Add this when AMD driver issues are resolved + // optimizer.RegisterPass(CreateCommonUniformElimPass()); + } + optimizer.RegisterPass(CreateAggressiveDCEPass()); + optimizer.RegisterPass(CreateCFGCleanupPass()); + + if (!optimizer.Run(spirv.data(), spirv.size(), &spirv)) + return; + } +#endif + glslang::GetThreadPoolAllocator().pop(); } diff --git a/Externals/glslang/SPIRV/GlslangToSpv.h b/Externals/glslang/SPIRV/GlslangToSpv.h index 97b280ca3a..f7f7cff620 100644 --- a/Externals/glslang/SPIRV/GlslangToSpv.h +++ b/Externals/glslang/SPIRV/GlslangToSpv.h @@ -1,11 +1,11 @@ // -//Copyright (C) 2014 LunarG, Inc. +// Copyright (C) 2014 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,18 +19,24 @@ // 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. +// 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 + +#if defined(_MSC_VER) && _MSC_VER >= 1900 + #pragma warning(disable : 4464) // relative include path contains '..' +#endif #include "../glslang/Include/intermediate.h" @@ -41,10 +47,21 @@ namespace glslang { +struct SpvOptions { + SpvOptions() : generateDebugInfo(false), disableOptimizer(true), + optimizeSize(false) { } + bool generateDebugInfo; + bool disableOptimizer; + bool optimizeSize; +}; + void GetSpirvVersion(std::string&); -void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector& spirv); -void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector& spirv, spv::SpvBuildLogger* logger); +int GetSpirvGeneratorVersion(); +void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector& spirv, + SpvOptions* options = nullptr); +void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector& spirv, + spv::SpvBuildLogger* logger, SpvOptions* options = nullptr); void OutputSpvBin(const std::vector& spirv, const char* baseName); -void OutputSpvHex(const std::vector& spirv, const char* baseName); +void OutputSpvHex(const std::vector& spirv, const char* baseName, const char* varName); } diff --git a/Externals/glslang/SPIRV/InReadableOrder.cpp b/Externals/glslang/SPIRV/InReadableOrder.cpp index 86aae6d057..52b29613a4 100644 --- a/Externals/glslang/SPIRV/InReadableOrder.cpp +++ b/Externals/glslang/SPIRV/InReadableOrder.cpp @@ -1,11 +1,11 @@ // -//Copyright (C) 2016 Google, Inc. +// Copyright (C) 2016 Google, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,18 +19,18 @@ // 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. +// 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. // The SPIR-V spec requires code blocks to appear in an order satisfying the // dominator-tree direction (ie, dominator before the dominated). This is, @@ -51,7 +51,7 @@ #include "spvIR.h" #include -#include +#include using spv::Block; using spv::Id; @@ -69,33 +69,33 @@ public: void visit(Block* block) { assert(block); - if (visited_[block] || delayed_[block]) + if (visited_.count(block) || delayed_.count(block)) return; callback_(block); - visited_[block] = true; + visited_.insert(block); Block* mergeBlock = nullptr; Block* continueBlock = nullptr; auto mergeInst = block->getMergeInstruction(); if (mergeInst) { Id mergeId = mergeInst->getIdOperand(0); mergeBlock = block->getParent().getParent().getInstruction(mergeId)->getBlock(); - delayed_[mergeBlock] = true; + delayed_.insert(mergeBlock); if (mergeInst->getOpCode() == spv::OpLoopMerge) { Id continueId = mergeInst->getIdOperand(1); continueBlock = block->getParent().getParent().getInstruction(continueId)->getBlock(); - delayed_[continueBlock] = true; + delayed_.insert(continueBlock); } } const auto successors = block->getSuccessors(); for (auto it = successors.cbegin(); it != successors.cend(); ++it) visit(*it); if (continueBlock) { - delayed_[continueBlock] = false; + delayed_.erase(continueBlock); visit(continueBlock); } if (mergeBlock) { - delayed_[mergeBlock] = false; + delayed_.erase(mergeBlock); visit(mergeBlock); } } @@ -103,7 +103,7 @@ public: private: std::function callback_; // Whether a block has already been visited or is being delayed. - std::unordered_map visited_, delayed_; + std::unordered_set visited_, delayed_; }; } diff --git a/Externals/glslang/SPIRV/SPVRemapper.cpp b/Externals/glslang/SPIRV/SPVRemapper.cpp index 1bbd58924f..4bac145305 100755 --- a/Externals/glslang/SPIRV/SPVRemapper.cpp +++ b/Externals/glslang/SPIRV/SPVRemapper.cpp @@ -1,11 +1,11 @@ // -//Copyright (C) 2015 LunarG, Inc. +// Copyright (C) 2015 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,18 +19,18 @@ // 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. +// 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. // #include "SPVRemapper.h" @@ -103,10 +103,10 @@ namespace spv { switch (opCode) { case spv::OpTypeVector: // fall through - case spv::OpTypeMatrix: // ... - case spv::OpTypeSampler: // ... - case spv::OpTypeArray: // ... - case spv::OpTypeRuntimeArray: // ... + case spv::OpTypeMatrix: // ... + case spv::OpTypeSampler: // ... + case spv::OpTypeArray: // ... + case spv::OpTypeRuntimeArray: // ... case spv::OpTypePipe: return range_t(2, 3); case spv::OpTypeStruct: // fall through case spv::OpTypeFunction: return range_t(2, maxCount); @@ -127,6 +127,38 @@ namespace spv { } } + // Return the size of a type in 32-bit words. This currently only + // handles ints and floats, and is only invoked by queries which must be + // integer types. If ever needed, it can be generalized. + unsigned spirvbin_t::typeSizeInWords(spv::Id id) const + { + const unsigned typeStart = idPos(id); + const spv::Op opCode = asOpCode(typeStart); + + if (errorLatch) + return 0; + + switch (opCode) { + case spv::OpTypeInt: // fall through... + case spv::OpTypeFloat: return (spv[typeStart+2]+31)/32; + default: + return 0; + } + } + + // Looks up the type of a given const or variable ID, and + // returns its size in 32-bit words. + unsigned spirvbin_t::idTypeSizeInWords(spv::Id id) const + { + const auto tid_it = idTypeSizeMap.find(id); + if (tid_it == idTypeSizeMap.end()) { + error("type size for ID not found"); + return 0; + } + + return tid_it->second; + } + // Is this an opcode we should remove when using --strip? bool spirvbin_t::isStripOp(spv::Op opCode) const { @@ -140,6 +172,7 @@ namespace spv { } } + // Return true if this opcode is flow control bool spirvbin_t::isFlowCtrl(spv::Op opCode) const { switch (opCode) { @@ -155,6 +188,7 @@ namespace spv { } } + // Return true if this opcode defines a type bool spirvbin_t::isTypeOp(spv::Op opCode) const { switch (opCode) { @@ -182,17 +216,23 @@ namespace spv { } } + // Return true if this opcode defines a constant bool spirvbin_t::isConstOp(spv::Op opCode) const { switch (opCode) { - case spv::OpConstantNull: error("unimplemented constant type"); - case spv::OpConstantSampler: error("unimplemented constant type"); + case spv::OpConstantNull: + case spv::OpConstantSampler: + error("unimplemented constant type"); + return true; case spv::OpConstantTrue: case spv::OpConstantFalse: case spv::OpConstantComposite: - case spv::OpConstant: return true; - default: return false; + case spv::OpConstant: + return true; + + default: + return false; } } @@ -216,21 +256,33 @@ namespace spv { spv::Id spirvbin_t::localId(spv::Id id, spv::Id newId) { - assert(id != spv::NoResult && newId != spv::NoResult); + //assert(id != spv::NoResult && newId != spv::NoResult); + + if (id > bound()) { + error(std::string("ID out of range: ") + std::to_string(id)); + return spirvbin_t::unused; + } if (id >= idMapL.size()) idMapL.resize(id+1, unused); if (newId != unmapped && newId != unused) { - if (isOldIdUnused(id)) + if (isOldIdUnused(id)) { error(std::string("ID unused in module: ") + std::to_string(id)); + return spirvbin_t::unused; + } - if (!isOldIdUnmapped(id)) + if (!isOldIdUnmapped(id)) { error(std::string("ID already mapped: ") + std::to_string(id) + " -> " - + std::to_string(localId(id))); + + std::to_string(localId(id))); - if (isNewIdMapped(newId)) + return spirvbin_t::unused; + } + + if (isNewIdMapped(newId)) { error(std::string("ID already used in module: ") + std::to_string(newId)); + return spirvbin_t::unused; + } msg(4, 4, std::string("map: ") + std::to_string(id) + " -> " + std::to_string(newId)); setMapped(newId); @@ -256,7 +308,6 @@ namespace spv { return literal; } - void spirvbin_t::applyMap() { msg(3, 2, std::string("Applying map: ")); @@ -265,12 +316,15 @@ namespace spv { process(inst_fn_nop, // ignore instructions [this](spv::Id& id) { id = localId(id); + + if (errorLatch) + return; + assert(id != unused && id != unmapped); } ); } - // Find free IDs for anything we haven't mapped void spirvbin_t::mapRemainder() { @@ -284,25 +338,31 @@ namespace spv { continue; // Find a new mapping for any used but unmapped IDs - if (isOldIdUnmapped(id)) + if (isOldIdUnmapped(id)) { localId(id, unusedId = nextUnusedId(unusedId)); + if (errorLatch) + return; + } - if (isOldIdUnmapped(id)) + if (isOldIdUnmapped(id)) { error(std::string("old ID not mapped: ") + std::to_string(id)); + return; + } // Track max bound maxBound = std::max(maxBound, localId(id) + 1); + + if (errorLatch) + return; } bound(maxBound); // reset header ID bound to as big as it now needs to be } + // Mark debug instructions for stripping void spirvbin_t::stripDebug() { - if ((options & STRIP) == 0) - return; - - // build local Id and name maps + // Strip instructions in the stripOp set: debug info. process( [&](spv::Op opCode, unsigned start) { // remember opcodes we want to strip later @@ -313,6 +373,32 @@ namespace spv { op_fn_nop); } + // Mark instructions that refer to now-removed IDs for stripping + void spirvbin_t::stripDeadRefs() + { + process( + [&](spv::Op opCode, unsigned start) { + // strip opcodes pointing to removed data + switch (opCode) { + case spv::OpName: + case spv::OpMemberName: + case spv::OpDecorate: + case spv::OpMemberDecorate: + if (idPosR.find(asId(start+1)) == idPosR.end()) + stripInst(start); + break; + default: + break; // leave it alone + } + + return true; + }, + op_fn_nop); + + strip(); + } + + // Update local maps of ID, type, etc positions void spirvbin_t::buildLocalMaps() { msg(2, 2, std::string("build local maps: ")); @@ -321,10 +407,9 @@ namespace spv { idMapL.clear(); // preserve nameMap, so we don't clear that. fnPos.clear(); - fnPosDCE.clear(); fnCalls.clear(); typeConstPos.clear(); - typeConstPosR.clear(); + idPosR.clear(); entryPoint = spv::NoResult; largestNewId = 0; @@ -336,9 +421,27 @@ namespace spv { // build local Id and name maps process( [&](spv::Op opCode, unsigned start) { - // remember opcodes we want to strip later - if ((options & STRIP) && isStripOp(opCode)) - stripInst(start); + unsigned word = start+1; + spv::Id typeId = spv::NoResult; + + if (spv::InstructionDesc[opCode].hasType()) + typeId = asId(word++); + + // If there's a result ID, remember the size of its type + if (spv::InstructionDesc[opCode].hasResult()) { + const spv::Id resultId = asId(word++); + idPosR[resultId] = start; + + if (typeId != spv::NoResult) { + const unsigned idTypeSize = typeSizeInWords(typeId); + + if (errorLatch) + return false; + + if (idTypeSize != 0) + idTypeSizeMap[resultId] = idTypeSize; + } + } if (opCode == spv::Op::OpName) { const spv::Id target = asId(start+1); @@ -350,24 +453,31 @@ namespace spv { } else if (opCode == spv::Op::OpEntryPoint) { entryPoint = asId(start + 2); } else if (opCode == spv::Op::OpFunction) { - if (fnStart != 0) + if (fnStart != 0) { error("nested function found"); + return false; + } + fnStart = start; fnRes = asId(start + 2); } else if (opCode == spv::Op::OpFunctionEnd) { assert(fnRes != spv::NoResult); - if (fnStart == 0) + if (fnStart == 0) { error("function end without function start"); + return false; + } + fnPos[fnRes] = range_t(fnStart, start + asWordCount(start)); fnStart = 0; } else if (isConstOp(opCode)) { + if (errorLatch) + return false; + assert(asId(start + 2) != spv::NoResult); typeConstPos.insert(start); - typeConstPosR[asId(start + 2)] = start; } else if (isTypeOp(opCode)) { assert(asId(start + 1) != spv::NoResult); typeConstPos.insert(start); - typeConstPosR[asId(start + 1)] = start; } return false; @@ -382,30 +492,37 @@ namespace spv { { msg(2, 2, std::string("validating: ")); - if (spv.size() < header_size) + if (spv.size() < header_size) { error("file too short: "); + return; + } - if (magic() != spv::MagicNumber) + if (magic() != spv::MagicNumber) { error("bad magic number"); + return; + } // field 1 = version // field 2 = generator magic // field 3 = result bound - if (schemaNum() != 0) + if (schemaNum() != 0) { error("bad schema, must be 0"); + return; + } } - int spirvbin_t::processInstruction(unsigned word, instfn_t instFn, idfn_t idFn) { const auto instructionStart = word; const unsigned wordCount = asWordCount(instructionStart); - const spv::Op opCode = asOpCode(instructionStart); const int nextInst = word++ + wordCount; + spv::Op opCode = asOpCode(instructionStart); - if (nextInst > int(spv.size())) + if (nextInst > int(spv.size())) { error("spir instruction terminated too early"); + return -1; + } // Base for computing number of operands; will be updated as more is learned unsigned numOperands = wordCount - 1; @@ -436,10 +553,31 @@ namespace spv { return nextInst; } + // Circular buffer so we can look back at previous unmapped values during the mapping pass. + static const unsigned idBufferSize = 4; + spv::Id idBuffer[idBufferSize]; + unsigned idBufferPos = 0; + // Store IDs from instruction in our map for (int op = 0; numOperands > 0; ++op, --numOperands) { + // SpecConstantOp is special: it includes the operands of another opcode which is + // given as a literal in the 3rd word. We will switch over to pretending that the + // opcode being processed is the literal opcode value of the SpecConstantOp. See the + // SPIRV spec for details. This way we will handle IDs and literals as appropriate for + // the embedded op. + if (opCode == spv::OpSpecConstantOp) { + if (op == 0) { + opCode = asOpCode(word++); // this is the opcode embedded in the SpecConstantOp. + --numOperands; + } + } + switch (spv::InstructionDesc[opCode].operands.getClass(op)) { case spv::OperandId: + case spv::OperandScope: + case spv::OperandMemorySemantics: + idBuffer[idBufferPos] = asId(word); + idBufferPos = (idBufferPos + 1) % idBufferSize; idFn(asId(word++)); break; @@ -457,13 +595,28 @@ namespace spv { // word += numOperands; return nextInst; - case spv::OperandVariableLiteralId: - while (numOperands > 0) { - ++word; // immediate - idFn(asId(word++)); // ID - numOperands -= 2; + case spv::OperandVariableLiteralId: { + if (opCode == OpSwitch) { + // word-2 is the position of the selector ID. OpSwitch Literals match its type. + // In case the IDs are currently being remapped, we get the word[-2] ID from + // the circular idBuffer. + const unsigned literalSizePos = (idBufferPos+idBufferSize-2) % idBufferSize; + const unsigned literalSize = idTypeSizeInWords(idBuffer[literalSizePos]); + const unsigned numLiteralIdPairs = (nextInst-word) / (1+literalSize); + + if (errorLatch) + return -1; + + for (unsigned arg=0; arg 0) { fnLocalVars.erase(id); idMap.erase(id); @@ -825,6 +999,9 @@ namespace spv { } ); + if (errorLatch) + return; + process( [&](spv::Op opCode, unsigned start) { if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0) @@ -833,6 +1010,9 @@ namespace spv { }, op_fn_nop); + if (errorLatch) + return; + // Chase replacements to their origins, in case there is a chain such as: // 2 = store 1 // 3 = load 2 @@ -866,6 +1046,9 @@ namespace spv { } ); + if (errorLatch) + return; + strip(); // strip out data we decided to eliminate } @@ -891,7 +1074,6 @@ namespace spv { if (call_it == fnCalls.end() || call_it->second == 0) { changed = true; stripRange.push_back(fn->second); - fnPosDCE.insert(*fn); // decrease counts of called functions process( @@ -910,6 +1092,9 @@ namespace spv { fn->second.first, fn->second.second); + if (errorLatch) + return; + fn = fnPos.erase(fn); } else ++fn; } @@ -942,14 +1127,21 @@ namespace spv { [&](spv::Id& id) { if (varUseCount[id]) ++varUseCount[id]; } ); + if (errorLatch) + return; + // Remove single-use function variables + associated decorations and names process( [&](spv::Op opCode, unsigned start) { - if ((opCode == spv::OpVariable && varUseCount[asId(start+2)] == 1) || - (opCode == spv::OpDecorate && varUseCount[asId(start+1)] == 1) || - (opCode == spv::OpName && varUseCount[asId(start+1)] == 1)) { - stripInst(start); - } + spv::Id id = spv::NoResult; + if (opCode == spv::OpVariable) + id = asId(start+2); + if (opCode == spv::OpDecorate || opCode == spv::OpName) + id = asId(start+1); + + if (id != spv::NoResult && varUseCount[id] == 1) + stripInst(start); + return true; }, op_fn_nop); @@ -966,28 +1158,37 @@ namespace spv { std::unordered_map typeUseCount; - // Count total type usage - process(inst_fn_nop, - [&](spv::Id& id) { if (isType[id]) ++typeUseCount[id]; } - ); + // This is not the most efficient algorithm, but this is an offline tool, and + // it's easy to write this way. Can be improved opportunistically if needed. + bool changed = true; + while (changed) { + changed = false; + strip(); + typeUseCount.clear(); - // Remove types from deleted code - for (const auto& fn : fnPosDCE) + // Count total type usage process(inst_fn_nop, - [&](spv::Id& id) { if (isType[id]) --typeUseCount[id]; }, - fn.second.first, fn.second.second); + [&](spv::Id& id) { if (isType[id]) ++typeUseCount[id]; } + ); - // Remove single reference types - for (const auto typeStart : typeConstPos) { - const spv::Id typeId = asTypeConstId(typeStart); - if (typeUseCount[typeId] == 1) { - --typeUseCount[typeId]; - stripInst(typeStart); + if (errorLatch) + return; + + // Remove single reference types + for (const auto typeStart : typeConstPos) { + const spv::Id typeId = asTypeConstId(typeStart); + if (typeUseCount[typeId] == 1) { + changed = true; + --typeUseCount[typeId]; + stripInst(typeStart); + } } + + if (errorLatch) + return; } } - #ifdef NOTDEF bool spirvbin_t::matchType(const spirvbin_t::globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const { @@ -1047,7 +1248,6 @@ namespace spv { } } - // Look for an equivalent type in the globalTypes map spv::Id spirvbin_t::findType(const spirvbin_t::globaltypes_t& globalTypes, spv::Id lt) const { @@ -1060,12 +1260,14 @@ namespace spv { } #endif // NOTDEF - // Return start position in SPV of given type. error if not found. - unsigned spirvbin_t::typePos(spv::Id id) const + // Return start position in SPV of given Id. error if not found. + unsigned spirvbin_t::idPos(spv::Id id) const { - const auto tid_it = typeConstPosR.find(id); - if (tid_it == typeConstPosR.end()) - error("type ID not found"); + const auto tid_it = idPosR.find(id); + if (tid_it == idPosR.end()) { + error("ID not found"); + return 0; + } return tid_it->second; } @@ -1083,11 +1285,11 @@ namespace spv { case spv::OpTypeInt: return 3 + (spv[typeStart+3]); case spv::OpTypeFloat: return 5; case spv::OpTypeVector: - return 6 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1); + return 6 + hashType(idPos(spv[typeStart+2])) * (spv[typeStart+3] - 1); case spv::OpTypeMatrix: - return 30 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1); + return 30 + hashType(idPos(spv[typeStart+2])) * (spv[typeStart+3] - 1); case spv::OpTypeImage: - return 120 + hashType(typePos(spv[typeStart+2])) + + return 120 + hashType(idPos(spv[typeStart+2])) + spv[typeStart+3] + // dimensionality spv[typeStart+4] * 8 * 16 + // depth spv[typeStart+5] * 4 * 16 + // arrayed @@ -1098,24 +1300,24 @@ namespace spv { case spv::OpTypeSampledImage: return 502; case spv::OpTypeArray: - return 501 + hashType(typePos(spv[typeStart+2])) * spv[typeStart+3]; + return 501 + hashType(idPos(spv[typeStart+2])) * spv[typeStart+3]; case spv::OpTypeRuntimeArray: - return 5000 + hashType(typePos(spv[typeStart+2])); + return 5000 + hashType(idPos(spv[typeStart+2])); case spv::OpTypeStruct: { std::uint32_t hash = 10000; for (unsigned w=2; w < wordCount; ++w) - hash += w * hashType(typePos(spv[typeStart+w])); + hash += w * hashType(idPos(spv[typeStart+w])); return hash; } case spv::OpTypeOpaque: return 6000 + spv[typeStart+2]; - case spv::OpTypePointer: return 100000 + hashType(typePos(spv[typeStart+3])); + case spv::OpTypePointer: return 100000 + hashType(idPos(spv[typeStart+3])); case spv::OpTypeFunction: { std::uint32_t hash = 200000; for (unsigned w=2; w < wordCount; ++w) - hash += w * hashType(typePos(spv[typeStart+w])); + hash += w * hashType(idPos(spv[typeStart+w])); return hash; } @@ -1132,14 +1334,14 @@ namespace spv { case spv::OpConstantFalse: return 300008; case spv::OpConstantComposite: { - std::uint32_t hash = 300011 + hashType(typePos(spv[typeStart+1])); + std::uint32_t hash = 300011 + hashType(idPos(spv[typeStart+1])); for (unsigned w=3; w < wordCount; ++w) - hash += w * hashType(typePos(spv[typeStart+w])); + hash += w * hashType(idPos(spv[typeStart+w])); return hash; } case spv::OpConstant: { - std::uint32_t hash = 400011 + hashType(typePos(spv[typeStart+1])); + std::uint32_t hash = 400011 + hashType(idPos(spv[typeStart+1])); for (unsigned w=3; w < wordCount; ++w) hash += w * spv[typeStart+w]; return hash; @@ -1164,12 +1366,17 @@ namespace spv { const spv::Id resId = asTypeConstId(typeStart); const std::uint32_t hashval = hashType(typeStart); - if (isOldIdUnmapped(resId)) + if (errorLatch) + return; + + if (isOldIdUnmapped(resId)) { localId(resId, nextUnusedId(hashval % softTypeIdLimit + firstMappedID)); + if (errorLatch) + return; + } } } - // Strip a single binary by removing ranges given in stripRange void spirvbin_t::strip() { @@ -1185,7 +1392,7 @@ namespace spv { int strippedPos = 0; for (unsigned word = 0; word < unsigned(spv.size()); ++word) { - if (strip_it != stripRange.end() && word >= strip_it->second) + while (strip_it != stripRange.end() && word >= strip_it->second) ++strip_it; if (strip_it == stripRange.end() || word < strip_it->first || word >= strip_it->second) @@ -1206,25 +1413,56 @@ namespace spv { // Set up opcode tables from SpvDoc spv::Parameterize(); - validate(); // validate header - buildLocalMaps(); + validate(); // validate header + buildLocalMaps(); // build ID maps msg(3, 4, std::string("ID bound: ") + std::to_string(bound())); + if (options & STRIP) stripDebug(); + if (errorLatch) return; + strip(); // strip out data we decided to eliminate + if (errorLatch) return; if (options & OPT_LOADSTORE) optLoadStore(); - if (options & OPT_FWD_LS) forwardLoadStores(); - if (options & DCE_FUNCS) dceFuncs(); - if (options & DCE_VARS) dceVars(); - if (options & DCE_TYPES) dceTypes(); - if (options & MAP_TYPES) mapTypeConst(); - if (options & MAP_NAMES) mapNames(); - if (options & MAP_FUNCS) mapFnBodies(); + if (errorLatch) return; - mapRemainder(); // map any unmapped IDs - applyMap(); // Now remap each shader to the new IDs we've come up with - strip(); // strip out data we decided to eliminate + if (options & OPT_FWD_LS) forwardLoadStores(); + if (errorLatch) return; + + if (options & DCE_FUNCS) dceFuncs(); + if (errorLatch) return; + + if (options & DCE_VARS) dceVars(); + if (errorLatch) return; + + if (options & DCE_TYPES) dceTypes(); + if (errorLatch) return; + + strip(); // strip out data we decided to eliminate + if (errorLatch) return; + + stripDeadRefs(); // remove references to things we DCEed + if (errorLatch) return; + + // after the last strip, we must clean any debug info referring to now-deleted data + + if (options & MAP_TYPES) mapTypeConst(); + if (errorLatch) return; + + if (options & MAP_NAMES) mapNames(); + if (errorLatch) return; + + if (options & MAP_FUNCS) mapFnBodies(); + if (errorLatch) return; + + if (options & MAP_ALL) { + mapRemainder(); // map any unmapped IDs + if (errorLatch) return; + + applyMap(); // Now remap each shader to the new IDs we've come up with + if (errorLatch) return; + } } // remap from a memory image diff --git a/Externals/glslang/SPIRV/SPVRemapper.h b/Externals/glslang/SPIRV/SPVRemapper.h index e5e8e1bde1..97e3f31fa6 100755 --- a/Externals/glslang/SPIRV/SPVRemapper.h +++ b/Externals/glslang/SPIRV/SPVRemapper.h @@ -1,11 +1,11 @@ // -//Copyright (C) 2015 LunarG, Inc. +// Copyright (C) 2015 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,18 +19,18 @@ // 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. +// 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 @@ -38,7 +38,8 @@ #include #include -#include +#include +#include namespace spv { @@ -74,7 +75,8 @@ public: } // namespace SPV #if !defined (use_cpp11) -#include +#include +#include namespace spv { class spirvbin_t : public spirvbin_base_t @@ -82,7 +84,7 @@ class spirvbin_t : public spirvbin_base_t public: spirvbin_t(int /*verbose = 0*/) { } - void remap(std::vector& /*spv*/, unsigned int /*opts = 0*/) + void remap(std::vector& /*spv*/, unsigned int /*opts = 0*/) { printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n"); exit(5); @@ -110,8 +112,11 @@ namespace spv { class spirvbin_t : public spirvbin_base_t { public: - spirvbin_t(int verbose = 0) : entryPoint(spv::NoResult), largestNewId(0), verbose(verbose) { } - + 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& spv, std::uint32_t opts = DO_EVERYTHING); @@ -159,17 +164,22 @@ private: typedef std::set posmap_t; typedef std::unordered_map posmap_rev_t; - // handle error - void error(const std::string& txt) const { errorHandler(txt); } + // Maps and ID to the size of its base type, if known. + typedef std::unordered_map 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 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; - 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]); } @@ -177,10 +187,10 @@ private: 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 typePos(spv::Id id) const; + 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); } + 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 @@ -233,9 +243,10 @@ private: void applyMap(); // remap per local name map void mapRemainder(); // map any IDs we haven't touched yet - void stripDebug(); // strip debug info + void stripDebug(); // strip all debug info + void stripDeadRefs(); // strips debug info for now-dead references after DCE void strip(); // remove debug symbols - + std::vector spv; // SPIR words namemap_t nameMap; // ID names from OpName @@ -258,14 +269,14 @@ private: // Function start and end. use unordered_map because we'll have // many fewer functions than IDs. std::unordered_map fnPos; - std::unordered_map fnPosDCE; // deleted functions // Which functions are called, anywhere in the module, with a call count std::unordered_map fnCalls; - - posmap_t typeConstPos; // word positions that define types & consts (ordered) - posmap_rev_t typeConstPosR; // reverse map from IDs to positions - + + 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 idMapL; // ID {M}ap from {L}ocal to {G}lobal IDs spv::Id entryPoint; // module entry point @@ -278,6 +289,11 @@ private: 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; }; diff --git a/Externals/glslang/SPIRV/SpvBuilder.cpp b/Externals/glslang/SPIRV/SpvBuilder.cpp index e5317ab7ee..27ce71caa3 100644 --- a/Externals/glslang/SPIRV/SpvBuilder.cpp +++ b/Externals/glslang/SPIRV/SpvBuilder.cpp @@ -1,12 +1,12 @@ // -//Copyright (C) 2014-2015 LunarG, Inc. -//Copyright (C) 2015-2016 Google, Inc. +// Copyright (C) 2014-2015 LunarG, Inc. +// Copyright (C) 2015-2016 Google, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,47 +20,53 @@ // 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. +// 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. // // Helper for making SPIR-V IR. Generally, this is documented in the header // SpvBuilder.h. // -#include -#include +#include +#include #include #include #include "SpvBuilder.h" +#include "hex_float.h" + #ifndef _WIN32 #include #endif namespace spv { -Builder::Builder(unsigned int magicNumber, SpvBuildLogger* buildLogger) : +Builder::Builder(unsigned int spvVersion, unsigned int magicNumber, SpvBuildLogger* buildLogger) : + spvVersion(spvVersion), source(SourceLanguageUnknown), sourceVersion(0), + sourceFileStringId(NoResult), + currentLine(0), + emitOpLines(false), addressModel(AddressingModelLogical), memoryModel(MemoryModelGLSL450), builderNumber(magicNumber), buildPoint(0), uniqueId(0), - mainFunction(0), + entryPointFunction(0), generatingOpCodeForSpecConst(false), logger(buildLogger) { @@ -75,11 +81,31 @@ Id Builder::import(const char* name) { Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport); import->addStringOperand(name); - + imports.push_back(std::unique_ptr(import)); return import->getResultId(); } +// Emit an OpLine if we've been asked to emit OpLines and the line number +// has changed since the last time, and is a valid line number. +void Builder::setLine(int lineNum) +{ + if (lineNum != 0 && lineNum != currentLine) { + currentLine = lineNum; + if (emitOpLines) + addLine(sourceFileStringId, currentLine, 0); + } +} + +void Builder::addLine(Id fileName, int lineNum, int column) +{ + Instruction* line = new Instruction(OpLine); + line->addIdOperand(fileName); + line->addImmediateOperand(lineNum); + line->addImmediateOperand(column); + buildPoint->addInstruction(std::unique_ptr(line)); +} + // For creating new groupedTypes (will return old type if the requested one was already made). Id Builder::makeVoidType() { @@ -166,6 +192,9 @@ Id Builder::makeIntegerType(int width, bool hasSign) // deal with capabilities switch (width) { + case 8: + addCapability(CapabilityInt8); + break; case 16: addCapability(CapabilityInt16); break; @@ -242,7 +271,7 @@ Id Builder::makeStructResultType(Id type0, Id type1) type = groupedTypes[OpTypeStruct][t]; if (type->getNumOperands() != 2) continue; - if (type->getIdOperand(0) != type0 || + if (type->getIdOperand(0) != type0 || type->getIdOperand(1) != type1) continue; return type->getResultId(); @@ -375,6 +404,8 @@ Id Builder::makeFunctionType(Id returnType, const std::vector& paramTypes) Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format) { + assert(sampled == 1 || sampled == 2); + // try to find it Instruction* type; for (int t = 0; t < (int)groupedTypes[OpTypeImage].size(); ++t) { @@ -406,27 +437,27 @@ Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, boo // deal with capabilities switch (dim) { case DimBuffer: - if (sampled) + if (sampled == 1) addCapability(CapabilitySampledBuffer); else addCapability(CapabilityImageBuffer); break; case Dim1D: - if (sampled) + if (sampled == 1) addCapability(CapabilitySampled1D); else addCapability(CapabilityImage1D); break; case DimCube: if (arrayed) { - if (sampled) + if (sampled == 1) addCapability(CapabilitySampledCubeArray); else addCapability(CapabilityImageCubeArray); } break; case DimRect: - if (sampled) + if (sampled == 1) addCapability(CapabilitySampledRect); else addCapability(CapabilityImageRect); @@ -439,10 +470,14 @@ Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, boo } if (ms) { - if (arrayed) - addCapability(CapabilityImageMSArray); - if (! sampled) - addCapability(CapabilityStorageImageMultisample); + if (sampled == 2) { + // Images used with subpass data are not storage + // images, so don't require the capability for them. + if (dim != Dim::DimSubpassData) + addCapability(CapabilityStorageImageMultisample); + if (arrayed) + addCapability(CapabilityImageMSArray); + } } return type->getResultId(); @@ -588,7 +623,7 @@ Id Builder::getContainedTypeId(Id typeId) const // See if a scalar constant of this type has already been created, so it // can be reused rather than duplicated. (Required by the specification). -Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const +Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) { Instruction* constant; for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) { @@ -603,7 +638,7 @@ Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned valu } // Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double' or 'int64'). -Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) const +Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) { Instruction* constant; for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) { @@ -624,7 +659,7 @@ Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, bool Builder::isConstantOpCode(Op opcode) const { switch (opcode) { - case OpUndef: + case OpUndef: case OpConstantTrue: case OpConstantFalse: case OpConstant: @@ -785,7 +820,54 @@ Id Builder::makeDoubleConstant(double d, bool specConstant) return c->getResultId(); } -Id Builder::findCompositeConstant(Op typeClass, std::vector& comps) const +Id Builder::makeFloat16Constant(float f16, bool specConstant) +{ + Op opcode = specConstant ? OpSpecConstant : OpConstant; + Id typeId = makeFloatType(16); + + spvutils::HexFloat> fVal(f16); + spvutils::HexFloat> f16Val(0); + fVal.castTo(f16Val, spvutils::kRoundToZero); + + unsigned value = f16Val.value().getAsFloat().get_value(); + + // See if we already made it. Applies only to regular constants, because specialization constants + // must remain distinct for the purpose of applying a SpecId decoration. + if (!specConstant) { + Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value); + if (existing) + return existing; + } + + Instruction* c = new Instruction(getUniqueId(), typeId, opcode); + c->addImmediateOperand(value); + constantsTypesGlobals.push_back(std::unique_ptr(c)); + groupedConstants[OpTypeFloat].push_back(c); + module.mapInstruction(c); + + return c->getResultId(); +} + +Id Builder::makeFpConstant(Id type, double d, bool specConstant) +{ + assert(isFloatType(type)); + + switch (getScalarTypeWidth(type)) { + case 16: + return makeFloat16Constant((float)d, specConstant); + case 32: + return makeFloatConstant((float)d, specConstant); + case 64: + return makeDoubleConstant(d, specConstant); + default: + break; + } + + assert(false); + return NoResult; +} + +Id Builder::findCompositeConstant(Op typeClass, const std::vector& comps) { Instruction* constant = 0; bool found = false; @@ -813,8 +895,32 @@ Id Builder::findCompositeConstant(Op typeClass, std::vector& comps) const return found ? constant->getResultId() : NoResult; } +Id Builder::findStructConstant(Id typeId, const std::vector& comps) +{ + Instruction* constant = 0; + bool found = false; + for (int i = 0; i < (int)groupedStructConstants[typeId].size(); ++i) { + constant = groupedStructConstants[typeId][i]; + + // same contents? + bool mismatch = false; + for (int op = 0; op < constant->getNumOperands(); ++op) { + if (constant->getIdOperand(op) != comps[op]) { + mismatch = true; + break; + } + } + if (! mismatch) { + found = true; + break; + } + } + + return found ? constant->getResultId() : NoResult; +} + // Comments in header -Id Builder::makeCompositeConstant(Id typeId, std::vector& members, bool specConstant) +Id Builder::makeCompositeConstant(Id typeId, const std::vector& members, bool specConstant) { Op opcode = specConstant ? OpSpecConstantComposite : OpConstantComposite; assert(typeId); @@ -823,25 +929,33 @@ Id Builder::makeCompositeConstant(Id typeId, std::vector& members, bool spec switch (typeClass) { case OpTypeVector: case OpTypeArray: - case OpTypeStruct: case OpTypeMatrix: + if (! specConstant) { + Id existing = findCompositeConstant(typeClass, members); + if (existing) + return existing; + } + break; + case OpTypeStruct: + if (! specConstant) { + Id existing = findStructConstant(typeId, members); + if (existing) + return existing; + } break; default: assert(0); return makeFloatConstant(0.0); } - if (! specConstant) { - Id existing = findCompositeConstant(typeClass, members); - if (existing) - return existing; - } - Instruction* c = new Instruction(getUniqueId(), typeId, opcode); for (int op = 0; op < (int)members.size(); ++op) c->addIdOperand(members[op]); constantsTypesGlobals.push_back(std::unique_ptr(c)); - groupedConstants[typeClass].push_back(c); + if (typeClass == OpTypeStruct) + groupedStructConstants[typeId].push_back(c); + else + groupedConstants[typeClass].push_back(c); module.mapInstruction(c); return c->getResultId(); @@ -894,21 +1008,11 @@ void Builder::addMemberName(Id id, int memberNumber, const char* string) names.push_back(std::unique_ptr(name)); } -void Builder::addLine(Id target, Id fileName, int lineNum, int column) -{ - Instruction* line = new Instruction(OpLine); - line->addIdOperand(target); - line->addIdOperand(fileName); - line->addImmediateOperand(lineNum); - line->addImmediateOperand(column); - - lines.push_back(std::unique_ptr(line)); -} - void Builder::addDecoration(Id id, Decoration decoration, int num) { if (decoration == spv::DecorationMax) return; + Instruction* dec = new Instruction(OpDecorate); dec->addIdOperand(id); dec->addImmediateOperand(decoration); @@ -918,8 +1022,37 @@ void Builder::addDecoration(Id id, Decoration decoration, int num) decorations.push_back(std::unique_ptr(dec)); } +void Builder::addDecoration(Id id, Decoration decoration, const char* s) +{ + if (decoration == spv::DecorationMax) + return; + + Instruction* dec = new Instruction(OpDecorateStringGOOGLE); + dec->addIdOperand(id); + dec->addImmediateOperand(decoration); + dec->addStringOperand(s); + + decorations.push_back(std::unique_ptr(dec)); +} + +void Builder::addDecorationId(Id id, Decoration decoration, Id idDecoration) +{ + if (decoration == spv::DecorationMax) + return; + + Instruction* dec = new Instruction(OpDecorateId); + dec->addIdOperand(id); + dec->addImmediateOperand(decoration); + dec->addIdOperand(idDecoration); + + decorations.push_back(std::unique_ptr(dec)); +} + void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num) { + if (decoration == spv::DecorationMax) + return; + Instruction* dec = new Instruction(OpMemberDecorate); dec->addIdOperand(id); dec->addImmediateOperand(member); @@ -930,23 +1063,37 @@ void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decorat decorations.push_back(std::unique_ptr(dec)); } -// Comments in header -Function* Builder::makeEntrypoint(const char* entryPoint) +void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const char *s) { - assert(! mainFunction); + if (decoration == spv::DecorationMax) + return; + + Instruction* dec = new Instruction(OpMemberDecorateStringGOOGLE); + dec->addIdOperand(id); + dec->addImmediateOperand(member); + dec->addImmediateOperand(decoration); + dec->addStringOperand(s); + + decorations.push_back(std::unique_ptr(dec)); +} + +// Comments in header +Function* Builder::makeEntryPoint(const char* entryPoint) +{ + assert(! entryPointFunction); Block* entry; std::vector params; - std::vector precisions; + std::vector> decorations; - mainFunction = makeFunctionEntry(NoPrecision, makeVoidType(), entryPoint, params, precisions, &entry); + entryPointFunction = makeFunctionEntry(NoPrecision, makeVoidType(), entryPoint, params, decorations, &entry); - return mainFunction; + return entryPointFunction; } // Comments in header Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name, - const std::vector& paramTypes, const std::vector& precisions, Block **entry) + const std::vector& paramTypes, const std::vector>& decorations, Block **entry) { // Make the function and initial instructions in it Id typeId = makeFunctionType(returnType, paramTypes); @@ -955,8 +1102,10 @@ Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const // Set up the precisions setPrecision(function->getId(), precision); - for (unsigned p = 0; p < (unsigned)precisions.size(); ++p) - setPrecision(firstParamId + p, precisions[p]); + for (unsigned p = 0; p < (unsigned)decorations.size(); ++p) { + for (int d = 0; d < (int)decorations[p].size(); ++d) + addDecoration(firstParamId + p, decorations[p][d]); + } // CFG if (entry) { @@ -1064,7 +1213,7 @@ Id Builder::createLoad(Id lValue) } // Comments in header -Id Builder::createAccessChain(StorageClass storageClass, Id base, std::vector& offsets) +Id Builder::createAccessChain(StorageClass storageClass, Id base, const std::vector& offsets) { // Figure out the final resulting type. spv::Id typeId = getTypeId(base); @@ -1091,7 +1240,8 @@ Id Builder::createAccessChain(StorageClass storageClass, Id base, std::vectoraddIdOperand(base); length->addImmediateOperand(member); buildPoint->addInstruction(std::unique_ptr(length)); @@ -1114,7 +1264,7 @@ Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index) return extract->getResultId(); } -Id Builder::createCompositeExtract(Id composite, Id typeId, std::vector& indexes) +Id Builder::createCompositeExtract(Id composite, Id typeId, const std::vector& indexes) { // Generate code for spec constants if in spec constant operation // generation mode. @@ -1141,7 +1291,7 @@ Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned i return insert->getResultId(); } -Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, std::vector& indexes) +Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, const std::vector& indexes) { Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert); insert->addIdOperand(object); @@ -1292,7 +1442,7 @@ Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector& op return op->getResultId(); } -Id Builder::createFunctionCall(spv::Function* function, std::vector& args) +Id Builder::createFunctionCall(spv::Function* function, const std::vector& args) { Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall); op->addIdOperand(function->getId()); @@ -1304,7 +1454,7 @@ Id Builder::createFunctionCall(spv::Function* function, std::vector& ar } // Comments in header -Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, std::vector& channels) +Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector& channels) { if (channels.size() == 1) return setPrecision(createCompositeExtract(source, typeId, channels.front()), precision); @@ -1326,16 +1476,18 @@ Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, std: } // Comments in header -Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, std::vector& channels) +Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector& channels) { - assert(getNumComponents(source) == (int)channels.size()); if (channels.size() == 1 && getNumComponents(source) == 1) return createCompositeInsert(source, target, typeId, channels.front()); Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle); - assert(isVector(source)); + assert(isVector(target)); swizzle->addIdOperand(target); + + assert(getNumComponents(source) == (int)channels.size()); + assert(isVector(source)); swizzle->addIdOperand(source); // Set up an identity shuffle from the base value to the result value @@ -1403,7 +1555,7 @@ Id Builder::smearScalar(Decoration precision, Id scalar, Id vectorType) } // Comments in header -Id Builder::createBuiltinCall(Id resultType, Id builtins, int entryPoint, std::vector& args) +Id Builder::createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector& args) { Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst); inst->addIdOperand(builtins); @@ -1618,7 +1770,7 @@ Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, } // Comments in header -Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters) +Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters, bool isUnsignedResult) { // All these need a capability addCapability(CapabilityImageQuery); @@ -1651,19 +1803,25 @@ Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameter } if (isArrayedImageType(getImageType(parameters.sampler))) ++numComponents; + + Id intType = isUnsignedResult ? makeUintType(32) : makeIntType(32); if (numComponents == 1) - resultType = makeIntType(32); + resultType = intType; else - resultType = makeVectorType(makeIntType(32), numComponents); + resultType = makeVectorType(intType, numComponents); break; } case OpImageQueryLod: +#ifdef AMD_EXTENSIONS + resultType = makeVectorType(getScalarTypeId(getTypeId(parameters.coords)), 2); +#else resultType = makeVectorType(makeFloatType(32), 2); +#endif break; case OpImageQueryLevels: case OpImageQuerySamples: - resultType = makeIntType(32); + resultType = isUnsignedResult ? makeUintType(32) : makeIntType(32); break; default: assert(0); @@ -1751,7 +1909,7 @@ Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, b } // OpCompositeConstruct -Id Builder::createCompositeConstruct(Id typeId, std::vector& constituents) +Id Builder::createCompositeConstruct(Id typeId, const std::vector& constituents) { assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 && getNumTypeConstituents(typeId) == (int)constituents.size())); @@ -1789,34 +1947,72 @@ Id Builder::createConstructor(Decoration precision, const std::vector& sourc if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1) return smearScalar(precision, sources[0], resultTypeId); + // accumulate the arguments for OpCompositeConstruct + std::vector constituents; Id scalarTypeId = getScalarTypeId(resultTypeId); - std::vector constituents; // accumulate the arguments for OpCompositeConstruct - for (unsigned int i = 0; i < sources.size(); ++i) { - assert(! isAggregate(sources[i])); - unsigned int sourceSize = getNumComponents(sources[i]); + + // lambda to store the result of visiting an argument component + const auto latchResult = [&](Id comp) { + if (numTargetComponents > 1) + constituents.push_back(comp); + else + result = comp; + ++targetComponent; + }; + + // lambda to visit a vector argument's components + const auto accumulateVectorConstituents = [&](Id sourceArg) { + unsigned int sourceSize = getNumComponents(sourceArg); unsigned int sourcesToUse = sourceSize; if (sourcesToUse + targetComponent > numTargetComponents) sourcesToUse = numTargetComponents - targetComponent; for (unsigned int s = 0; s < sourcesToUse; ++s) { - Id arg = sources[i]; - if (sourceSize > 1) { - std::vector swiz; - swiz.push_back(s); - arg = createRvalueSwizzle(precision, scalarTypeId, arg, swiz); - } - - if (numTargetComponents > 1) - constituents.push_back(arg); - else - result = arg; - ++targetComponent; + std::vector swiz; + swiz.push_back(s); + latchResult(createRvalueSwizzle(precision, scalarTypeId, sourceArg, swiz)); } + }; + + // lambda to visit a matrix argument's components + const auto accumulateMatrixConstituents = [&](Id sourceArg) { + unsigned int sourceSize = getNumColumns(sourceArg) * getNumRows(sourceArg); + unsigned int sourcesToUse = sourceSize; + if (sourcesToUse + targetComponent > numTargetComponents) + sourcesToUse = numTargetComponents - targetComponent; + + int col = 0; + int row = 0; + for (unsigned int s = 0; s < sourcesToUse; ++s) { + if (row >= getNumRows(sourceArg)) { + row = 0; + col++; + } + std::vector indexes; + indexes.push_back(col); + indexes.push_back(row); + latchResult(createCompositeExtract(sourceArg, scalarTypeId, indexes)); + row++; + } + }; + + // Go through the source arguments, each one could have either + // a single or multiple components to contribute. + for (unsigned int i = 0; i < sources.size(); ++i) { + if (isScalar(sources[i])) + latchResult(sources[i]); + else if (isVector(sources[i])) + accumulateVectorConstituents(sources[i]); + else if (isMatrix(sources[i])) + accumulateMatrixConstituents(sources[i]); + else + assert(0); if (targetComponent >= numTargetComponents) break; } + // If the result is a vector, make it from the gathered constituents. if (constituents.size() > 0) result = createCompositeConstruct(resultTypeId, constituents); @@ -1893,7 +2089,6 @@ Id Builder::createMatrixConstructor(Decoration precision, const std::vector& } } - // Step 2: Construct a matrix from that array. // First make the column vectors, then make the matrix. @@ -1914,9 +2109,10 @@ Id Builder::createMatrixConstructor(Decoration precision, const std::vector& } // Comments in header -Builder::If::If(Id cond, Builder& gb) : +Builder::If::If(Id cond, unsigned int ctrl, Builder& gb) : builder(gb), condition(cond), + control(ctrl), elseBlock(0) { function = &builder.getBuildPoint()->getParent(); @@ -1957,7 +2153,7 @@ void Builder::If::makeEndIf() // Go back to the headerBlock and make the flow control split builder.setBuildPoint(headerBlock); - builder.createSelectionMerge(mergeBlock, SelectionControlMaskNone); + builder.createSelectionMerge(mergeBlock, control); if (elseBlock) builder.createConditionalBranch(condition, thenBlock, elseBlock); else @@ -1969,7 +2165,8 @@ void Builder::If::makeEndIf() } // Comments in header -void Builder::makeSwitch(Id selector, int numSegments, std::vector& caseValues, std::vector& valueIndexToSegment, int defaultSegment, +void Builder::makeSwitch(Id selector, unsigned int control, int numSegments, const std::vector& caseValues, + const std::vector& valueIndexToSegment, int defaultSegment, std::vector& segmentBlocks) { Function& function = buildPoint->getParent(); @@ -1981,7 +2178,7 @@ void Builder::makeSwitch(Id selector, int numSegments, std::vector& caseVal Block* mergeBlock = new Block(getUniqueId(), function); // make and insert the switch's selection-merge instruction - createSelectionMerge(mergeBlock, SelectionControlMaskNone); + createSelectionMerge(mergeBlock, control); // make the switch instruction Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch); @@ -2097,10 +2294,11 @@ void Builder::accessChainPushSwizzle(std::vector& swizzle, Id preSwizz accessChain.preSwizzleBaseType = preSwizzleBaseType; // if needed, propagate the swizzle for the current access chain - if (accessChain.swizzle.size()) { + if (accessChain.swizzle.size() > 0) { std::vector oldSwizzle = accessChain.swizzle; accessChain.swizzle.resize(0); for (unsigned int i = 0; i < swizzle.size(); ++i) { + assert(swizzle[i] < oldSwizzle.size()); accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]); } } else @@ -2117,37 +2315,28 @@ void Builder::accessChainStore(Id rvalue) transferAccessChainSwizzle(true); Id base = collapseAccessChain(); + Id source = rvalue; - if (accessChain.swizzle.size() && accessChain.component != NoResult) - logger->missingFunctionality("simultaneous l-value swizzle and dynamic component selection"); + // dynamic component should be gone + assert(accessChain.component == NoResult); // If swizzle still exists, it is out-of-order or not full, we must load the target vector, // extract and insert elements to perform writeMask and/or swizzle. - Id source = NoResult; - if (accessChain.swizzle.size()) { + if (accessChain.swizzle.size() > 0) { Id tempBaseId = createLoad(base); - source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, rvalue, accessChain.swizzle); + source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle); } - // dynamic component selection - if (accessChain.component != NoResult) { - Id tempBaseId = (source == NoResult) ? createLoad(base) : source; - source = createVectorInsertDynamic(tempBaseId, getTypeId(tempBaseId), rvalue, accessChain.component); - } - - if (source == NoResult) - source = rvalue; - createStore(source, base); } // Comments in header -Id Builder::accessChainLoad(Decoration precision, Id resultType) +Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resultType) { Id id; if (accessChain.isRValue) { - // transfer access chain, but keep it static, so we can stay in registers + // transfer access chain, but try to stay in registers transferAccessChainSwizzle(false); if (accessChain.indexChain.size() > 0) { Id swizzleBase = accessChain.preSwizzleBaseType != NoType ? accessChain.preSwizzleBaseType : resultType; @@ -2188,6 +2377,7 @@ Id Builder::accessChainLoad(Decoration precision, Id resultType) // load through the access chain id = createLoad(collapseAccessChain()); setPrecision(id, precision); + addDecoration(id, nonUniform); } // Done, unless there are swizzles to do @@ -2195,19 +2385,20 @@ Id Builder::accessChainLoad(Decoration precision, Id resultType) return id; // Do remaining swizzling - // First, static swizzling - if (accessChain.swizzle.size()) { - // static swizzle + + // Do the basic swizzle + if (accessChain.swizzle.size() > 0) { Id swizzledType = getScalarTypeId(getTypeId(id)); if (accessChain.swizzle.size() > 1) swizzledType = makeVectorType(swizzledType, (int)accessChain.swizzle.size()); id = createRvalueSwizzle(precision, swizzledType, id, accessChain.swizzle); } - // dynamic single-component selection + // Do the dynamic component if (accessChain.component != NoResult) id = setPrecision(createVectorExtractDynamic(id, resultType, accessChain.component), precision); + addDecoration(id, nonUniform); return id; } @@ -2300,7 +2491,7 @@ void Builder::dump(std::vector& out) const { // Header, before first instructions: out.push_back(MagicNumber); - out.push_back(Version); + out.push_back(spvVersion); out.push_back(builderNumber); out.push_back(uniqueId + 1); out.push_back(0); @@ -2312,7 +2503,11 @@ void Builder::dump(std::vector& out) const capInst.dump(out); } - // TBD: OpExtension ... + for (auto it = extensions.cbegin(); it != extensions.cend(); ++it) { + Instruction extInst(0, 0, OpExtension); + extInst.addStringOperand(it->c_str()); + extInst.dump(out); + } dumpInstructions(out, imports); Instruction memInst(0, 0, OpMemoryModel); @@ -2325,19 +2520,15 @@ void Builder::dump(std::vector& out) const dumpInstructions(out, executionModes); // Debug instructions - if (source != SourceLanguageUnknown) { - Instruction sourceInst(0, 0, OpSource); - sourceInst.addImmediateOperand(source); - sourceInst.addImmediateOperand(sourceVersion); - sourceInst.dump(out); - } - for (int e = 0; e < (int)extensions.size(); ++e) { - Instruction extInst(0, 0, OpSourceExtension); - extInst.addStringOperand(extensions[e]); - extInst.dump(out); + dumpInstructions(out, strings); + dumpSourceInstructions(out); + for (int e = 0; e < (int)sourceExtensions.size(); ++e) { + Instruction sourceExtInst(0, 0, OpSourceExtension); + sourceExtInst.addStringOperand(sourceExtensions[e]); + sourceExtInst.dump(out); } dumpInstructions(out, names); - dumpInstructions(out, lines); + dumpModuleProcesses(out); // Annotation instructions dumpInstructions(out, decorations); @@ -2353,26 +2544,66 @@ void Builder::dump(std::vector& out) const // Protected methods. // -// Turn the described access chain in 'accessChain' into an instruction +// Turn the described access chain in 'accessChain' into an instruction(s) // computing its address. This *cannot* include complex swizzles, which must -// be handled after this is called, but it does include swizzles that select -// an individual element, as a single address of a scalar type can be -// computed by an OpAccessChain instruction. +// be handled after this is called. +// +// Can generate code. Id Builder::collapseAccessChain() { assert(accessChain.isRValue == false); - if (accessChain.indexChain.size() > 0) { - if (accessChain.instr == 0) { - StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base)); - accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain); - } - + // did we already emit an access chain for this? + if (accessChain.instr != NoResult) return accessChain.instr; - } else + + // If we have a dynamic component, we can still transfer + // that into a final operand to the access chain. We need to remap the + // dynamic component through the swizzle to get a new dynamic component to + // update. + // + // This was not done in transferAccessChainSwizzle() because it might + // generate code. + remapDynamicSwizzle(); + if (accessChain.component != NoResult) { + // transfer the dynamic component to the access chain + accessChain.indexChain.push_back(accessChain.component); + accessChain.component = NoResult; + } + + // note that non-trivial swizzling is left pending + + // do we have an access chain? + if (accessChain.indexChain.size() == 0) return accessChain.base; - // note that non-trivial swizzling is left pending... + // emit the access chain + StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base)); + accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain); + + return accessChain.instr; +} + +// For a dynamic component selection of a swizzle. +// +// Turn the swizzle and dynamic component into just a dynamic component. +// +// Generates code. +void Builder::remapDynamicSwizzle() +{ + // do we have a swizzle to remap a dynamic component through? + if (accessChain.component != NoResult && accessChain.swizzle.size() > 1) { + // build a vector of the swizzle for the component to map into + std::vector components; + for (int c = 0; c < (int)accessChain.swizzle.size(); ++c) + components.push_back(makeUintConstant(accessChain.swizzle[c])); + Id mapType = makeVectorType(makeUintType(32), (int)accessChain.swizzle.size()); + Id map = makeCompositeConstant(mapType, components); + + // use it + accessChain.component = createVectorExtractDynamic(map, makeUintType(32), accessChain.component); + accessChain.swizzle.clear(); + } } // clear out swizzle if it is redundant, that is reselecting the same components @@ -2398,38 +2629,30 @@ void Builder::simplifyAccessChainSwizzle() // To the extent any swizzling can become part of the chain // of accesses instead of a post operation, make it so. -// If 'dynamic' is true, include transferring a non-static component index, -// otherwise, only transfer static indexes. +// If 'dynamic' is true, include transferring the dynamic component, +// otherwise, leave it pending. // -// Also, Boolean vectors are likely to be special. While -// for external storage, they should only be integer types, -// function-local bool vectors could use sub-word indexing, -// so keep that as a separate Insert/Extract on a loaded vector. +// Does not generate code. just updates the access chain. void Builder::transferAccessChainSwizzle(bool dynamic) { - // too complex? - if (accessChain.swizzle.size() > 1) - return; - // non existent? if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult) return; - // single component... - - // skip doing it for Boolean vectors - if (isBoolType(getContainedTypeId(accessChain.preSwizzleBaseType))) + // too complex? + // (this requires either a swizzle, or generating code for a dynamic component) + if (accessChain.swizzle.size() > 1) return; + // single component, either in the swizzle and/or dynamic component if (accessChain.swizzle.size() == 1) { - // handle static component + assert(accessChain.component == NoResult); + // handle static component selection accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front())); accessChain.swizzle.clear(); - // note, the only valid remaining dynamic access would be to this one - // component, so don't bother even looking at accessChain.component accessChain.preSwizzleBaseType = NoType; - accessChain.component = NoResult; } else if (dynamic && accessChain.component != NoResult) { + assert(accessChain.swizzle.size() == 0); // handle dynamic component accessChain.indexChain.push_back(accessChain.component); accessChain.preSwizzleBaseType = NoType; @@ -2447,7 +2670,7 @@ void Builder::createAndSetNoPredecessorBlock(const char* /*name*/) buildPoint->getParent().addBlock(block); setBuildPoint(block); - //if (name) + // if (name) // addName(block->getId(), name); } @@ -2468,12 +2691,15 @@ void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control) buildPoint->addInstruction(std::unique_ptr(merge)); } -void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control) +void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control, + unsigned int dependencyLength) { Instruction* merge = new Instruction(OpLoopMerge); merge->addIdOperand(mergeBlock->getId()); merge->addIdOperand(continueBlock->getId()); merge->addImmediateOperand(control); + if ((control & LoopControlDependencyLengthMask) != 0) + merge->addImmediateOperand(dependencyLength); buildPoint->addInstruction(std::unique_ptr(merge)); } @@ -2488,6 +2714,48 @@ void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* els elseBlock->addPredecessor(buildPoint); } +// OpSource +// [OpSourceContinued] +// ... +void Builder::dumpSourceInstructions(std::vector& out) const +{ + const int maxWordCount = 0xFFFF; + const int opSourceWordCount = 4; + const int nonNullBytesPerInstruction = 4 * (maxWordCount - opSourceWordCount) - 1; + + if (source != SourceLanguageUnknown) { + // OpSource Language Version File Source + Instruction sourceInst(NoResult, NoType, OpSource); + sourceInst.addImmediateOperand(source); + sourceInst.addImmediateOperand(sourceVersion); + // File operand + if (sourceFileStringId != NoResult) { + sourceInst.addIdOperand(sourceFileStringId); + // Source operand + if (sourceText.size() > 0) { + int nextByte = 0; + std::string subString; + while ((int)sourceText.size() - nextByte > 0) { + subString = sourceText.substr(nextByte, nonNullBytesPerInstruction); + if (nextByte == 0) { + // OpSource + sourceInst.addStringOperand(subString.c_str()); + sourceInst.dump(out); + } else { + // OpSourcContinued + Instruction sourceContinuedInst(OpSourceContinued); + sourceContinuedInst.addStringOperand(subString.c_str()); + sourceContinuedInst.dump(out); + } + nextByte += nonNullBytesPerInstruction; + } + } else + sourceInst.dump(out); + } else + sourceInst.dump(out); + } +} + void Builder::dumpInstructions(std::vector& out, const std::vector >& instructions) const { for (int i = 0; i < (int)instructions.size(); ++i) { @@ -2495,4 +2763,13 @@ void Builder::dumpInstructions(std::vector& out, const std::vector } } +void Builder::dumpModuleProcesses(std::vector& out) const +{ + for (int i = 0; i < (int)moduleProcesses.size(); ++i) { + Instruction moduleProcessed(OpModuleProcessed); + moduleProcessed.addStringOperand(moduleProcesses[i]); + moduleProcessed.dump(out); + } +} + }; // end spv namespace diff --git a/Externals/glslang/SPIRV/SpvBuilder.h b/Externals/glslang/SPIRV/SpvBuilder.h index c7e3bcda9d..099b1d957f 100755 --- a/Externals/glslang/SPIRV/SpvBuilder.h +++ b/Externals/glslang/SPIRV/SpvBuilder.h @@ -1,12 +1,13 @@ // -//Copyright (C) 2014-2015 LunarG, Inc. -//Copyright (C) 2015-2016 Google, Inc. +// Copyright (C) 2014-2015 LunarG, Inc. +// Copyright (C) 2015-2016 Google, Inc. +// Copyright (C) 2017 ARM Limited. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,18 +21,18 @@ // 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. +// 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. // // "Builder" is an interface to fully build SPIR-V IR. Allocate one of @@ -55,22 +56,36 @@ #include #include #include +#include namespace spv { class Builder { public: - Builder(unsigned int userNumber, SpvBuildLogger* logger); + Builder(unsigned int spvVersion, unsigned int userNumber, SpvBuildLogger* logger); virtual ~Builder(); static const int maxMatrixSize = 4; + unsigned int getSpvVersion() const { return spvVersion; } + void setSource(spv::SourceLanguage lang, int version) { source = lang; sourceVersion = version; } - void addSourceExtension(const char* ext) { extensions.push_back(ext); } + void setSourceFile(const std::string& file) + { + Instruction* fileString = new Instruction(getUniqueId(), NoType, OpString); + fileString->addStringOperand(file.c_str()); + sourceFileStringId = fileString->getResultId(); + strings.push_back(std::unique_ptr(fileString)); + } + void setSourceText(const std::string& text) { sourceText = text; } + void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); } + void addModuleProcessed(const std::string& p) { moduleProcesses.push_back(p.c_str()); } + void setEmitOpLines() { emitOpLines = true; } + void addExtension(const char* ext) { extensions.insert(ext); } Id import(const char*); void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem) { @@ -91,6 +106,12 @@ public: return id; } + // Log the current line, and if different than the last one, + // issue a new OpLine, using the current file name. + void setLine(int line); + // Low-level OpLine. See setLine() for a layered helper. + void addLine(Id fileName, int line, int column); + // For creating new types (will return old type if the requested one was already made). Id makeVoidType(); Id makeBoolType(); @@ -132,7 +153,10 @@ public: bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); } bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); } - bool isBoolType(Id typeId) const { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); } + bool isBoolType(Id typeId) { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); } + bool isIntType(Id typeId) const { return getTypeClass(typeId) == 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; } bool isScalarType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; } bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; } @@ -152,6 +176,13 @@ public: unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); } StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); } + int getScalarTypeWidth(Id typeId) const + { + Id scalarTypeId = getScalarTypeId(typeId); + assert(getTypeClass(scalarTypeId) == OpTypeInt || getTypeClass(scalarTypeId) == OpTypeFloat); + return module.getInstruction(scalarTypeId)->getImmediateOperand(0); + } + int getTypeNumColumns(Id typeId) const { assert(isMatrixType(typeId)); @@ -184,24 +215,32 @@ public: // For making new constants (will return old constant if the requested one was already made). Id makeBoolConstant(bool b, bool specConstant = false); + Id makeInt8Constant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(8), (unsigned)i, specConstant); } + Id makeUint8Constant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(8), u, specConstant); } + Id makeInt16Constant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(16), (unsigned)i, specConstant); } + Id makeUint16Constant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(16), u, specConstant); } Id makeIntConstant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); } Id makeUintConstant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(32), 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) { return makeInt64Constant(makeUintType(64), u, specConstant); } Id makeFloatConstant(float f, bool specConstant = false); Id makeDoubleConstant(double d, bool specConstant = false); + Id makeFloat16Constant(float f16, bool specConstant = false); + Id makeFpConstant(Id type, double d, bool specConstant = false); // Turn the array of constants into a proper spv constant of the requested type. - Id makeCompositeConstant(Id type, std::vector& comps, bool specConst = false); + Id makeCompositeConstant(Id type, const std::vector& comps, bool specConst = false); // Methods for adding information outside the CFG. Instruction* addEntryPoint(ExecutionModel, Function*, const char* name); void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1); void addName(Id, const char* name); void addMemberName(Id, int member, const char* name); - void addLine(Id target, Id fileName, int line, int column); void addDecoration(Id, Decoration, int num = -1); + void addDecoration(Id, Decoration, const char*); + void addDecorationId(Id id, Decoration, Id idDecoration); void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1); + void addMemberDecoration(Id, unsigned int member, Decoration, const char*); // At the end of what block do the next create*() instructions go? void setBuildPoint(Block* bp) { buildPoint = bp; } @@ -209,13 +248,13 @@ public: // Make the entry-point function. The returned pointer is only valid // for the lifetime of this builder. - Function* makeEntrypoint(const char*); + Function* makeEntryPoint(const char*); // Make a shader-style function, and create its entry block if entry is non-zero. // Return the function, pass back the entry. // The returned pointer is only valid for the lifetime of this builder. Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, const std::vector& paramTypes, - const std::vector& precisions, Block **entry = 0); + const std::vector>& precisions, Block **entry = 0); // Create a return. An 'implicit' return is one not appearing in the source // code. In the case of an implicit return, no post-return block is inserted. @@ -240,16 +279,16 @@ public: Id createLoad(Id lValue); // Create an OpAccessChain instruction - Id createAccessChain(StorageClass, Id base, std::vector& offsets); + Id createAccessChain(StorageClass, Id base, const std::vector& offsets); // Create an OpArrayLength instruction Id createArrayLength(Id base, unsigned int member); // Create an OpCompositeExtract instruction Id createCompositeExtract(Id composite, Id typeId, unsigned index); - Id createCompositeExtract(Id composite, Id typeId, std::vector& indexes); + Id createCompositeExtract(Id composite, Id typeId, const std::vector& indexes); Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index); - Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector& indexes); + Id createCompositeInsert(Id object, Id composite, Id typeId, const std::vector& indexes); Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex); Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex); @@ -263,18 +302,18 @@ public: Id createBinOp(Op, Id typeId, Id operand1, Id operand2); Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3); Id createOp(Op, Id typeId, const std::vector& operands); - Id createFunctionCall(spv::Function*, std::vector&); + Id createFunctionCall(spv::Function*, const std::vector&); Id createSpecConstantOp(Op, Id typeId, const std::vector& operands, const std::vector& literals); // Take an rvalue (source) and a set of channels to extract from it to // make a new rvalue, which is returned. - Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, std::vector& channels); + Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector& channels); // Take a copy of an lvalue (target) and a source of components, and set the // source components into the lvalue where the 'channels' say to put them. // An updated version of the target is returned. // (No true lvalue or stores are used.) - Id createLvalueSwizzle(Id typeId, Id target, Id source, std::vector& channels); + Id createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector& channels); // If both the id and precision are valid, the id // gets tagged with the requested precision. @@ -297,7 +336,7 @@ public: // Generally, the type of 'scalar' does not need to be the same type as the components in 'vector'. // The type of the created vector is a vector of components of the same type as the scalar. // - // Note: One of the arguments will change, with the result coming back that way rather than + // Note: One of the arguments will change, with the result coming back that way rather than // through the return value. void promoteScalar(Decoration precision, Id& left, Id& right); @@ -307,7 +346,7 @@ public: Id smearScalar(Decoration precision, Id scalarVal, Id vectorType); // Create a call to a built-in function. - Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, std::vector& args); + Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector& args); // List of parameters used to create a texture operation struct TextureParameters { @@ -331,7 +370,7 @@ public: // Emit the OpTextureQuery* instruction that was passed in. // Figure out the right return value and type, and return it. - Id createTextureQueryCall(Op, const TextureParameters&); + Id createTextureQueryCall(Op, const TextureParameters&, bool isUnsignedResult); Id createSamplePositionCall(Decoration precision, Id, Id); @@ -342,7 +381,7 @@ public: Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */); // OpCompositeConstruct - Id createCompositeConstruct(Id typeId, std::vector& constituents); + Id createCompositeConstruct(Id typeId, const std::vector& constituents); // vector or scalar constructor Id createConstructor(Decoration precision, const std::vector& sources, Id resultTypeId); @@ -353,7 +392,7 @@ public: // Helper to use for building nested control flow with if-then-else. class If { public: - If(Id condition, Builder& builder); + If(Id condition, unsigned int ctrl, Builder& builder); ~If() {} void makeBeginElse(); @@ -365,6 +404,7 @@ public: Builder& builder; Id condition; + unsigned int control; Function* function; Block* headerBlock; Block* thenBlock; @@ -384,8 +424,8 @@ 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, int numSegments, std::vector& caseValues, std::vector& valueToSegment, int defaultSegment, - std::vector& segmentBB); // return argument + void makeSwitch(Id condition, unsigned int control, int numSegments, const std::vector& caseValues, + const std::vector& valueToSegment, int defaultSegment, std::vector& segmentBB); // return argument // Add a branch to the innermost switch's merge block. void addSwitchBreak(); @@ -466,7 +506,7 @@ public: // // the SPIR-V builder maintains a single active chain that - // the following methods operated on + // the following methods operate on // // for external save and restore @@ -499,19 +539,22 @@ public: // push new swizzle onto the end of any existing swizzle, merging into a single swizzle void accessChainPushSwizzle(std::vector& swizzle, Id preSwizzleBaseType); - // push a variable component selection onto the access chain; supporting only one, so unsided + // push a dynamic component selection onto the access chain, only applicable with a + // non-trivial swizzle or no swizzle void accessChainPushComponent(Id component, Id preSwizzleBaseType) { - accessChain.component = component; - if (accessChain.preSwizzleBaseType == NoType) - accessChain.preSwizzleBaseType = preSwizzleBaseType; + if (accessChain.swizzle.size() != 1) { + accessChain.component = component; + if (accessChain.preSwizzleBaseType == NoType) + accessChain.preSwizzleBaseType = preSwizzleBaseType; + } } // use accessChain and swizzle to store value void accessChainStore(Id rvalue); // use accessChain and swizzle to load an r-value - Id accessChainLoad(Decoration precision, Id ResultType); + Id accessChainLoad(Decoration precision, Decoration nonUniform, Id ResultType); // get the direct pointer for an l-value Id accessChainGetLValue(); @@ -527,7 +570,7 @@ public: void createBranch(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, unsigned int control, unsigned int dependencyLength); // Sets to generate opcode for specialization constants. void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; } @@ -539,19 +582,30 @@ public: protected: Id makeIntConstant(Id typeId, unsigned value, bool specConstant); Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant); - Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const; - Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) const; - Id findCompositeConstant(Op typeClass, std::vector& comps) const; + 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, const std::vector& comps); + Id findStructConstant(Id typeId, const std::vector& comps); Id collapseAccessChain(); + void remapDynamicSwizzle(); void transferAccessChainSwizzle(bool dynamic); void simplifyAccessChainSwizzle(); void createAndSetNoPredecessorBlock(const char*); void createSelectionMerge(Block* mergeBlock, unsigned int control); + void dumpSourceInstructions(std::vector&) const; void dumpInstructions(std::vector&, const std::vector >&) const; + void dumpModuleProcesses(std::vector&) const; + unsigned int spvVersion; // the version of SPIR-V to emit in the header SourceLanguage source; int sourceVersion; - std::vector extensions; + spv::Id sourceFileStringId; + std::string sourceText; + int currentLine; + bool emitOpLines; + std::set extensions; + std::vector sourceExtensions; + std::vector moduleProcesses; AddressingModel addressModel; MemoryModel memoryModel; std::set capabilities; @@ -559,24 +613,25 @@ public: Module module; Block* buildPoint; Id uniqueId; - Function* mainFunction; + Function* entryPointFunction; bool generatingOpCodeForSpecConst; AccessChain accessChain; // special blocks of instructions for output + std::vector > strings; std::vector > imports; std::vector > entryPoints; std::vector > executionModes; std::vector > names; - std::vector > lines; std::vector > decorations; std::vector > constantsTypesGlobals; std::vector > externals; std::vector > functions; // not output, internally used for quick & dirty canonical (unique) creation - std::vector groupedConstants[OpConstant]; // all types appear before OpConstant - std::vector groupedTypes[OpConstant]; + std::unordered_map> groupedConstants; // map type opcodes to constant inst. + std::unordered_map> groupedStructConstants; // map struct-id to constant instructions + std::unordered_map> groupedTypes; // map type opcodes to type instructions // stack of switches std::stack switchMerges; @@ -584,7 +639,7 @@ public: // Our loop stack. std::stack loops; - // The stream for outputing warnings and errors. + // The stream for outputting warnings and errors. SpvBuildLogger* logger; }; // end Builder class diff --git a/Externals/glslang/SPIRV/bitutils.h b/Externals/glslang/SPIRV/bitutils.h new file mode 100644 index 0000000000..31288ab69d --- /dev/null +++ b/Externals/glslang/SPIRV/bitutils.h @@ -0,0 +1,81 @@ +// Copyright (c) 2015-2016 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef LIBSPIRV_UTIL_BITUTILS_H_ +#define LIBSPIRV_UTIL_BITUTILS_H_ + +#include +#include + +namespace spvutils { + +// Performs a bitwise copy of source to the destination type Dest. +template +Dest BitwiseCast(Src source) { + Dest dest; + static_assert(sizeof(source) == sizeof(dest), + "BitwiseCast: Source and destination must have the same size"); + std::memcpy(&dest, &source, sizeof(dest)); + return dest; +} + +// SetBits returns an integer of type with bits set +// for position through , counting from the least +// significant bit. In particular when Num == 0, no positions are set to 1. +// A static assert will be triggered if First + Num > sizeof(T) * 8, that is, +// a bit that will not fit in the underlying type is set. +template +struct SetBits { + static_assert(First < sizeof(T) * 8, + "Tried to set a bit that is shifted too far."); + const static T get = (T(1) << First) | SetBits::get; +}; + +template +struct SetBits { + const static T get = T(0); +}; + +// This is all compile-time so we can put our tests right here. +static_assert(SetBits::get == uint32_t(0x00000000), + "SetBits failed"); +static_assert(SetBits::get == uint32_t(0x00000001), + "SetBits failed"); +static_assert(SetBits::get == uint32_t(0x80000000), + "SetBits failed"); +static_assert(SetBits::get == uint32_t(0x00000006), + "SetBits failed"); +static_assert(SetBits::get == uint32_t(0xc0000000), + "SetBits failed"); +static_assert(SetBits::get == uint32_t(0x7FFFFFFF), + "SetBits failed"); +static_assert(SetBits::get == uint32_t(0xFFFFFFFF), + "SetBits failed"); +static_assert(SetBits::get == uint32_t(0xFFFF0000), + "SetBits failed"); + +static_assert(SetBits::get == uint64_t(0x0000000000000001LL), + "SetBits failed"); +static_assert(SetBits::get == uint64_t(0x8000000000000000LL), + "SetBits failed"); +static_assert(SetBits::get == uint64_t(0xc000000000000000LL), + "SetBits failed"); +static_assert(SetBits::get == uint64_t(0x0000000080000000LL), + "SetBits failed"); +static_assert(SetBits::get == uint64_t(0x00000000FFFF0000LL), + "SetBits failed"); + +} // namespace spvutils + +#endif // LIBSPIRV_UTIL_BITUTILS_H_ diff --git a/Externals/glslang/SPIRV/disassemble.cpp b/Externals/glslang/SPIRV/disassemble.cpp old mode 100644 new mode 100755 index 75688cb9a9..b432e65d0f --- a/Externals/glslang/SPIRV/disassemble.cpp +++ b/Externals/glslang/SPIRV/disassemble.cpp @@ -1,11 +1,11 @@ // -//Copyright (C) 2014-2015 LunarG, Inc. +// Copyright (C) 2014-2015 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,41 +19,58 @@ // 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. +// 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. // // Disassembler for SPIR-V. // -#include -#include -#include +#include +#include +#include #include #include #include #include -namespace spv { - // Include C-based headers that don't have a namespace - #include "GLSL.std.450.h" -} -const char* GlslStd450DebugNames[spv::GLSLstd450Count]; - #include "disassemble.h" #include "doc.h" namespace spv { + extern "C" { + // Include C-based headers that don't have a namespace + #include "GLSL.std.450.h" +#ifdef AMD_EXTENSIONS + #include "GLSL.ext.AMD.h" +#endif + +#ifdef NV_EXTENSIONS + #include "GLSL.ext.NV.h" +#endif + } +} +const char* GlslStd450DebugNames[spv::GLSLstd450Count]; + +namespace spv { + +#ifdef AMD_EXTENSIONS +static const char* GLSLextAMDGetDebugNames(const char*, unsigned); +#endif + +#ifdef NV_EXTENSIONS +static const char* GLSLextNVGetDebugNames(const char*, unsigned); +#endif static void Kill(std::ostream& out, const char* message) { @@ -64,6 +81,15 @@ static void Kill(std::ostream& out, const char* message) // used to identify the extended instruction library imported when printing enum ExtInstSet { GLSL450Inst, + +#ifdef AMD_EXTENSIONS + GLSLextAMDInst, +#endif + +#ifdef NV_EXTENSIONS + GLSLextNVInst, +#endif + OpenCLExtInst, }; @@ -205,10 +231,12 @@ void SpirvStream::outputIndent() void SpirvStream::formatId(Id id, std::stringstream& idStream) { - if (id >= bound) - Kill(out, "Bad "); - if (id != 0) { + // On instructions with no IDs, this is called with "0", which does not + // have to be within ID bounds on null shaders. + if (id >= bound) + Kill(out, "Bad "); + idStream << id; if (idDescriptor[id].size() > 0) idStream << "(" << idDescriptor[id] << ")"; @@ -322,13 +350,24 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, idDescriptor[resultId] = (const char*)(&stream[word]); } else { - if (idDescriptor[resultId].size() == 0) { + if (resultId != 0 && idDescriptor[resultId].size() == 0) { switch (opCode) { case OpTypeInt: - idDescriptor[resultId] = "int"; + switch (stream[word]) { + case 8: idDescriptor[resultId] = "int8_t"; break; + case 16: idDescriptor[resultId] = "int16_t"; break; + default: assert(0); // fallthrough + case 32: idDescriptor[resultId] = "int"; break; + case 64: idDescriptor[resultId] = "int64_t"; break; + } break; case OpTypeFloat: - idDescriptor[resultId] = "float"; + switch (stream[word]) { + case 16: 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: idDescriptor[resultId] = "bool"; @@ -340,8 +379,18 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, idDescriptor[resultId] = "ptr"; break; case OpTypeVector: - if (idDescriptor[stream[word]].size() > 0) + if (idDescriptor[stream[word]].size() > 0) { idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1); + if (strstr(idDescriptor[stream[word]].c_str(), "8")) { + idDescriptor[resultId].append("8"); + } + if (strstr(idDescriptor[stream[word]].c_str(), "16")) { + idDescriptor[resultId].append("16"); + } + if (strstr(idDescriptor[stream[word]].c_str(), "64")) { + idDescriptor[resultId].append("64"); + } + } idDescriptor[resultId].append("vec"); switch (stream[word + 1]) { case 2: idDescriptor[resultId].append("2"); break; @@ -446,14 +495,38 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, --numOperands; if (opCode == OpExtInst) { ExtInstSet extInstSet = GLSL450Inst; - if (0 == memcmp("OpenCL", (const char*)(idDescriptor[stream[word-2]].c_str()), 6)) { + const char* name = idDescriptor[stream[word - 2]].c_str(); + if (0 == memcmp("OpenCL", name, 6)) { extInstSet = OpenCLExtInst; +#ifdef AMD_EXTENSIONS + } else if (strcmp(spv::E_SPV_AMD_shader_ballot, name) == 0 || + strcmp(spv::E_SPV_AMD_shader_trinary_minmax, name) == 0 || + strcmp(spv::E_SPV_AMD_shader_explicit_vertex_parameter, name) == 0 || + strcmp(spv::E_SPV_AMD_gcn_shader, name) == 0) { + extInstSet = GLSLextAMDInst; +#endif +#ifdef NV_EXTENSIONS + }else if (strcmp(spv::E_SPV_NV_sample_mask_override_coverage, name) == 0 || + strcmp(spv::E_SPV_NV_geometry_shader_passthrough, name) == 0 || + strcmp(spv::E_SPV_NV_viewport_array2, name) == 0 || + strcmp(spv::E_SPV_NVX_multiview_per_view_attributes, name) == 0) { + extInstSet = GLSLextNVInst; +#endif } unsigned entrypoint = stream[word - 1]; if (extInstSet == GLSL450Inst) { if (entrypoint < GLSLstd450Count) { out << "(" << GlslStd450DebugNames[entrypoint] << ")"; } +#ifdef AMD_EXTENSIONS + } else if (extInstSet == GLSLextAMDInst) { + out << "(" << GLSLextAMDGetDebugNames(name, entrypoint) << ")"; +#endif +#ifdef NV_EXTENSIONS + } + else if (extInstSet == GLSLextNVInst) { + out << "(" << GLSLextNVGetDebugNames(name, entrypoint) << ")"; +#endif } } break; @@ -561,6 +634,79 @@ static void GLSLstd450GetDebugNames(const char** names) names[GLSLstd450InterpolateAtOffset] = "InterpolateAtOffset"; } +#ifdef AMD_EXTENSIONS +static const char* GLSLextAMDGetDebugNames(const char* name, unsigned entrypoint) +{ + if (strcmp(name, spv::E_SPV_AMD_shader_ballot) == 0) { + switch (entrypoint) { + case SwizzleInvocationsAMD: return "SwizzleInvocationsAMD"; + case SwizzleInvocationsMaskedAMD: return "SwizzleInvocationsMaskedAMD"; + case WriteInvocationAMD: return "WriteInvocationAMD"; + case MbcntAMD: return "MbcntAMD"; + default: return "Bad"; + } + } else if (strcmp(name, spv::E_SPV_AMD_shader_trinary_minmax) == 0) { + switch (entrypoint) { + case FMin3AMD: return "FMin3AMD"; + case UMin3AMD: return "UMin3AMD"; + case SMin3AMD: return "SMin3AMD"; + case FMax3AMD: return "FMax3AMD"; + case UMax3AMD: return "UMax3AMD"; + case SMax3AMD: return "SMax3AMD"; + case FMid3AMD: return "FMid3AMD"; + case UMid3AMD: return "UMid3AMD"; + case SMid3AMD: return "SMid3AMD"; + default: return "Bad"; + } + } else if (strcmp(name, spv::E_SPV_AMD_shader_explicit_vertex_parameter) == 0) { + switch (entrypoint) { + case InterpolateAtVertexAMD: return "InterpolateAtVertexAMD"; + default: return "Bad"; + } + } + else if (strcmp(name, spv::E_SPV_AMD_gcn_shader) == 0) { + switch (entrypoint) { + case CubeFaceIndexAMD: return "CubeFaceIndexAMD"; + case CubeFaceCoordAMD: return "CubeFaceCoordAMD"; + case TimeAMD: return "TimeAMD"; + default: + break; + } + } + + return "Bad"; +} +#endif + +#ifdef NV_EXTENSIONS +static const char* GLSLextNVGetDebugNames(const char* name, unsigned entrypoint) +{ + if (strcmp(name, spv::E_SPV_NV_sample_mask_override_coverage) == 0 || + strcmp(name, spv::E_SPV_NV_geometry_shader_passthrough) == 0 || + strcmp(name, spv::E_ARB_shader_viewport_layer_array) == 0 || + strcmp(name, spv::E_SPV_NV_viewport_array2) == 0 || + strcmp(spv::E_SPV_NVX_multiview_per_view_attributes, name) == 0) { + switch (entrypoint) { + case DecorationOverrideCoverageNV: return "OverrideCoverageNV"; + case DecorationPassthroughNV: return "PassthroughNV"; + case CapabilityGeometryShaderPassthroughNV: return "GeometryShaderPassthroughNV"; + case DecorationViewportRelativeNV: return "ViewportRelativeNV"; + case BuiltInViewportMaskNV: return "ViewportMaskNV"; + case CapabilityShaderViewportMaskNV: return "ShaderViewportMaskNV"; + case DecorationSecondaryViewportRelativeNV: return "SecondaryViewportRelativeNV"; + case BuiltInSecondaryPositionNV: return "SecondaryPositionNV"; + case BuiltInSecondaryViewportMaskNV: return "SecondaryViewportMaskNV"; + case CapabilityShaderStereoViewNV: return "ShaderStereoViewNV"; + case BuiltInPositionPerViewNV: return "PositionPerViewNV"; + case BuiltInViewportMaskPerViewNV: return "ViewportMaskPerViewNV"; + case CapabilityPerViewAttributesNV: return "PerViewAttributesNV"; + default: return "Bad"; + } + } + return "Bad"; +} +#endif + void Disassemble(std::ostream& out, const std::vector& stream) { SpirvStream SpirvStream(out, stream); diff --git a/Externals/glslang/SPIRV/disassemble.h b/Externals/glslang/SPIRV/disassemble.h index f5d0bc23be..47cef65a57 100755 --- a/Externals/glslang/SPIRV/disassemble.h +++ b/Externals/glslang/SPIRV/disassemble.h @@ -1,11 +1,11 @@ // -//Copyright (C) 2014-2015 LunarG, Inc. +// Copyright (C) 2014-2015 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,18 +19,18 @@ // 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. +// 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. // // Disassembler for SPIR-V. diff --git a/Externals/glslang/SPIRV/doc.cpp b/Externals/glslang/SPIRV/doc.cpp index fed3ec4271..a905968735 100755 --- a/Externals/glslang/SPIRV/doc.cpp +++ b/Externals/glslang/SPIRV/doc.cpp @@ -1,11 +1,11 @@ // -//Copyright (C) 2014-2015 LunarG, Inc. +// Copyright (C) 2014-2015 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,21 +19,21 @@ // 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. +// 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. // -// 1) Programatically fill in instruction/operand information. +// 1) Programmatically fill in instruction/operand information. // This can be used for disassembly, printing documentation, etc. // // 2) Print documentation from this parameterization. @@ -41,10 +41,24 @@ #include "doc.h" -#include -#include +#include +#include #include +namespace spv { + extern "C" { + // Include C-based headers that don't have a namespace + #include "GLSL.ext.KHR.h" + #include "GLSL.ext.EXT.h" +#ifdef AMD_EXTENSIONS + #include "GLSL.ext.AMD.h" +#endif +#ifdef NV_EXTENSIONS + #include "GLSL.ext.NV.h" +#endif + } +} + namespace spv { // @@ -52,16 +66,14 @@ namespace spv { // the specification (or their sanitized versions for auto-generating the // spirv headers. // -// Also, the ceilings are declared next to these, to help keep them in sync. +// Also, for masks the ceilings are declared next to these, to help keep them in sync. // Ceilings should be // - one more than the maximum value an enumerant takes on, for non-mask enumerants -// (for non-sparse enums, this is the number of enumurants) +// (for non-sparse enums, this is the number of enumerants) // - the number of bits consumed by the set of masks -// (for non-sparse mask enums, this is the number of enumurants) +// (for non-sparse mask enums, this is the number of enumerants) // -const int SourceLanguageCeiling = 6; // HLSL todo: need official enumerant - const char* SourceString(int source) { switch (source) { @@ -72,13 +84,10 @@ const char* SourceString(int source) case 4: return "OpenCL_CPP"; case 5: return "HLSL"; - case SourceLanguageCeiling: default: return "Bad"; } } -const int ExecutionModelCeiling = 7; - const char* ExecutionModelString(int model) { switch (model) { @@ -90,13 +99,10 @@ const char* ExecutionModelString(int model) case 5: return "GLCompute"; case 6: return "Kernel"; - case ExecutionModelCeiling: default: return "Bad"; } } -const int AddressingModelCeiling = 3; - const char* AddressingString(int addr) { switch (addr) { @@ -104,13 +110,10 @@ const char* AddressingString(int addr) case 1: return "Physical32"; case 2: return "Physical64"; - case AddressingModelCeiling: default: return "Bad"; } } -const int MemoryModelCeiling = 3; - const char* MemoryString(int mem) { switch (mem) { @@ -118,7 +121,6 @@ const char* MemoryString(int mem) case 1: return "GLSL450"; case 2: return "OpenCL"; - case MemoryModelCeiling: default: return "Bad"; } } @@ -162,13 +164,12 @@ const char* ExecutionModeString(int mode) case 31: return "ContractionOff"; case 32: return "Bad"; + case 4446: return "PostDepthCoverage"; case ExecutionModeCeiling: default: return "Bad"; } } -const int StorageClassCeiling = 12; - const char* StorageClassString(int StorageClass) { switch (StorageClass) { @@ -184,8 +185,8 @@ const char* StorageClassString(int StorageClass) case 9: return "PushConstant"; case 10: return "AtomicCounter"; case 11: return "Image"; + case 12: return "StorageBuffer"; - case StorageClassCeiling: default: return "Bad"; } } @@ -243,11 +244,23 @@ const char* DecorationString(int decoration) case DecorationCeiling: default: return "Bad"; + +#ifdef AMD_EXTENSIONS + case DecorationExplicitInterpAMD: return "ExplicitInterpAMD"; +#endif +#ifdef NV_EXTENSIONS + case DecorationOverrideCoverageNV: return "OverrideCoverageNV"; + case DecorationPassthroughNV: return "PassthroughNV"; + case DecorationViewportRelativeNV: return "ViewportRelativeNV"; + case DecorationSecondaryViewportRelativeNV: return "SecondaryViewportRelativeNV"; +#endif + + case DecorationNonUniformEXT: return "DecorationNonUniformEXT"; + case DecorationHlslCounterBufferGOOGLE: return "DecorationHlslCounterBufferGOOGLE"; + case DecorationHlslSemanticGOOGLE: return "DecorationHlslSemanticGOOGLE"; } } -const int BuiltInCeiling = 44; - const char* BuiltInString(int builtIn) { switch (builtIn) { @@ -296,13 +309,42 @@ const char* BuiltInString(int builtIn) case 42: return "VertexIndex"; // TBD: put next to VertexId? case 43: return "InstanceIndex"; // TBD: put next to InstanceId? - case BuiltInCeiling: + case 4416: return "SubgroupEqMaskKHR"; + case 4417: return "SubgroupGeMaskKHR"; + case 4418: return "SubgroupGtMaskKHR"; + case 4419: return "SubgroupLeMaskKHR"; + case 4420: return "SubgroupLtMaskKHR"; + case 4438: return "DeviceIndex"; + case 4440: return "ViewIndex"; + case 4424: return "BaseVertex"; + case 4425: return "BaseInstance"; + case 4426: return "DrawIndex"; + case 5014: return "FragStencilRefEXT"; + +#ifdef AMD_EXTENSIONS + case 4992: return "BaryCoordNoPerspAMD"; + case 4993: return "BaryCoordNoPerspCentroidAMD"; + case 4994: return "BaryCoordNoPerspSampleAMD"; + case 4995: return "BaryCoordSmoothAMD"; + case 4996: return "BaryCoordSmoothCentroidAMD"; + case 4997: return "BaryCoordSmoothSampleAMD"; + case 4998: return "BaryCoordPullModelAMD"; +#endif + +#ifdef NV_EXTENSIONS + case 5253: return "ViewportMaskNV"; + case 5257: return "SecondaryPositionNV"; + case 5258: return "SecondaryViewportMaskNV"; + case 5261: return "PositionPerViewNV"; + case 5262: return "ViewportMaskPerViewNV"; +#endif + + case 5264: return "FullyCoveredEXT"; + default: return "Bad"; } } -const int DimensionCeiling = 7; - const char* DimensionString(int dim) { switch (dim) { @@ -314,13 +356,10 @@ const char* DimensionString(int dim) case 5: return "Buffer"; case 6: return "SubpassData"; - case DimensionCeiling: default: return "Bad"; } } -const int SamplerAddressingModeCeiling = 5; - const char* SamplerAddressingModeString(int mode) { switch (mode) { @@ -330,26 +369,20 @@ const char* SamplerAddressingModeString(int mode) case 3: return "Repeat"; case 4: return "RepeatMirrored"; - case SamplerAddressingModeCeiling: default: return "Bad"; } } -const int SamplerFilterModeCeiling = 2; - const char* SamplerFilterModeString(int mode) { switch (mode) { case 0: return "Nearest"; case 1: return "Linear"; - case SamplerFilterModeCeiling: default: return "Bad"; } } -const int ImageFormatCeiling = 40; - const char* ImageFormatString(int format) { switch (format) { @@ -406,14 +439,11 @@ const char* ImageFormatString(int format) case 38: return "R16ui"; case 39: return "R8ui"; - case ImageFormatCeiling: default: return "Bad"; } } -const int ImageChannelOrderCeiling = 19; - const char* ImageChannelOrderString(int format) { switch (format) { @@ -437,14 +467,11 @@ const char* ImageChannelOrderString(int format) case 17: return "sRGBA"; case 18: return "sBGRA"; - case ImageChannelOrderCeiling: default: return "Bad"; } } -const int ImageChannelDataTypeCeiling = 17; - const char* ImageChannelDataTypeString(int type) { switch (type) @@ -467,7 +494,6 @@ const char* ImageChannelDataTypeString(int type) case 15: return "UnormInt24"; case 16: return "UnormInt101010_2"; - case ImageChannelDataTypeCeiling: default: return "Bad"; } @@ -493,8 +519,6 @@ const char* ImageOperandsString(int format) } } -const int FPFastMathCeiling = 5; - const char* FPFastMathString(int mode) { switch (mode) { @@ -504,13 +528,10 @@ const char* FPFastMathString(int mode) case 3: return "AllowRecip"; case 4: return "Fast"; - case FPFastMathCeiling: default: return "Bad"; } } -const int FPRoundingModeCeiling = 4; - const char* FPRoundingModeString(int mode) { switch (mode) { @@ -519,26 +540,20 @@ const char* FPRoundingModeString(int mode) case 2: return "RTP"; case 3: return "RTN"; - case FPRoundingModeCeiling: default: return "Bad"; } } -const int LinkageTypeCeiling = 2; - const char* LinkageTypeString(int type) { switch (type) { case 0: return "Export"; case 1: return "Import"; - case LinkageTypeCeiling: default: return "Bad"; } } -const int FuncParamAttrCeiling = 8; - const char* FuncParamAttrString(int attr) { switch (attr) { @@ -551,13 +566,10 @@ const char* FuncParamAttrString(int attr) case 6: return "NoWrite"; case 7: return "NoReadWrite"; - case FuncParamAttrCeiling: default: return "Bad"; } } -const int AccessQualifierCeiling = 3; - const char* AccessQualifierString(int attr) { switch (attr) { @@ -565,7 +577,6 @@ const char* AccessQualifierString(int attr) case 1: return "WriteOnly"; case 2: return "ReadWrite"; - case AccessQualifierCeiling: default: return "Bad"; } } @@ -583,13 +594,15 @@ const char* SelectControlString(int cont) } } -const int LoopControlCeiling = 2; +const int LoopControlCeiling = 4; const char* LoopControlString(int cont) { switch (cont) { case 0: return "Unroll"; case 1: return "DontUnroll"; + case 2: return "DependencyInfinite"; + case 3: return "DependencyLength"; case LoopControlCeiling: default: return "Bad"; @@ -611,8 +624,6 @@ const char* FunctionControlString(int cont) } } -const int MemorySemanticsCeiling = 12; - const char* MemorySemanticsString(int mem) { // Note: No bits set (None) means "Relaxed" @@ -630,13 +641,10 @@ const char* MemorySemanticsString(int mem) case 10: return "AtomicCounterMemory"; case 11: return "ImageMemory"; - case MemorySemanticsCeiling: default: return "Bad"; } } -const int MemoryAccessCeiling = 3; - const char* MemoryAccessString(int mem) { switch (mem) { @@ -644,13 +652,10 @@ const char* MemoryAccessString(int mem) case 1: return "Aligned"; case 2: return "Nontemporal"; - case MemoryAccessCeiling: default: return "Bad"; } } -const int ScopeCeiling = 5; - const char* ScopeString(int mem) { switch (mem) { @@ -660,29 +665,29 @@ const char* ScopeString(int mem) case 3: return "Subgroup"; case 4: return "Invocation"; - case ScopeCeiling: default: return "Bad"; } } -const int GroupOperationCeiling = 3; - const char* GroupOperationString(int gop) { switch (gop) { - case 0: return "Reduce"; - case 1: return "InclusiveScan"; - case 2: return "ExclusiveScan"; + case GroupOperationReduce: return "Reduce"; + case GroupOperationInclusiveScan: return "InclusiveScan"; + case GroupOperationExclusiveScan: return "ExclusiveScan"; + case GroupOperationClusteredReduce: return "ClusteredReduce"; +#ifdef NV_EXTENSIONS + case GroupOperationPartitionedReduceNV: return "PartitionedReduceNV"; + case GroupOperationPartitionedInclusiveScanNV: return "PartitionedInclusiveScanNV"; + case GroupOperationPartitionedExclusiveScanNV: return "PartitionedExclusiveScanNV"; +#endif - case GroupOperationCeiling: default: return "Bad"; } } -const int KernelEnqueueFlagsCeiling = 3; - const char* KernelEnqueueFlagsString(int flag) { switch (flag) @@ -691,26 +696,20 @@ const char* KernelEnqueueFlagsString(int flag) case 1: return "WaitKernel"; case 2: return "WaitWorkGroup"; - case KernelEnqueueFlagsCeiling: default: return "Bad"; } } -const int KernelProfilingInfoCeiling = 1; - const char* KernelProfilingInfoString(int info) { switch (info) { case 0: return "CmdExecTime"; - case KernelProfilingInfoCeiling: default: return "Bad"; } } -const int CapabilityCeiling = 58; - const char* CapabilityString(int info) { switch (info) @@ -773,8 +772,63 @@ const char* CapabilityString(int info) case 55: return "StorageImageReadWithoutFormat"; case 56: return "StorageImageWriteWithoutFormat"; case 57: return "MultiViewport"; + case 61: return "GroupNonUniform"; + case 62: return "GroupNonUniformVote"; + case 63: return "GroupNonUniformArithmetic"; + case 64: return "GroupNonUniformBallot"; + case 65: return "GroupNonUniformShuffle"; + case 66: return "GroupNonUniformShuffleRelative"; + case 67: return "GroupNonUniformClustered"; + case 68: return "GroupNonUniformQuad"; + + case CapabilitySubgroupBallotKHR: return "SubgroupBallotKHR"; + case CapabilityDrawParameters: return "DrawParameters"; + case CapabilitySubgroupVoteKHR: return "SubgroupVoteKHR"; + + case CapabilityStorageUniformBufferBlock16: return "StorageUniformBufferBlock16"; + case CapabilityStorageUniform16: return "StorageUniform16"; + case CapabilityStoragePushConstant16: return "StoragePushConstant16"; + case CapabilityStorageInputOutput16: return "StorageInputOutput16"; + + case CapabilityDeviceGroup: return "DeviceGroup"; + case CapabilityMultiView: return "MultiView"; + + case CapabilityStencilExportEXT: return "StencilExportEXT"; + +#ifdef AMD_EXTENSIONS + case CapabilityFloat16ImageAMD: return "Float16ImageAMD"; + case CapabilityImageGatherBiasLodAMD: return "ImageGatherBiasLodAMD"; + case CapabilityFragmentMaskAMD: return "FragmentMaskAMD"; + case CapabilityImageReadWriteLodAMD: return "ImageReadWriteLodAMD"; +#endif + + case CapabilityAtomicStorageOps: return "AtomicStorageOps"; + + case CapabilitySampleMaskPostDepthCoverage: return "SampleMaskPostDepthCoverage"; +#ifdef NV_EXTENSIONS + case CapabilityGeometryShaderPassthroughNV: return "GeometryShaderPassthroughNV"; + case CapabilityShaderViewportIndexLayerNV: return "ShaderViewportIndexLayerNV"; + case CapabilityShaderViewportMaskNV: return "ShaderViewportMaskNV"; + case CapabilityShaderStereoViewNV: return "ShaderStereoViewNV"; + case CapabilityPerViewAttributesNV: return "PerViewAttributesNV"; + case CapabilityGroupNonUniformPartitionedNV: return "GroupNonUniformPartitionedNV"; +#endif + + case CapabilityFragmentFullyCoveredEXT: return "FragmentFullyCoveredEXT"; + + case CapabilityShaderNonUniformEXT: return "CapabilityShaderNonUniformEXT"; + case CapabilityRuntimeDescriptorArrayEXT: return "CapabilityRuntimeDescriptorArrayEXT"; + case CapabilityInputAttachmentArrayDynamicIndexingEXT: return "CapabilityInputAttachmentArrayDynamicIndexingEXT"; + case CapabilityUniformTexelBufferArrayDynamicIndexingEXT: return "CapabilityUniformTexelBufferArrayDynamicIndexingEXT"; + case CapabilityStorageTexelBufferArrayDynamicIndexingEXT: return "CapabilityStorageTexelBufferArrayDynamicIndexingEXT"; + case CapabilityUniformBufferArrayNonUniformIndexingEXT: return "CapabilityUniformBufferArrayNonUniformIndexingEXT"; + case CapabilitySampledImageArrayNonUniformIndexingEXT: return "CapabilitySampledImageArrayNonUniformIndexingEXT"; + case CapabilityStorageBufferArrayNonUniformIndexingEXT: return "CapabilityStorageBufferArrayNonUniformIndexingEXT"; + case CapabilityStorageImageArrayNonUniformIndexingEXT: return "CapabilityStorageImageArrayNonUniformIndexingEXT"; + case CapabilityInputAttachmentArrayNonUniformIndexingEXT: return "CapabilityInputAttachmentArrayNonUniformIndexingEXT"; + case CapabilityUniformTexelBufferArrayNonUniformIndexingEXT: return "CapabilityUniformTexelBufferArrayNonUniformIndexingEXT"; + case CapabilityStorageTexelBufferArrayNonUniformIndexingEXT: return "CapabilityStorageTexelBufferArrayNonUniformIndexingEXT"; - case CapabilityCeiling: default: return "Bad"; } } @@ -1104,7 +1158,71 @@ const char* OpcodeString(int op) case 319: return "OpAtomicFlagClear"; case 320: return "OpImageSparseRead"; - case OpcodeCeiling: + case OpModuleProcessed: return "OpModuleProcessed"; + case OpDecorateId: return "OpDecorateId"; + + case 333: return "OpGroupNonUniformElect"; + case 334: return "OpGroupNonUniformAll"; + case 335: return "OpGroupNonUniformAny"; + case 336: return "OpGroupNonUniformAllEqual"; + case 337: return "OpGroupNonUniformBroadcast"; + case 338: return "OpGroupNonUniformBroadcastFirst"; + case 339: return "OpGroupNonUniformBallot"; + case 340: return "OpGroupNonUniformInverseBallot"; + case 341: return "OpGroupNonUniformBallotBitExtract"; + case 342: return "OpGroupNonUniformBallotBitCount"; + case 343: return "OpGroupNonUniformBallotFindLSB"; + case 344: return "OpGroupNonUniformBallotFindMSB"; + case 345: return "OpGroupNonUniformShuffle"; + case 346: return "OpGroupNonUniformShuffleXor"; + case 347: return "OpGroupNonUniformShuffleUp"; + case 348: return "OpGroupNonUniformShuffleDown"; + case 349: return "OpGroupNonUniformIAdd"; + case 350: return "OpGroupNonUniformFAdd"; + case 351: return "OpGroupNonUniformIMul"; + case 352: return "OpGroupNonUniformFMul"; + case 353: return "OpGroupNonUniformSMin"; + case 354: return "OpGroupNonUniformUMin"; + case 355: return "OpGroupNonUniformFMin"; + case 356: return "OpGroupNonUniformSMax"; + case 357: return "OpGroupNonUniformUMax"; + case 358: return "OpGroupNonUniformFMax"; + case 359: return "OpGroupNonUniformBitwiseAnd"; + case 360: return "OpGroupNonUniformBitwiseOr"; + case 361: return "OpGroupNonUniformBitwiseXor"; + case 362: return "OpGroupNonUniformLogicalAnd"; + case 363: return "OpGroupNonUniformLogicalOr"; + case 364: return "OpGroupNonUniformLogicalXor"; + case 365: return "OpGroupNonUniformQuadBroadcast"; + case 366: return "OpGroupNonUniformQuadSwap"; + + case 4421: return "OpSubgroupBallotKHR"; + case 4422: return "OpSubgroupFirstInvocationKHR"; + case 4428: return "OpSubgroupAllKHR"; + case 4429: return "OpSubgroupAnyKHR"; + case 4430: return "OpSubgroupAllEqualKHR"; + case 4432: return "OpSubgroupReadInvocationKHR"; + +#ifdef AMD_EXTENSIONS + case 5000: return "OpGroupIAddNonUniformAMD"; + case 5001: return "OpGroupFAddNonUniformAMD"; + case 5002: return "OpGroupFMinNonUniformAMD"; + case 5003: return "OpGroupUMinNonUniformAMD"; + case 5004: return "OpGroupSMinNonUniformAMD"; + case 5005: return "OpGroupFMaxNonUniformAMD"; + case 5006: return "OpGroupUMaxNonUniformAMD"; + case 5007: return "OpGroupSMaxNonUniformAMD"; + + case 5011: return "OpFragmentMaskFetchAMD"; + case 5012: return "OpFragmentFetchAMD"; +#endif + + case OpDecorateStringGOOGLE: return "OpDecorateStringGOOGLE"; + case OpMemberDecorateStringGOOGLE: return "OpMemberDecorateStringGOOGLE"; + +#ifdef NV_EXTENSIONS + case OpGroupNonUniformPartitionNV: return "OpGroupNonUniformPartitionNV"; +#endif default: return "Bad"; } @@ -1112,40 +1230,17 @@ const char* OpcodeString(int op) // The set of objects that hold all the instruction/operand // parameterization information. -InstructionParameters InstructionDesc[OpcodeCeiling]; +InstructionParameters InstructionDesc[OpCodeMask + 1]; OperandParameters ExecutionModeOperands[ExecutionModeCeiling]; OperandParameters DecorationOperands[DecorationCeiling]; EnumDefinition OperandClassParams[OperandCount]; -EnumParameters ExecutionModelParams[ExecutionModelCeiling]; -EnumParameters AddressingParams[AddressingModelCeiling]; -EnumParameters MemoryParams[MemoryModelCeiling]; EnumParameters ExecutionModeParams[ExecutionModeCeiling]; -EnumParameters StorageParams[StorageClassCeiling]; -EnumParameters SamplerAddressingModeParams[SamplerAddressingModeCeiling]; -EnumParameters SamplerFilterModeParams[SamplerFilterModeCeiling]; -EnumParameters ImageFormatParams[ImageFormatCeiling]; -EnumParameters ImageChannelOrderParams[ImageChannelOrderCeiling]; -EnumParameters ImageChannelDataTypeParams[ImageChannelDataTypeCeiling]; EnumParameters ImageOperandsParams[ImageOperandsCeiling]; -EnumParameters FPFastMathParams[FPFastMathCeiling]; -EnumParameters FPRoundingModeParams[FPRoundingModeCeiling]; -EnumParameters LinkageTypeParams[LinkageTypeCeiling]; EnumParameters DecorationParams[DecorationCeiling]; -EnumParameters BuiltInParams[BuiltInCeiling]; -EnumParameters DimensionalityParams[DimensionCeiling]; -EnumParameters FuncParamAttrParams[FuncParamAttrCeiling]; -EnumParameters AccessQualifierParams[AccessQualifierCeiling]; -EnumParameters GroupOperationParams[GroupOperationCeiling]; EnumParameters LoopControlParams[FunctionControlCeiling]; EnumParameters SelectionControlParams[SelectControlCeiling]; EnumParameters FunctionControlParams[FunctionControlCeiling]; -EnumParameters MemorySemanticsParams[MemorySemanticsCeiling]; -EnumParameters MemoryAccessParams[MemoryAccessCeiling]; -EnumParameters ScopeParams[ScopeCeiling]; -EnumParameters KernelEnqueueFlagsParams[KernelEnqueueFlagsCeiling]; -EnumParameters KernelProfilingInfoParams[KernelProfilingInfoCeiling]; -EnumParameters CapabilityParams[CapabilityCeiling]; // Set up all the parameterizing descriptions of the opcodes, operands, etc. void Parameterize() @@ -1195,7 +1290,10 @@ void Parameterize() InstructionDesc[OpImageWrite].setResultAndType(false, false); InstructionDesc[OpDecorationGroup].setResultAndType(true, false); InstructionDesc[OpDecorate].setResultAndType(false, false); + InstructionDesc[OpDecorateId].setResultAndType(false, false); + InstructionDesc[OpDecorateStringGOOGLE].setResultAndType(false, false); InstructionDesc[OpMemberDecorate].setResultAndType(false, false); + InstructionDesc[OpMemberDecorateStringGOOGLE].setResultAndType(false, false); InstructionDesc[OpGroupDecorate].setResultAndType(false, false); InstructionDesc[OpGroupMemberDecorate].setResultAndType(false, false); InstructionDesc[OpName].setResultAndType(false, false); @@ -1234,6 +1332,7 @@ void Parameterize() InstructionDesc[OpReleaseEvent].setResultAndType(false, false); InstructionDesc[OpGroupWaitEvents].setResultAndType(false, false); InstructionDesc[OpAtomicFlagClear].setResultAndType(false, false); + InstructionDesc[OpModuleProcessed].setResultAndType(false, false); // Specific additional context-dependent operands @@ -1271,354 +1370,39 @@ void Parameterize() DecorationOperands[DecorationInputAttachmentIndex].push(OperandLiteralNumber, "'Attachment Index'"); DecorationOperands[DecorationAlignment].push(OperandLiteralNumber, "'Alignment'"); - OperandClassParams[OperandSource].set(SourceLanguageCeiling, SourceString, 0); - OperandClassParams[OperandExecutionModel].set(ExecutionModelCeiling, ExecutionModelString, ExecutionModelParams); - OperandClassParams[OperandAddressing].set(AddressingModelCeiling, AddressingString, AddressingParams); - OperandClassParams[OperandMemory].set(MemoryModelCeiling, MemoryString, MemoryParams); + OperandClassParams[OperandSource].set(0, SourceString, 0); + OperandClassParams[OperandExecutionModel].set(0, ExecutionModelString, nullptr); + OperandClassParams[OperandAddressing].set(0, AddressingString, nullptr); + OperandClassParams[OperandMemory].set(0, MemoryString, nullptr); OperandClassParams[OperandExecutionMode].set(ExecutionModeCeiling, ExecutionModeString, ExecutionModeParams); OperandClassParams[OperandExecutionMode].setOperands(ExecutionModeOperands); - OperandClassParams[OperandStorage].set(StorageClassCeiling, StorageClassString, StorageParams); - OperandClassParams[OperandDimensionality].set(DimensionCeiling, DimensionString, DimensionalityParams); - OperandClassParams[OperandSamplerAddressingMode].set(SamplerAddressingModeCeiling, SamplerAddressingModeString, SamplerAddressingModeParams); - OperandClassParams[OperandSamplerFilterMode].set(SamplerFilterModeCeiling, SamplerFilterModeString, SamplerFilterModeParams); - OperandClassParams[OperandSamplerImageFormat].set(ImageFormatCeiling, ImageFormatString, ImageFormatParams); - OperandClassParams[OperandImageChannelOrder].set(ImageChannelOrderCeiling, ImageChannelOrderString, ImageChannelOrderParams); - OperandClassParams[OperandImageChannelDataType].set(ImageChannelDataTypeCeiling, ImageChannelDataTypeString, ImageChannelDataTypeParams); + OperandClassParams[OperandStorage].set(0, StorageClassString, nullptr); + OperandClassParams[OperandDimensionality].set(0, DimensionString, nullptr); + OperandClassParams[OperandSamplerAddressingMode].set(0, SamplerAddressingModeString, nullptr); + OperandClassParams[OperandSamplerFilterMode].set(0, SamplerFilterModeString, nullptr); + OperandClassParams[OperandSamplerImageFormat].set(0, ImageFormatString, nullptr); + OperandClassParams[OperandImageChannelOrder].set(0, ImageChannelOrderString, nullptr); + OperandClassParams[OperandImageChannelDataType].set(0, ImageChannelDataTypeString, nullptr); OperandClassParams[OperandImageOperands].set(ImageOperandsCeiling, ImageOperandsString, ImageOperandsParams, true); - OperandClassParams[OperandFPFastMath].set(FPFastMathCeiling, FPFastMathString, FPFastMathParams, true); - OperandClassParams[OperandFPRoundingMode].set(FPRoundingModeCeiling, FPRoundingModeString, FPRoundingModeParams); - OperandClassParams[OperandLinkageType].set(LinkageTypeCeiling, LinkageTypeString, LinkageTypeParams); - OperandClassParams[OperandFuncParamAttr].set(FuncParamAttrCeiling, FuncParamAttrString, FuncParamAttrParams); - OperandClassParams[OperandAccessQualifier].set(AccessQualifierCeiling, AccessQualifierString, AccessQualifierParams); + OperandClassParams[OperandFPFastMath].set(0, FPFastMathString, nullptr, true); + OperandClassParams[OperandFPRoundingMode].set(0, FPRoundingModeString, nullptr); + OperandClassParams[OperandLinkageType].set(0, LinkageTypeString, nullptr); + OperandClassParams[OperandFuncParamAttr].set(0, FuncParamAttrString, nullptr); + OperandClassParams[OperandAccessQualifier].set(0, AccessQualifierString, nullptr); OperandClassParams[OperandDecoration].set(DecorationCeiling, DecorationString, DecorationParams); OperandClassParams[OperandDecoration].setOperands(DecorationOperands); - OperandClassParams[OperandBuiltIn].set(BuiltInCeiling, BuiltInString, BuiltInParams); + OperandClassParams[OperandBuiltIn].set(0, BuiltInString, nullptr); OperandClassParams[OperandSelect].set(SelectControlCeiling, SelectControlString, SelectionControlParams, true); OperandClassParams[OperandLoop].set(LoopControlCeiling, LoopControlString, LoopControlParams, true); OperandClassParams[OperandFunction].set(FunctionControlCeiling, FunctionControlString, FunctionControlParams, true); - OperandClassParams[OperandMemorySemantics].set(MemorySemanticsCeiling, MemorySemanticsString, MemorySemanticsParams, true); - OperandClassParams[OperandMemoryAccess].set(MemoryAccessCeiling, MemoryAccessString, MemoryAccessParams, true); - OperandClassParams[OperandScope].set(ScopeCeiling, ScopeString, ScopeParams); - OperandClassParams[OperandGroupOperation].set(GroupOperationCeiling, GroupOperationString, GroupOperationParams); - OperandClassParams[OperandKernelEnqueueFlags].set(KernelEnqueueFlagsCeiling, KernelEnqueueFlagsString, KernelEnqueueFlagsParams); - OperandClassParams[OperandKernelProfilingInfo].set(KernelProfilingInfoCeiling, KernelProfilingInfoString, KernelProfilingInfoParams, true); - OperandClassParams[OperandCapability].set(CapabilityCeiling, CapabilityString, CapabilityParams); - OperandClassParams[OperandOpcode].set(OpcodeCeiling, OpcodeString, 0); - - CapabilityParams[CapabilityShader].caps.push_back(CapabilityMatrix); - CapabilityParams[CapabilityGeometry].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityTessellation].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityVector16].caps.push_back(CapabilityKernel); - CapabilityParams[CapabilityFloat16Buffer].caps.push_back(CapabilityKernel); - CapabilityParams[CapabilityInt64Atomics].caps.push_back(CapabilityInt64); - CapabilityParams[CapabilityImageBasic].caps.push_back(CapabilityKernel); - CapabilityParams[CapabilityImageReadWrite].caps.push_back(CapabilityImageBasic); - CapabilityParams[CapabilityImageMipmap].caps.push_back(CapabilityImageBasic); - CapabilityParams[CapabilityPipes].caps.push_back(CapabilityKernel); - CapabilityParams[CapabilityDeviceEnqueue].caps.push_back(CapabilityKernel); - CapabilityParams[CapabilityLiteralSampler].caps.push_back(CapabilityKernel); - CapabilityParams[CapabilityAtomicStorage].caps.push_back(CapabilityShader); - CapabilityParams[CapabilitySampleRateShading].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityTessellationPointSize].caps.push_back(CapabilityTessellation); - CapabilityParams[CapabilityGeometryPointSize].caps.push_back(CapabilityGeometry); - CapabilityParams[CapabilityImageGatherExtended].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityStorageImageExtendedFormats].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityStorageImageMultisample].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityUniformBufferArrayDynamicIndexing].caps.push_back(CapabilityShader); - CapabilityParams[CapabilitySampledImageArrayDynamicIndexing].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityStorageBufferArrayDynamicIndexing].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityStorageImageArrayDynamicIndexing].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityClipDistance].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityCullDistance].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityGenericPointer].caps.push_back(CapabilityAddresses); - CapabilityParams[CapabilityInt8].caps.push_back(CapabilityKernel); - CapabilityParams[CapabilityInputAttachment].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityMinLod].caps.push_back(CapabilityShader); - CapabilityParams[CapabilitySparseResidency].caps.push_back(CapabilityShader); - CapabilityParams[CapabilitySampled1D].caps.push_back(CapabilityShader); - CapabilityParams[CapabilitySampledRect].caps.push_back(CapabilityShader); - CapabilityParams[CapabilitySampledBuffer].caps.push_back(CapabilityShader); - CapabilityParams[CapabilitySampledCubeArray].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityImageMSArray].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityImage1D].caps.push_back(CapabilitySampled1D); - CapabilityParams[CapabilityImageRect].caps.push_back(CapabilitySampledRect); - CapabilityParams[CapabilityImageBuffer].caps.push_back(CapabilitySampledBuffer); - CapabilityParams[CapabilityImageCubeArray].caps.push_back(CapabilitySampledCubeArray); - CapabilityParams[CapabilityImageQuery].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityDerivativeControl].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityInterpolationFunction].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityTransformFeedback].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityGeometryStreams].caps.push_back(CapabilityGeometry); - CapabilityParams[CapabilityStorageImageReadWithoutFormat].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityStorageImageWriteWithoutFormat].caps.push_back(CapabilityShader); - CapabilityParams[CapabilityMultiViewport].caps.push_back(CapabilityGeometry); - - AddressingParams[AddressingModelPhysical32].caps.push_back(CapabilityAddresses); - AddressingParams[AddressingModelPhysical64].caps.push_back(CapabilityAddresses); - - MemoryParams[MemoryModelSimple].caps.push_back(CapabilityShader); - MemoryParams[MemoryModelGLSL450].caps.push_back(CapabilityShader); - MemoryParams[MemoryModelOpenCL].caps.push_back(CapabilityKernel); - - MemorySemanticsParams[MemorySemanticsUniformMemoryShift].caps.push_back(CapabilityShader); - MemorySemanticsParams[MemorySemanticsAtomicCounterMemoryShift].caps.push_back(CapabilityAtomicStorage); - - ExecutionModelParams[ExecutionModelVertex].caps.push_back(CapabilityShader); - ExecutionModelParams[ExecutionModelTessellationControl].caps.push_back(CapabilityTessellation); - ExecutionModelParams[ExecutionModelTessellationEvaluation].caps.push_back(CapabilityTessellation); - ExecutionModelParams[ExecutionModelGeometry].caps.push_back(CapabilityGeometry); - ExecutionModelParams[ExecutionModelFragment].caps.push_back(CapabilityShader); - ExecutionModelParams[ExecutionModelGLCompute].caps.push_back(CapabilityShader); - ExecutionModelParams[ExecutionModelKernel].caps.push_back(CapabilityKernel); - - // Storage capabilites - StorageParams[StorageClassInput].caps.push_back(CapabilityShader); - StorageParams[StorageClassUniform].caps.push_back(CapabilityShader); - StorageParams[StorageClassOutput].caps.push_back(CapabilityShader); - StorageParams[StorageClassPrivate].caps.push_back(CapabilityShader); - StorageParams[StorageClassGeneric].caps.push_back(CapabilityKernel); - StorageParams[StorageClassAtomicCounter].caps.push_back(CapabilityAtomicStorage); - StorageParams[StorageClassPushConstant].caps.push_back(CapabilityShader); - - // Sampler Filter & Addressing mode capabilities - SamplerAddressingModeParams[SamplerAddressingModeNone].caps.push_back(CapabilityKernel); - SamplerAddressingModeParams[SamplerAddressingModeClampToEdge].caps.push_back(CapabilityKernel); - SamplerAddressingModeParams[SamplerAddressingModeClamp].caps.push_back(CapabilityKernel); - SamplerAddressingModeParams[SamplerAddressingModeRepeat].caps.push_back(CapabilityKernel); - SamplerAddressingModeParams[SamplerAddressingModeRepeatMirrored].caps.push_back(CapabilityKernel); - - SamplerFilterModeParams[SamplerFilterModeNearest].caps.push_back(CapabilityKernel); - SamplerFilterModeParams[SamplerFilterModeLinear].caps.push_back(CapabilityKernel); - - // image format capabilities - - // ES/Desktop float - ImageFormatParams[ImageFormatRgba32f].caps.push_back(CapabilityShader); - ImageFormatParams[ImageFormatRgba16f].caps.push_back(CapabilityShader); - ImageFormatParams[ImageFormatR32f].caps.push_back(CapabilityShader); - ImageFormatParams[ImageFormatRgba8].caps.push_back(CapabilityShader); - ImageFormatParams[ImageFormatRgba8Snorm].caps.push_back(CapabilityShader); - - // Desktop float - ImageFormatParams[ImageFormatRg32f].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatRg16f].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatR11fG11fB10f].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatR16f].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatRgba16].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatRgb10A2].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatRg16].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatRg8].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatR16].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatR8].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatRgba16Snorm].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatRg16Snorm].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatRg8Snorm].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatR16Snorm].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatR8Snorm].caps.push_back(CapabilityStorageImageExtendedFormats); - - // ES/Desktop int - ImageFormatParams[ImageFormatRgba32i].caps.push_back(CapabilityShader); - ImageFormatParams[ImageFormatRgba16i].caps.push_back(CapabilityShader); - ImageFormatParams[ImageFormatRgba8i].caps.push_back(CapabilityShader); - ImageFormatParams[ImageFormatR32i].caps.push_back(CapabilityShader); - - // Desktop int - ImageFormatParams[ImageFormatRg32i].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatRg16i].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatRg8i].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatR16i].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatR8i].caps.push_back(CapabilityStorageImageExtendedFormats); - - // ES/Desktop uint - ImageFormatParams[ImageFormatRgba32ui].caps.push_back(CapabilityShader); - ImageFormatParams[ImageFormatRgba16ui].caps.push_back(CapabilityShader); - ImageFormatParams[ImageFormatRgba8ui].caps.push_back(CapabilityShader); - ImageFormatParams[ImageFormatR32ui].caps.push_back(CapabilityShader); - - // Desktop uint - ImageFormatParams[ImageFormatRgb10a2ui].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatRg32ui].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatRg16ui].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatRg8ui].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatR16ui].caps.push_back(CapabilityStorageImageExtendedFormats); - ImageFormatParams[ImageFormatR8ui].caps.push_back(CapabilityStorageImageExtendedFormats); - - // image channel order capabilities - for (int i = 0; i < ImageChannelOrderCeiling; ++i) { - ImageChannelOrderParams[i].caps.push_back(CapabilityKernel); - } - - // image channel type capabilities - for (int i = 0; i < ImageChannelDataTypeCeiling; ++i) { - ImageChannelDataTypeParams[i].caps.push_back(CapabilityKernel); - } - - // image lookup operands - ImageOperandsParams[ImageOperandsBiasShift].caps.push_back(CapabilityShader); - ImageOperandsParams[ImageOperandsOffsetShift].caps.push_back(CapabilityImageGatherExtended); - ImageOperandsParams[ImageOperandsMinLodShift].caps.push_back(CapabilityMinLod); - - // fast math flags capabilities - for (int i = 0; i < FPFastMathCeiling; ++i) { - FPFastMathParams[i].caps.push_back(CapabilityKernel); - } - - // fp rounding mode capabilities - for (int i = 0; i < FPRoundingModeCeiling; ++i) { - FPRoundingModeParams[i].caps.push_back(CapabilityKernel); - } - - // linkage types - for (int i = 0; i < LinkageTypeCeiling; ++i) { - LinkageTypeParams[i].caps.push_back(CapabilityLinkage); - } - - // function argument types - for (int i = 0; i < FuncParamAttrCeiling; ++i) { - FuncParamAttrParams[i].caps.push_back(CapabilityKernel); - } - - // function argument types - for (int i = 0; i < AccessQualifierCeiling; ++i) { - AccessQualifierParams[i].caps.push_back(CapabilityKernel); - } - - ExecutionModeParams[ExecutionModeInvocations].caps.push_back(CapabilityGeometry); - ExecutionModeParams[ExecutionModeSpacingEqual].caps.push_back(CapabilityTessellation); - ExecutionModeParams[ExecutionModeSpacingFractionalEven].caps.push_back(CapabilityTessellation); - ExecutionModeParams[ExecutionModeSpacingFractionalOdd].caps.push_back(CapabilityTessellation); - ExecutionModeParams[ExecutionModeVertexOrderCw].caps.push_back(CapabilityTessellation); - ExecutionModeParams[ExecutionModeVertexOrderCcw].caps.push_back(CapabilityTessellation); - ExecutionModeParams[ExecutionModePixelCenterInteger].caps.push_back(CapabilityShader); - ExecutionModeParams[ExecutionModeOriginUpperLeft].caps.push_back(CapabilityShader); - ExecutionModeParams[ExecutionModeOriginLowerLeft].caps.push_back(CapabilityShader); - ExecutionModeParams[ExecutionModeEarlyFragmentTests].caps.push_back(CapabilityShader); - ExecutionModeParams[ExecutionModePointMode].caps.push_back(CapabilityTessellation); - ExecutionModeParams[ExecutionModeXfb].caps.push_back(CapabilityTransformFeedback); - ExecutionModeParams[ExecutionModeDepthReplacing].caps.push_back(CapabilityShader); - ExecutionModeParams[ExecutionModeDepthGreater].caps.push_back(CapabilityShader); - ExecutionModeParams[ExecutionModeDepthLess].caps.push_back(CapabilityShader); - ExecutionModeParams[ExecutionModeDepthUnchanged].caps.push_back(CapabilityShader); - ExecutionModeParams[ExecutionModeLocalSizeHint].caps.push_back(CapabilityKernel); - ExecutionModeParams[ExecutionModeInputPoints].caps.push_back(CapabilityGeometry); - ExecutionModeParams[ExecutionModeInputLines].caps.push_back(CapabilityGeometry); - ExecutionModeParams[ExecutionModeInputLinesAdjacency].caps.push_back(CapabilityGeometry); - ExecutionModeParams[ExecutionModeTriangles].caps.push_back(CapabilityGeometry); - ExecutionModeParams[ExecutionModeTriangles].caps.push_back(CapabilityTessellation); - ExecutionModeParams[ExecutionModeInputTrianglesAdjacency].caps.push_back(CapabilityGeometry); - ExecutionModeParams[ExecutionModeQuads].caps.push_back(CapabilityTessellation); - ExecutionModeParams[ExecutionModeIsolines].caps.push_back(CapabilityTessellation); - ExecutionModeParams[ExecutionModeOutputVertices].caps.push_back(CapabilityGeometry); - ExecutionModeParams[ExecutionModeOutputVertices].caps.push_back(CapabilityTessellation); - ExecutionModeParams[ExecutionModeOutputPoints].caps.push_back(CapabilityGeometry); - ExecutionModeParams[ExecutionModeOutputLineStrip].caps.push_back(CapabilityGeometry); - ExecutionModeParams[ExecutionModeOutputTriangleStrip].caps.push_back(CapabilityGeometry); - ExecutionModeParams[ExecutionModeVecTypeHint].caps.push_back(CapabilityKernel); - ExecutionModeParams[ExecutionModeContractionOff].caps.push_back(CapabilityKernel); - - DecorationParams[DecorationRelaxedPrecision].caps.push_back(CapabilityShader); - DecorationParams[DecorationBlock].caps.push_back(CapabilityShader); - DecorationParams[DecorationBufferBlock].caps.push_back(CapabilityShader); - DecorationParams[DecorationRowMajor].caps.push_back(CapabilityMatrix); - DecorationParams[DecorationColMajor].caps.push_back(CapabilityMatrix); - DecorationParams[DecorationGLSLShared].caps.push_back(CapabilityShader); - DecorationParams[DecorationGLSLPacked].caps.push_back(CapabilityShader); - DecorationParams[DecorationNoPerspective].caps.push_back(CapabilityShader); - DecorationParams[DecorationFlat].caps.push_back(CapabilityShader); - DecorationParams[DecorationPatch].caps.push_back(CapabilityTessellation); - DecorationParams[DecorationCentroid].caps.push_back(CapabilityShader); - DecorationParams[DecorationSample].caps.push_back(CapabilitySampleRateShading); - DecorationParams[DecorationInvariant].caps.push_back(CapabilityShader); - DecorationParams[DecorationConstant].caps.push_back(CapabilityKernel); - DecorationParams[DecorationUniform].caps.push_back(CapabilityShader); - DecorationParams[DecorationCPacked].caps.push_back(CapabilityKernel); - DecorationParams[DecorationSaturatedConversion].caps.push_back(CapabilityKernel); - DecorationParams[DecorationStream].caps.push_back(CapabilityGeometryStreams); - DecorationParams[DecorationLocation].caps.push_back(CapabilityShader); - DecorationParams[DecorationComponent].caps.push_back(CapabilityShader); - DecorationParams[DecorationOffset].caps.push_back(CapabilityShader); - DecorationParams[DecorationIndex].caps.push_back(CapabilityShader); - DecorationParams[DecorationBinding].caps.push_back(CapabilityShader); - DecorationParams[DecorationDescriptorSet].caps.push_back(CapabilityShader); - DecorationParams[DecorationXfbBuffer].caps.push_back(CapabilityTransformFeedback); - DecorationParams[DecorationXfbStride].caps.push_back(CapabilityTransformFeedback); - DecorationParams[DecorationArrayStride].caps.push_back(CapabilityShader); - DecorationParams[DecorationMatrixStride].caps.push_back(CapabilityMatrix); - DecorationParams[DecorationFuncParamAttr].caps.push_back(CapabilityKernel); - DecorationParams[DecorationFPRoundingMode].caps.push_back(CapabilityKernel); - DecorationParams[DecorationFPFastMathMode].caps.push_back(CapabilityKernel); - DecorationParams[DecorationLinkageAttributes].caps.push_back(CapabilityLinkage); - DecorationParams[DecorationSpecId].caps.push_back(CapabilityShader); - DecorationParams[DecorationNoContraction].caps.push_back(CapabilityShader); - DecorationParams[DecorationInputAttachmentIndex].caps.push_back(CapabilityInputAttachment); - DecorationParams[DecorationAlignment].caps.push_back(CapabilityKernel); - - BuiltInParams[BuiltInPosition].caps.push_back(CapabilityShader); - BuiltInParams[BuiltInPointSize].caps.push_back(CapabilityShader); - BuiltInParams[BuiltInClipDistance].caps.push_back(CapabilityClipDistance); - BuiltInParams[BuiltInCullDistance].caps.push_back(CapabilityCullDistance); - - BuiltInParams[BuiltInVertexId].caps.push_back(CapabilityShader); - BuiltInParams[BuiltInVertexId].desc = "Vertex ID, which takes on values 0, 1, 2, . . . ."; - - BuiltInParams[BuiltInInstanceId].caps.push_back(CapabilityShader); - BuiltInParams[BuiltInInstanceId].desc = "Instance ID, which takes on values 0, 1, 2, . . . ."; - - BuiltInParams[BuiltInVertexIndex].caps.push_back(CapabilityShader); - BuiltInParams[BuiltInVertexIndex].desc = "Vertex index, which takes on values base, base+1, base+2, . . . ."; - - BuiltInParams[BuiltInInstanceIndex].caps.push_back(CapabilityShader); - BuiltInParams[BuiltInInstanceIndex].desc = "Instance index, which takes on values base, base+1, base+2, . . . ."; - - BuiltInParams[BuiltInPrimitiveId].caps.push_back(CapabilityGeometry); - BuiltInParams[BuiltInPrimitiveId].caps.push_back(CapabilityTessellation); - BuiltInParams[BuiltInInvocationId].caps.push_back(CapabilityGeometry); - BuiltInParams[BuiltInInvocationId].caps.push_back(CapabilityTessellation); - BuiltInParams[BuiltInLayer].caps.push_back(CapabilityGeometry); - BuiltInParams[BuiltInViewportIndex].caps.push_back(CapabilityMultiViewport); - BuiltInParams[BuiltInTessLevelOuter].caps.push_back(CapabilityTessellation); - BuiltInParams[BuiltInTessLevelInner].caps.push_back(CapabilityTessellation); - BuiltInParams[BuiltInTessCoord].caps.push_back(CapabilityTessellation); - BuiltInParams[BuiltInPatchVertices].caps.push_back(CapabilityTessellation); - BuiltInParams[BuiltInFragCoord].caps.push_back(CapabilityShader); - BuiltInParams[BuiltInPointCoord].caps.push_back(CapabilityShader); - BuiltInParams[BuiltInFrontFacing].caps.push_back(CapabilityShader); - BuiltInParams[BuiltInSampleId].caps.push_back(CapabilitySampleRateShading); - BuiltInParams[BuiltInSamplePosition].caps.push_back(CapabilitySampleRateShading); - BuiltInParams[BuiltInSampleMask].caps.push_back(CapabilitySampleRateShading); - BuiltInParams[BuiltInFragDepth].caps.push_back(CapabilityShader); - BuiltInParams[BuiltInHelperInvocation].caps.push_back(CapabilityShader); - BuiltInParams[BuiltInWorkDim].caps.push_back(CapabilityKernel); - BuiltInParams[BuiltInGlobalSize].caps.push_back(CapabilityKernel); - BuiltInParams[BuiltInEnqueuedWorkgroupSize].caps.push_back(CapabilityKernel); - BuiltInParams[BuiltInGlobalOffset].caps.push_back(CapabilityKernel); - BuiltInParams[BuiltInGlobalLinearId].caps.push_back(CapabilityKernel); - - BuiltInParams[BuiltInSubgroupSize].caps.push_back(CapabilityKernel); - BuiltInParams[BuiltInSubgroupMaxSize].caps.push_back(CapabilityKernel); - BuiltInParams[BuiltInNumSubgroups].caps.push_back(CapabilityKernel); - BuiltInParams[BuiltInNumEnqueuedSubgroups].caps.push_back(CapabilityKernel); - BuiltInParams[BuiltInSubgroupId].caps.push_back(CapabilityKernel); - BuiltInParams[BuiltInSubgroupLocalInvocationId].caps.push_back(CapabilityKernel); - - DimensionalityParams[Dim1D].caps.push_back(CapabilitySampled1D); - DimensionalityParams[DimCube].caps.push_back(CapabilityShader); - DimensionalityParams[DimRect].caps.push_back(CapabilitySampledRect); - DimensionalityParams[DimBuffer].caps.push_back(CapabilitySampledBuffer); - DimensionalityParams[DimSubpassData].caps.push_back(CapabilityInputAttachment); - - // Group Operations - for (int i = 0; i < GroupOperationCeiling; ++i) { - GroupOperationParams[i].caps.push_back(CapabilityKernel); - } - - // Enqueue flags - for (int i = 0; i < KernelEnqueueFlagsCeiling; ++i) { - KernelEnqueueFlagsParams[i].caps.push_back(CapabilityKernel); - } - - // Profiling info - KernelProfilingInfoParams[0].caps.push_back(CapabilityKernel); + OperandClassParams[OperandMemorySemantics].set(0, MemorySemanticsString, nullptr, true); + OperandClassParams[OperandMemoryAccess].set(0, MemoryAccessString, nullptr, true); + OperandClassParams[OperandScope].set(0, ScopeString, nullptr); + OperandClassParams[OperandGroupOperation].set(0, GroupOperationString, nullptr); + OperandClassParams[OperandKernelEnqueueFlags].set(0, KernelEnqueueFlagsString, nullptr); + OperandClassParams[OperandKernelProfilingInfo].set(0, KernelProfilingInfoString, nullptr, true); + OperandClassParams[OperandCapability].set(0, CapabilityString, nullptr); + OperandClassParams[OperandOpcode].set(OpCodeMask + 1, OpcodeString, 0); // set name of operator, an initial set of style operands, and the description @@ -1670,7 +1454,6 @@ void Parameterize() InstructionDesc[OpTypeVector].operands.push(OperandId, "'Component Type'"); InstructionDesc[OpTypeVector].operands.push(OperandLiteralNumber, "'Component Count'"); - InstructionDesc[OpTypeMatrix].capabilities.push_back(CapabilityMatrix); InstructionDesc[OpTypeMatrix].operands.push(OperandId, "'Column Type'"); InstructionDesc[OpTypeMatrix].operands.push(OperandLiteralNumber, "'Column Count'"); @@ -1688,31 +1471,19 @@ void Parameterize() InstructionDesc[OpTypeArray].operands.push(OperandId, "'Element Type'"); InstructionDesc[OpTypeArray].operands.push(OperandId, "'Length'"); - InstructionDesc[OpTypeRuntimeArray].capabilities.push_back(CapabilityShader); InstructionDesc[OpTypeRuntimeArray].operands.push(OperandId, "'Element Type'"); InstructionDesc[OpTypeStruct].operands.push(OperandVariableIds, "'Member 0 type', +\n'member 1 type', +\n..."); - InstructionDesc[OpTypeOpaque].capabilities.push_back(CapabilityKernel); InstructionDesc[OpTypeOpaque].operands.push(OperandLiteralString, "The name of the opaque type."); InstructionDesc[OpTypePointer].operands.push(OperandStorage, ""); InstructionDesc[OpTypePointer].operands.push(OperandId, "'Type'"); - InstructionDesc[OpTypeForwardPointer].capabilities.push_back(CapabilityAddresses); InstructionDesc[OpTypeForwardPointer].operands.push(OperandId, "'Pointer Type'"); InstructionDesc[OpTypeForwardPointer].operands.push(OperandStorage, ""); - InstructionDesc[OpTypeEvent].capabilities.push_back(CapabilityKernel); - - InstructionDesc[OpTypeDeviceEvent].capabilities.push_back(CapabilityDeviceEnqueue); - - InstructionDesc[OpTypeReserveId].capabilities.push_back(CapabilityPipes); - - InstructionDesc[OpTypeQueue].capabilities.push_back(CapabilityDeviceEnqueue); - InstructionDesc[OpTypePipe].operands.push(OperandAccessQualifier, "'Qualifier'"); - InstructionDesc[OpTypePipe].capabilities.push_back(CapabilityPipes); InstructionDesc[OpTypeFunction].operands.push(OperandId, "'Return Type'"); InstructionDesc[OpTypeFunction].operands.push(OperandVariableIds, "'Parameter 0 Type', +\n'Parameter 1 Type', +\n..."); @@ -1721,7 +1492,6 @@ void Parameterize() InstructionDesc[OpConstantComposite].operands.push(OperandVariableIds, "'Constituents'"); - InstructionDesc[OpConstantSampler].capabilities.push_back(CapabilityLiteralSampler); InstructionDesc[OpConstantSampler].operands.push(OperandSamplerAddressingMode, ""); InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Param'"); InstructionDesc[OpConstantSampler].operands.push(OperandSamplerFilterMode, ""); @@ -1759,11 +1529,24 @@ void Parameterize() InstructionDesc[OpDecorate].operands.push(OperandDecoration, ""); InstructionDesc[OpDecorate].operands.push(OperandVariableLiterals, "See <>."); + InstructionDesc[OpDecorateId].operands.push(OperandId, "'Target'"); + InstructionDesc[OpDecorateId].operands.push(OperandDecoration, ""); + InstructionDesc[OpDecorateId].operands.push(OperandVariableIds, "See <>."); + + InstructionDesc[OpDecorateStringGOOGLE].operands.push(OperandId, "'Target'"); + InstructionDesc[OpDecorateStringGOOGLE].operands.push(OperandDecoration, ""); + InstructionDesc[OpDecorateStringGOOGLE].operands.push(OperandLiteralString, "'Literal String'"); + InstructionDesc[OpMemberDecorate].operands.push(OperandId, "'Structure Type'"); InstructionDesc[OpMemberDecorate].operands.push(OperandLiteralNumber, "'Member'"); InstructionDesc[OpMemberDecorate].operands.push(OperandDecoration, ""); InstructionDesc[OpMemberDecorate].operands.push(OperandVariableLiterals, "See <>."); + InstructionDesc[OpMemberDecorateStringGOOGLE].operands.push(OperandId, "'Structure Type'"); + InstructionDesc[OpMemberDecorateStringGOOGLE].operands.push(OperandLiteralNumber, "'Member'"); + InstructionDesc[OpMemberDecorateStringGOOGLE].operands.push(OperandDecoration, ""); + InstructionDesc[OpMemberDecorateStringGOOGLE].operands.push(OperandLiteralString, "'Literal String'"); + InstructionDesc[OpGroupDecorate].operands.push(OperandId, "'Decoration Group'"); InstructionDesc[OpGroupDecorate].operands.push(OperandVariableIds, "'Targets'"); @@ -1801,8 +1584,6 @@ void Parameterize() InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Size'"); InstructionDesc[OpCopyMemorySized].operands.push(OperandMemoryAccess, "", true); - InstructionDesc[OpCopyMemorySized].capabilities.push_back(CapabilityAddresses); - InstructionDesc[OpSampledImage].operands.push(OperandId, "'Image'"); InstructionDesc[OpSampledImage].operands.push(OperandId, "'Sampler'"); @@ -1823,7 +1604,6 @@ void Parameterize() InstructionDesc[OpImageSampleImplicitLod].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSampleImplicitLod].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSampleImplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSampleImplicitLod].capabilities.push_back(CapabilityShader); InstructionDesc[OpImageSampleExplicitLod].operands.push(OperandId, "'Sampled Image'"); InstructionDesc[OpImageSampleExplicitLod].operands.push(OperandId, "'Coordinate'"); @@ -1835,40 +1615,34 @@ void Parameterize() InstructionDesc[OpImageSampleDrefImplicitLod].operands.push(OperandId, "'D~ref~'"); InstructionDesc[OpImageSampleDrefImplicitLod].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSampleDrefImplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSampleDrefImplicitLod].capabilities.push_back(CapabilityShader); InstructionDesc[OpImageSampleDrefExplicitLod].operands.push(OperandId, "'Sampled Image'"); InstructionDesc[OpImageSampleDrefExplicitLod].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSampleDrefExplicitLod].operands.push(OperandId, "'D~ref~'"); InstructionDesc[OpImageSampleDrefExplicitLod].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSampleDrefExplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSampleDrefExplicitLod].capabilities.push_back(CapabilityShader); InstructionDesc[OpImageSampleProjImplicitLod].operands.push(OperandId, "'Sampled Image'"); InstructionDesc[OpImageSampleProjImplicitLod].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSampleProjImplicitLod].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSampleProjImplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSampleProjImplicitLod].capabilities.push_back(CapabilityShader); InstructionDesc[OpImageSampleProjExplicitLod].operands.push(OperandId, "'Sampled Image'"); InstructionDesc[OpImageSampleProjExplicitLod].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSampleProjExplicitLod].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSampleProjExplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSampleProjExplicitLod].capabilities.push_back(CapabilityShader); InstructionDesc[OpImageSampleProjDrefImplicitLod].operands.push(OperandId, "'Sampled Image'"); InstructionDesc[OpImageSampleProjDrefImplicitLod].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSampleProjDrefImplicitLod].operands.push(OperandId, "'D~ref~'"); InstructionDesc[OpImageSampleProjDrefImplicitLod].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSampleProjDrefImplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSampleProjDrefImplicitLod].capabilities.push_back(CapabilityShader); InstructionDesc[OpImageSampleProjDrefExplicitLod].operands.push(OperandId, "'Sampled Image'"); InstructionDesc[OpImageSampleProjDrefExplicitLod].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSampleProjDrefExplicitLod].operands.push(OperandId, "'D~ref~'"); InstructionDesc[OpImageSampleProjDrefExplicitLod].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSampleProjDrefExplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSampleProjDrefExplicitLod].capabilities.push_back(CapabilityShader); InstructionDesc[OpImageFetch].operands.push(OperandId, "'Image'"); InstructionDesc[OpImageFetch].operands.push(OperandId, "'Coordinate'"); @@ -1880,122 +1654,96 @@ void Parameterize() InstructionDesc[OpImageGather].operands.push(OperandId, "'Component'"); InstructionDesc[OpImageGather].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageGather].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageGather].capabilities.push_back(CapabilityShader); InstructionDesc[OpImageDrefGather].operands.push(OperandId, "'Sampled Image'"); InstructionDesc[OpImageDrefGather].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageDrefGather].operands.push(OperandId, "'D~ref~'"); InstructionDesc[OpImageDrefGather].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageDrefGather].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageDrefGather].capabilities.push_back(CapabilityShader); InstructionDesc[OpImageSparseSampleImplicitLod].operands.push(OperandId, "'Sampled Image'"); InstructionDesc[OpImageSparseSampleImplicitLod].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSparseSampleImplicitLod].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSparseSampleImplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseSampleImplicitLod].capabilities.push_back(CapabilitySparseResidency); InstructionDesc[OpImageSparseSampleExplicitLod].operands.push(OperandId, "'Sampled Image'"); InstructionDesc[OpImageSparseSampleExplicitLod].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSparseSampleExplicitLod].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSparseSampleExplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseSampleExplicitLod].capabilities.push_back(CapabilitySparseResidency); InstructionDesc[OpImageSparseSampleDrefImplicitLod].operands.push(OperandId, "'Sampled Image'"); InstructionDesc[OpImageSparseSampleDrefImplicitLod].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSparseSampleDrefImplicitLod].operands.push(OperandId, "'D~ref~'"); InstructionDesc[OpImageSparseSampleDrefImplicitLod].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSparseSampleDrefImplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseSampleDrefImplicitLod].capabilities.push_back(CapabilitySparseResidency); InstructionDesc[OpImageSparseSampleDrefExplicitLod].operands.push(OperandId, "'Sampled Image'"); InstructionDesc[OpImageSparseSampleDrefExplicitLod].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSparseSampleDrefExplicitLod].operands.push(OperandId, "'D~ref~'"); InstructionDesc[OpImageSparseSampleDrefExplicitLod].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSparseSampleDrefExplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseSampleDrefExplicitLod].capabilities.push_back(CapabilitySparseResidency); InstructionDesc[OpImageSparseSampleProjImplicitLod].operands.push(OperandId, "'Sampled Image'"); InstructionDesc[OpImageSparseSampleProjImplicitLod].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSparseSampleProjImplicitLod].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSparseSampleProjImplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseSampleProjImplicitLod].capabilities.push_back(CapabilitySparseResidency); InstructionDesc[OpImageSparseSampleProjExplicitLod].operands.push(OperandId, "'Sampled Image'"); InstructionDesc[OpImageSparseSampleProjExplicitLod].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSparseSampleProjExplicitLod].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSparseSampleProjExplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseSampleProjExplicitLod].capabilities.push_back(CapabilitySparseResidency); InstructionDesc[OpImageSparseSampleProjDrefImplicitLod].operands.push(OperandId, "'Sampled Image'"); InstructionDesc[OpImageSparseSampleProjDrefImplicitLod].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSparseSampleProjDrefImplicitLod].operands.push(OperandId, "'D~ref~'"); InstructionDesc[OpImageSparseSampleProjDrefImplicitLod].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSparseSampleProjDrefImplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseSampleProjDrefImplicitLod].capabilities.push_back(CapabilitySparseResidency); InstructionDesc[OpImageSparseSampleProjDrefExplicitLod].operands.push(OperandId, "'Sampled Image'"); InstructionDesc[OpImageSparseSampleProjDrefExplicitLod].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSparseSampleProjDrefExplicitLod].operands.push(OperandId, "'D~ref~'"); InstructionDesc[OpImageSparseSampleProjDrefExplicitLod].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSparseSampleProjDrefExplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseSampleProjDrefExplicitLod].capabilities.push_back(CapabilitySparseResidency); InstructionDesc[OpImageSparseFetch].operands.push(OperandId, "'Image'"); InstructionDesc[OpImageSparseFetch].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSparseFetch].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSparseFetch].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseFetch].capabilities.push_back(CapabilitySparseResidency); InstructionDesc[OpImageSparseGather].operands.push(OperandId, "'Sampled Image'"); InstructionDesc[OpImageSparseGather].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSparseGather].operands.push(OperandId, "'Component'"); InstructionDesc[OpImageSparseGather].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSparseGather].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseGather].capabilities.push_back(CapabilitySparseResidency); InstructionDesc[OpImageSparseDrefGather].operands.push(OperandId, "'Sampled Image'"); InstructionDesc[OpImageSparseDrefGather].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSparseDrefGather].operands.push(OperandId, "'D~ref~'"); InstructionDesc[OpImageSparseDrefGather].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSparseDrefGather].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseDrefGather].capabilities.push_back(CapabilitySparseResidency); InstructionDesc[OpImageSparseRead].operands.push(OperandId, "'Image'"); InstructionDesc[OpImageSparseRead].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSparseRead].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageSparseRead].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseRead].capabilities.push_back(CapabilitySparseResidency); InstructionDesc[OpImageSparseTexelsResident].operands.push(OperandId, "'Resident Code'"); - InstructionDesc[OpImageSparseTexelsResident].capabilities.push_back(CapabilitySparseResidency); InstructionDesc[OpImageQuerySizeLod].operands.push(OperandId, "'Image'"); InstructionDesc[OpImageQuerySizeLod].operands.push(OperandId, "'Level of Detail'"); - InstructionDesc[OpImageQuerySizeLod].capabilities.push_back(CapabilityKernel); - InstructionDesc[OpImageQuerySizeLod].capabilities.push_back(CapabilityImageQuery); InstructionDesc[OpImageQuerySize].operands.push(OperandId, "'Image'"); - InstructionDesc[OpImageQuerySize].capabilities.push_back(CapabilityKernel); - InstructionDesc[OpImageQuerySize].capabilities.push_back(CapabilityImageQuery); InstructionDesc[OpImageQueryLod].operands.push(OperandId, "'Image'"); InstructionDesc[OpImageQueryLod].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageQueryLod].capabilities.push_back(CapabilityImageQuery); InstructionDesc[OpImageQueryLevels].operands.push(OperandId, "'Image'"); - InstructionDesc[OpImageQueryLevels].capabilities.push_back(CapabilityKernel); - InstructionDesc[OpImageQueryLevels].capabilities.push_back(CapabilityImageQuery); InstructionDesc[OpImageQuerySamples].operands.push(OperandId, "'Image'"); - InstructionDesc[OpImageQuerySamples].capabilities.push_back(CapabilityKernel); - InstructionDesc[OpImageQuerySamples].capabilities.push_back(CapabilityImageQuery); InstructionDesc[OpImageQueryFormat].operands.push(OperandId, "'Image'"); - InstructionDesc[OpImageQueryFormat].capabilities.push_back(CapabilityKernel); InstructionDesc[OpImageQueryOrder].operands.push(OperandId, "'Image'"); - InstructionDesc[OpImageQueryOrder].capabilities.push_back(CapabilityKernel); InstructionDesc[OpAccessChain].operands.push(OperandId, "'Base'"); InstructionDesc[OpAccessChain].operands.push(OperandVariableIds, "'Indexes'"); @@ -2006,12 +1754,10 @@ void Parameterize() InstructionDesc[OpPtrAccessChain].operands.push(OperandId, "'Base'"); InstructionDesc[OpPtrAccessChain].operands.push(OperandId, "'Element'"); InstructionDesc[OpPtrAccessChain].operands.push(OperandVariableIds, "'Indexes'"); - InstructionDesc[OpPtrAccessChain].capabilities.push_back(CapabilityAddresses); InstructionDesc[OpInBoundsPtrAccessChain].operands.push(OperandId, "'Base'"); InstructionDesc[OpInBoundsPtrAccessChain].operands.push(OperandId, "'Element'"); InstructionDesc[OpInBoundsPtrAccessChain].operands.push(OperandVariableIds, "'Indexes'"); - InstructionDesc[OpInBoundsPtrAccessChain].capabilities.push_back(CapabilityAddresses); InstructionDesc[OpSNegate].operands.push(OperandId, "'Operand'"); @@ -2038,65 +1784,49 @@ void Parameterize() InstructionDesc[OpFConvert].operands.push(OperandId, "'Float Value'"); InstructionDesc[OpSatConvertSToU].operands.push(OperandId, "'Signed Value'"); - InstructionDesc[OpSatConvertSToU].capabilities.push_back(CapabilityKernel); InstructionDesc[OpSatConvertUToS].operands.push(OperandId, "'Unsigned Value'"); - InstructionDesc[OpSatConvertUToS].capabilities.push_back(CapabilityKernel); InstructionDesc[OpConvertPtrToU].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpConvertPtrToU].capabilities.push_back(CapabilityAddresses); InstructionDesc[OpConvertUToPtr].operands.push(OperandId, "'Integer Value'"); - InstructionDesc[OpConvertUToPtr].capabilities.push_back(CapabilityAddresses); InstructionDesc[OpPtrCastToGeneric].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpPtrCastToGeneric].capabilities.push_back(CapabilityKernel); InstructionDesc[OpGenericCastToPtr].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpGenericCastToPtr].capabilities.push_back(CapabilityKernel); InstructionDesc[OpGenericCastToPtrExplicit].operands.push(OperandId, "'Pointer'"); InstructionDesc[OpGenericCastToPtrExplicit].operands.push(OperandStorage, "'Storage'"); - InstructionDesc[OpGenericCastToPtrExplicit].capabilities.push_back(CapabilityKernel); InstructionDesc[OpGenericPtrMemSemantics].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpGenericPtrMemSemantics].capabilities.push_back(CapabilityKernel); InstructionDesc[OpBitcast].operands.push(OperandId, "'Operand'"); InstructionDesc[OpQuantizeToF16].operands.push(OperandId, "'Value'"); - InstructionDesc[OpTranspose].capabilities.push_back(CapabilityMatrix); InstructionDesc[OpTranspose].operands.push(OperandId, "'Matrix'"); InstructionDesc[OpIsNan].operands.push(OperandId, "'x'"); InstructionDesc[OpIsInf].operands.push(OperandId, "'x'"); - InstructionDesc[OpIsFinite].capabilities.push_back(CapabilityKernel); InstructionDesc[OpIsFinite].operands.push(OperandId, "'x'"); - InstructionDesc[OpIsNormal].capabilities.push_back(CapabilityKernel); InstructionDesc[OpIsNormal].operands.push(OperandId, "'x'"); - InstructionDesc[OpSignBitSet].capabilities.push_back(CapabilityKernel); InstructionDesc[OpSignBitSet].operands.push(OperandId, "'x'"); - InstructionDesc[OpLessOrGreater].capabilities.push_back(CapabilityKernel); InstructionDesc[OpLessOrGreater].operands.push(OperandId, "'x'"); InstructionDesc[OpLessOrGreater].operands.push(OperandId, "'y'"); - InstructionDesc[OpOrdered].capabilities.push_back(CapabilityKernel); InstructionDesc[OpOrdered].operands.push(OperandId, "'x'"); InstructionDesc[OpOrdered].operands.push(OperandId, "'y'"); - InstructionDesc[OpUnordered].capabilities.push_back(CapabilityKernel); InstructionDesc[OpUnordered].operands.push(OperandId, "'x'"); InstructionDesc[OpUnordered].operands.push(OperandId, "'y'"); InstructionDesc[OpArrayLength].operands.push(OperandId, "'Structure'"); InstructionDesc[OpArrayLength].operands.push(OperandLiteralNumber, "'Array member'"); - InstructionDesc[OpArrayLength].capabilities.push_back(CapabilityShader); InstructionDesc[OpIAdd].operands.push(OperandId, "'Operand 1'"); InstructionDesc[OpIAdd].operands.push(OperandId, "'Operand 2'"); @@ -2143,23 +1873,18 @@ void Parameterize() InstructionDesc[OpVectorTimesScalar].operands.push(OperandId, "'Vector'"); InstructionDesc[OpVectorTimesScalar].operands.push(OperandId, "'Scalar'"); - InstructionDesc[OpMatrixTimesScalar].capabilities.push_back(CapabilityMatrix); InstructionDesc[OpMatrixTimesScalar].operands.push(OperandId, "'Matrix'"); InstructionDesc[OpMatrixTimesScalar].operands.push(OperandId, "'Scalar'"); - InstructionDesc[OpVectorTimesMatrix].capabilities.push_back(CapabilityMatrix); InstructionDesc[OpVectorTimesMatrix].operands.push(OperandId, "'Vector'"); InstructionDesc[OpVectorTimesMatrix].operands.push(OperandId, "'Matrix'"); - InstructionDesc[OpMatrixTimesVector].capabilities.push_back(CapabilityMatrix); InstructionDesc[OpMatrixTimesVector].operands.push(OperandId, "'Matrix'"); InstructionDesc[OpMatrixTimesVector].operands.push(OperandId, "'Vector'"); - InstructionDesc[OpMatrixTimesMatrix].capabilities.push_back(CapabilityMatrix); InstructionDesc[OpMatrixTimesMatrix].operands.push(OperandId, "'LeftMatrix'"); InstructionDesc[OpMatrixTimesMatrix].operands.push(OperandId, "'RightMatrix'"); - InstructionDesc[OpOuterProduct].capabilities.push_back(CapabilityMatrix); InstructionDesc[OpOuterProduct].operands.push(OperandId, "'Vector 1'"); InstructionDesc[OpOuterProduct].operands.push(OperandId, "'Vector 2'"); @@ -2210,23 +1935,19 @@ void Parameterize() InstructionDesc[OpBitwiseAnd].operands.push(OperandId, "'Operand 1'"); InstructionDesc[OpBitwiseAnd].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpBitFieldInsert].capabilities.push_back(CapabilityShader); InstructionDesc[OpBitFieldInsert].operands.push(OperandId, "'Base'"); InstructionDesc[OpBitFieldInsert].operands.push(OperandId, "'Insert'"); InstructionDesc[OpBitFieldInsert].operands.push(OperandId, "'Offset'"); InstructionDesc[OpBitFieldInsert].operands.push(OperandId, "'Count'"); - - InstructionDesc[OpBitFieldSExtract].capabilities.push_back(CapabilityShader); + InstructionDesc[OpBitFieldSExtract].operands.push(OperandId, "'Base'"); InstructionDesc[OpBitFieldSExtract].operands.push(OperandId, "'Offset'"); InstructionDesc[OpBitFieldSExtract].operands.push(OperandId, "'Count'"); - InstructionDesc[OpBitFieldUExtract].capabilities.push_back(CapabilityShader); InstructionDesc[OpBitFieldUExtract].operands.push(OperandId, "'Base'"); InstructionDesc[OpBitFieldUExtract].operands.push(OperandId, "'Offset'"); InstructionDesc[OpBitFieldUExtract].operands.push(OperandId, "'Count'"); - InstructionDesc[OpBitReverse].capabilities.push_back(CapabilityShader); InstructionDesc[OpBitReverse].operands.push(OperandId, "'Base'"); InstructionDesc[OpBitCount].operands.push(OperandId, "'Base'"); @@ -2301,42 +2022,27 @@ void Parameterize() InstructionDesc[OpFUnordGreaterThanEqual].operands.push(OperandId, "'Operand 1'"); InstructionDesc[OpFUnordGreaterThanEqual].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpDPdx].capabilities.push_back(CapabilityShader); InstructionDesc[OpDPdx].operands.push(OperandId, "'P'"); - InstructionDesc[OpDPdy].capabilities.push_back(CapabilityShader); InstructionDesc[OpDPdy].operands.push(OperandId, "'P'"); - InstructionDesc[OpFwidth].capabilities.push_back(CapabilityShader); InstructionDesc[OpFwidth].operands.push(OperandId, "'P'"); - InstructionDesc[OpDPdxFine].capabilities.push_back(CapabilityDerivativeControl); InstructionDesc[OpDPdxFine].operands.push(OperandId, "'P'"); - InstructionDesc[OpDPdyFine].capabilities.push_back(CapabilityDerivativeControl); InstructionDesc[OpDPdyFine].operands.push(OperandId, "'P'"); - InstructionDesc[OpFwidthFine].capabilities.push_back(CapabilityDerivativeControl); InstructionDesc[OpFwidthFine].operands.push(OperandId, "'P'"); - InstructionDesc[OpDPdxCoarse].capabilities.push_back(CapabilityDerivativeControl); InstructionDesc[OpDPdxCoarse].operands.push(OperandId, "'P'"); - InstructionDesc[OpDPdyCoarse].capabilities.push_back(CapabilityDerivativeControl); InstructionDesc[OpDPdyCoarse].operands.push(OperandId, "'P'"); - InstructionDesc[OpFwidthCoarse].capabilities.push_back(CapabilityDerivativeControl); InstructionDesc[OpFwidthCoarse].operands.push(OperandId, "'P'"); - InstructionDesc[OpEmitVertex].capabilities.push_back(CapabilityGeometry); - - InstructionDesc[OpEndPrimitive].capabilities.push_back(CapabilityGeometry); - InstructionDesc[OpEmitStreamVertex].operands.push(OperandId, "'Stream'"); - InstructionDesc[OpEmitStreamVertex].capabilities.push_back(CapabilityGeometryStreams); InstructionDesc[OpEndStreamPrimitive].operands.push(OperandId, "'Stream'"); - InstructionDesc[OpEndStreamPrimitive].capabilities.push_back(CapabilityGeometryStreams); InstructionDesc[OpControlBarrier].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpControlBarrier].operands.push(OperandScope, "'Memory'"); @@ -2376,7 +2082,6 @@ void Parameterize() InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandMemorySemantics, "'Unequal'"); InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Value'"); InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Comparator'"); - InstructionDesc[OpAtomicCompareExchangeWeak].capabilities.push_back(CapabilityKernel); InstructionDesc[OpAtomicIIncrement].operands.push(OperandId, "'Pointer'"); InstructionDesc[OpAtomicIIncrement].operands.push(OperandScope, "'Scope'"); @@ -2434,16 +2139,15 @@ void Parameterize() InstructionDesc[OpAtomicFlagTestAndSet].operands.push(OperandId, "'Pointer'"); InstructionDesc[OpAtomicFlagTestAndSet].operands.push(OperandScope, "'Scope'"); InstructionDesc[OpAtomicFlagTestAndSet].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicFlagTestAndSet].capabilities.push_back(CapabilityKernel); InstructionDesc[OpAtomicFlagClear].operands.push(OperandId, "'Pointer'"); InstructionDesc[OpAtomicFlagClear].operands.push(OperandScope, "'Scope'"); InstructionDesc[OpAtomicFlagClear].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicFlagClear].capabilities.push_back(CapabilityKernel); InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Merge Block'"); InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Continue Target'"); InstructionDesc[OpLoopMerge].operands.push(OperandLoop, ""); + InstructionDesc[OpLoopMerge].operands.push(OperandOptionalLiteral, ""); InstructionDesc[OpSelectionMerge].operands.push(OperandId, "'Merge Block'"); InstructionDesc[OpSelectionMerge].operands.push(OperandSelect, ""); @@ -2459,19 +2163,15 @@ void Parameterize() InstructionDesc[OpSwitch].operands.push(OperandId, "'Default'"); InstructionDesc[OpSwitch].operands.push(OperandVariableLiteralId, "'Target'"); - InstructionDesc[OpKill].capabilities.push_back(CapabilityShader); InstructionDesc[OpReturnValue].operands.push(OperandId, "'Value'"); InstructionDesc[OpLifetimeStart].operands.push(OperandId, "'Pointer'"); InstructionDesc[OpLifetimeStart].operands.push(OperandLiteralNumber, "'Size'"); - InstructionDesc[OpLifetimeStart].capabilities.push_back(CapabilityKernel); InstructionDesc[OpLifetimeStop].operands.push(OperandId, "'Pointer'"); InstructionDesc[OpLifetimeStop].operands.push(OperandLiteralNumber, "'Size'"); - InstructionDesc[OpLifetimeStop].capabilities.push_back(CapabilityKernel); - InstructionDesc[OpGroupAsyncCopy].capabilities.push_back(CapabilityKernel); InstructionDesc[OpGroupAsyncCopy].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupAsyncCopy].operands.push(OperandId, "'Destination'"); InstructionDesc[OpGroupAsyncCopy].operands.push(OperandId, "'Source'"); @@ -2479,77 +2179,62 @@ void Parameterize() InstructionDesc[OpGroupAsyncCopy].operands.push(OperandId, "'Stride'"); InstructionDesc[OpGroupAsyncCopy].operands.push(OperandId, "'Event'"); - InstructionDesc[OpGroupWaitEvents].capabilities.push_back(CapabilityKernel); InstructionDesc[OpGroupWaitEvents].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupWaitEvents].operands.push(OperandId, "'Num Events'"); InstructionDesc[OpGroupWaitEvents].operands.push(OperandId, "'Events List'"); - InstructionDesc[OpGroupAll].capabilities.push_back(CapabilityGroups); InstructionDesc[OpGroupAll].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupAll].operands.push(OperandId, "'Predicate'"); - InstructionDesc[OpGroupAny].capabilities.push_back(CapabilityGroups); InstructionDesc[OpGroupAny].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupAny].operands.push(OperandId, "'Predicate'"); - InstructionDesc[OpGroupBroadcast].capabilities.push_back(CapabilityGroups); InstructionDesc[OpGroupBroadcast].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupBroadcast].operands.push(OperandId, "'Value'"); InstructionDesc[OpGroupBroadcast].operands.push(OperandId, "'LocalId'"); - InstructionDesc[OpGroupIAdd].capabilities.push_back(CapabilityGroups); InstructionDesc[OpGroupIAdd].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupIAdd].operands.push(OperandGroupOperation, "'Operation'"); InstructionDesc[OpGroupIAdd].operands.push(OperandId, "'X'"); - InstructionDesc[OpGroupFAdd].capabilities.push_back(CapabilityGroups); InstructionDesc[OpGroupFAdd].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupFAdd].operands.push(OperandGroupOperation, "'Operation'"); InstructionDesc[OpGroupFAdd].operands.push(OperandId, "'X'"); - InstructionDesc[OpGroupUMin].capabilities.push_back(CapabilityGroups); InstructionDesc[OpGroupUMin].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupUMin].operands.push(OperandGroupOperation, "'Operation'"); InstructionDesc[OpGroupUMin].operands.push(OperandId, "'X'"); - InstructionDesc[OpGroupSMin].capabilities.push_back(CapabilityGroups); InstructionDesc[OpGroupSMin].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupSMin].operands.push(OperandGroupOperation, "'Operation'"); InstructionDesc[OpGroupSMin].operands.push(OperandId, "X"); - InstructionDesc[OpGroupFMin].capabilities.push_back(CapabilityGroups); InstructionDesc[OpGroupFMin].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupFMin].operands.push(OperandGroupOperation, "'Operation'"); InstructionDesc[OpGroupFMin].operands.push(OperandId, "X"); - InstructionDesc[OpGroupUMax].capabilities.push_back(CapabilityGroups); InstructionDesc[OpGroupUMax].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupUMax].operands.push(OperandGroupOperation, "'Operation'"); InstructionDesc[OpGroupUMax].operands.push(OperandId, "X"); - InstructionDesc[OpGroupSMax].capabilities.push_back(CapabilityGroups); InstructionDesc[OpGroupSMax].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupSMax].operands.push(OperandGroupOperation, "'Operation'"); InstructionDesc[OpGroupSMax].operands.push(OperandId, "X"); - InstructionDesc[OpGroupFMax].capabilities.push_back(CapabilityGroups); InstructionDesc[OpGroupFMax].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupFMax].operands.push(OperandGroupOperation, "'Operation'"); InstructionDesc[OpGroupFMax].operands.push(OperandId, "X"); - InstructionDesc[OpReadPipe].capabilities.push_back(CapabilityPipes); InstructionDesc[OpReadPipe].operands.push(OperandId, "'Pipe'"); InstructionDesc[OpReadPipe].operands.push(OperandId, "'Pointer'"); InstructionDesc[OpReadPipe].operands.push(OperandId, "'Packet Size'"); InstructionDesc[OpReadPipe].operands.push(OperandId, "'Packet Alignment'"); - InstructionDesc[OpWritePipe].capabilities.push_back(CapabilityPipes); InstructionDesc[OpWritePipe].operands.push(OperandId, "'Pipe'"); InstructionDesc[OpWritePipe].operands.push(OperandId, "'Pointer'"); InstructionDesc[OpWritePipe].operands.push(OperandId, "'Packet Size'"); InstructionDesc[OpWritePipe].operands.push(OperandId, "'Packet Alignment'"); - InstructionDesc[OpReservedReadPipe].capabilities.push_back(CapabilityPipes); InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'Pipe'"); InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'Reserve Id'"); InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'Index'"); @@ -2557,7 +2242,6 @@ void Parameterize() InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'Packet Size'"); InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'Packet Alignment'"); - InstructionDesc[OpReservedWritePipe].capabilities.push_back(CapabilityPipes); InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'Pipe'"); InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'Reserve Id'"); InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'Index'"); @@ -2565,127 +2249,99 @@ void Parameterize() InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'Packet Size'"); InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'Packet Alignment'"); - InstructionDesc[OpReserveReadPipePackets].capabilities.push_back(CapabilityPipes); InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'Pipe'"); InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'Num Packets'"); InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'Packet Size'"); InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'Packet Alignment'"); - InstructionDesc[OpReserveWritePipePackets].capabilities.push_back(CapabilityPipes); InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'Pipe'"); InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'Num Packets'"); InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'Packet Size'"); InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'Packet Alignment'"); - InstructionDesc[OpCommitReadPipe].capabilities.push_back(CapabilityPipes); InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'Pipe'"); InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'Reserve Id'"); InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'Packet Size'"); InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'Packet Alignment'"); - InstructionDesc[OpCommitWritePipe].capabilities.push_back(CapabilityPipes); InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'Pipe'"); InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'Reserve Id'"); InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'Packet Size'"); InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'Packet Alignment'"); - InstructionDesc[OpIsValidReserveId].capabilities.push_back(CapabilityPipes); InstructionDesc[OpIsValidReserveId].operands.push(OperandId, "'Reserve Id'"); - InstructionDesc[OpGetNumPipePackets].capabilities.push_back(CapabilityPipes); InstructionDesc[OpGetNumPipePackets].operands.push(OperandId, "'Pipe'"); InstructionDesc[OpGetNumPipePackets].operands.push(OperandId, "'Packet Size'"); InstructionDesc[OpGetNumPipePackets].operands.push(OperandId, "'Packet Alignment'"); - InstructionDesc[OpGetMaxPipePackets].capabilities.push_back(CapabilityPipes); InstructionDesc[OpGetMaxPipePackets].operands.push(OperandId, "'Pipe'"); InstructionDesc[OpGetMaxPipePackets].operands.push(OperandId, "'Packet Size'"); InstructionDesc[OpGetMaxPipePackets].operands.push(OperandId, "'Packet Alignment'"); - InstructionDesc[OpGroupReserveReadPipePackets].capabilities.push_back(CapabilityPipes); InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'Pipe'"); InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'Num Packets'"); InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'Packet Size'"); InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'Packet Alignment'"); - InstructionDesc[OpGroupReserveWritePipePackets].capabilities.push_back(CapabilityPipes); InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'Pipe'"); InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'Num Packets'"); InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'Packet Size'"); InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'Packet Alignment'"); - InstructionDesc[OpGroupCommitReadPipe].capabilities.push_back(CapabilityPipes); InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'Pipe'"); InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'Reserve Id'"); InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'Packet Size'"); InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'Packet Alignment'"); - InstructionDesc[OpGroupCommitWritePipe].capabilities.push_back(CapabilityPipes); InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'Pipe'"); InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'Reserve Id'"); InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'Packet Size'"); InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'Packet Alignment'"); - InstructionDesc[OpBuildNDRange].capabilities.push_back(CapabilityDeviceEnqueue); InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'GlobalWorkSize'"); InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'LocalWorkSize'"); InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'GlobalWorkOffset'"); - InstructionDesc[OpGetDefaultQueue].capabilities.push_back(CapabilityDeviceEnqueue); - - InstructionDesc[OpCaptureEventProfilingInfo].capabilities.push_back(CapabilityDeviceEnqueue); - InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'Event'"); InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'Profiling Info'"); InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'Value'"); - InstructionDesc[OpSetUserEventStatus].capabilities.push_back(CapabilityDeviceEnqueue); - InstructionDesc[OpSetUserEventStatus].operands.push(OperandId, "'Event'"); InstructionDesc[OpSetUserEventStatus].operands.push(OperandId, "'Status'"); - InstructionDesc[OpIsValidEvent].capabilities.push_back(CapabilityDeviceEnqueue); InstructionDesc[OpIsValidEvent].operands.push(OperandId, "'Event'"); - InstructionDesc[OpCreateUserEvent].capabilities.push_back(CapabilityDeviceEnqueue); - - InstructionDesc[OpRetainEvent].capabilities.push_back(CapabilityDeviceEnqueue); InstructionDesc[OpRetainEvent].operands.push(OperandId, "'Event'"); - InstructionDesc[OpReleaseEvent].capabilities.push_back(CapabilityDeviceEnqueue); InstructionDesc[OpReleaseEvent].operands.push(OperandId, "'Event'"); - InstructionDesc[OpGetKernelWorkGroupSize].capabilities.push_back(CapabilityDeviceEnqueue); InstructionDesc[OpGetKernelWorkGroupSize].operands.push(OperandId, "'Invoke'"); InstructionDesc[OpGetKernelWorkGroupSize].operands.push(OperandId, "'Param'"); InstructionDesc[OpGetKernelWorkGroupSize].operands.push(OperandId, "'Param Size'"); InstructionDesc[OpGetKernelWorkGroupSize].operands.push(OperandId, "'Param Align'"); - InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].capabilities.push_back(CapabilityDeviceEnqueue); InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].operands.push(OperandId, "'Invoke'"); InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].operands.push(OperandId, "'Param'"); InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].operands.push(OperandId, "'Param Size'"); InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].operands.push(OperandId, "'Param Align'"); - InstructionDesc[OpGetKernelNDrangeSubGroupCount].capabilities.push_back(CapabilityDeviceEnqueue); InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'ND Range'"); InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'Invoke'"); InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'Param'"); InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'Param Size'"); InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'Param Align'"); - InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].capabilities.push_back(CapabilityDeviceEnqueue); InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'ND Range'"); InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'Invoke'"); InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'Param'"); InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'Param Size'"); InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'Param Align'"); - InstructionDesc[OpEnqueueKernel].capabilities.push_back(CapabilityDeviceEnqueue); InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Queue'"); InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Flags'"); InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'ND Range'"); @@ -2698,11 +2354,215 @@ void Parameterize() InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param Align'"); InstructionDesc[OpEnqueueKernel].operands.push(OperandVariableIds, "'Local Size'"); - InstructionDesc[OpEnqueueMarker].capabilities.push_back(CapabilityDeviceEnqueue); InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Queue'"); InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Num Events'"); InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Wait Events'"); InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Ret Event'"); + + InstructionDesc[OpGroupNonUniformElect].operands.push(OperandScope, "'Execution'"); + + InstructionDesc[OpGroupNonUniformAll].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformAll].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformAny].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformAny].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformAllEqual].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformAllEqual].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformBroadcast].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBroadcast].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformBroadcast].operands.push(OperandId, "ID"); + + InstructionDesc[OpGroupNonUniformBroadcastFirst].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBroadcastFirst].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformBallot].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBallot].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformInverseBallot].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformInverseBallot].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformBallotBitExtract].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBallotBitExtract].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformBallotBitExtract].operands.push(OperandId, "Bit"); + + InstructionDesc[OpGroupNonUniformBallotBitCount].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBallotBitCount].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformBallotBitCount].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformBallotFindLSB].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBallotFindLSB].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformBallotFindMSB].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBallotFindMSB].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformShuffle].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformShuffle].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformShuffle].operands.push(OperandId, "'Id'"); + + InstructionDesc[OpGroupNonUniformShuffleXor].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformShuffleXor].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformShuffleXor].operands.push(OperandId, "Mask"); + + InstructionDesc[OpGroupNonUniformShuffleUp].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformShuffleUp].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformShuffleUp].operands.push(OperandId, "Offset"); + + InstructionDesc[OpGroupNonUniformShuffleDown].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformShuffleDown].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformShuffleDown].operands.push(OperandId, "Offset"); + + InstructionDesc[OpGroupNonUniformIAdd].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformIAdd].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformIAdd].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformIAdd].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformFAdd].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformFAdd].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformFAdd].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformFAdd].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformIMul].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformIMul].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformIMul].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformIMul].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformFMul].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformFMul].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformFMul].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformFMul].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformSMin].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformSMin].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformSMin].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformSMin].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformUMin].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformUMin].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformUMin].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformUMin].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformFMin].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformFMin].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformFMin].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformFMin].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformSMax].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformSMax].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformSMax].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformSMax].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformUMax].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformUMax].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformUMax].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformUMax].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformFMax].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformFMax].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformFMax].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformFMax].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformBitwiseAnd].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBitwiseAnd].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformBitwiseAnd].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformBitwiseAnd].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformBitwiseOr].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBitwiseOr].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformBitwiseOr].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformBitwiseOr].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformBitwiseXor].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBitwiseXor].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformBitwiseXor].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformBitwiseXor].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformLogicalAnd].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformLogicalAnd].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformLogicalAnd].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformLogicalAnd].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformLogicalOr].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformLogicalOr].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformLogicalOr].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformLogicalOr].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformLogicalXor].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformLogicalXor].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformLogicalXor].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformLogicalXor].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformQuadBroadcast].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformQuadBroadcast].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformQuadBroadcast].operands.push(OperandId, "'Id'"); + + InstructionDesc[OpGroupNonUniformQuadSwap].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformQuadSwap].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformQuadSwap].operands.push(OperandLiteralNumber, "'Direction'"); + + InstructionDesc[OpSubgroupBallotKHR].operands.push(OperandId, "'Predicate'"); + + InstructionDesc[OpSubgroupFirstInvocationKHR].operands.push(OperandId, "'Value'"); + + InstructionDesc[OpSubgroupAnyKHR].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpSubgroupAnyKHR].operands.push(OperandId, "'Predicate'"); + + InstructionDesc[OpSubgroupAllKHR].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpSubgroupAllKHR].operands.push(OperandId, "'Predicate'"); + + InstructionDesc[OpSubgroupAllEqualKHR].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpSubgroupAllEqualKHR].operands.push(OperandId, "'Predicate'"); + + InstructionDesc[OpSubgroupReadInvocationKHR].operands.push(OperandId, "'Value'"); + InstructionDesc[OpSubgroupReadInvocationKHR].operands.push(OperandId, "'Index'"); + + InstructionDesc[OpModuleProcessed].operands.push(OperandLiteralString, "'process'"); + +#ifdef AMD_EXTENSIONS + InstructionDesc[OpGroupIAddNonUniformAMD].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupIAddNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupIAddNonUniformAMD].operands.push(OperandId, "'X'"); + + InstructionDesc[OpGroupFAddNonUniformAMD].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupFAddNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupFAddNonUniformAMD].operands.push(OperandId, "'X'"); + + InstructionDesc[OpGroupUMinNonUniformAMD].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupUMinNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupUMinNonUniformAMD].operands.push(OperandId, "'X'"); + + InstructionDesc[OpGroupSMinNonUniformAMD].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupSMinNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupSMinNonUniformAMD].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupFMinNonUniformAMD].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupFMinNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupFMinNonUniformAMD].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupUMaxNonUniformAMD].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupUMaxNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupUMaxNonUniformAMD].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupSMaxNonUniformAMD].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupSMaxNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupSMaxNonUniformAMD].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupFMaxNonUniformAMD].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupFMaxNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupFMaxNonUniformAMD].operands.push(OperandId, "X"); + + InstructionDesc[OpFragmentMaskFetchAMD].operands.push(OperandId, "'Image'"); + InstructionDesc[OpFragmentMaskFetchAMD].operands.push(OperandId, "'Coordinate'"); + + InstructionDesc[OpFragmentFetchAMD].operands.push(OperandId, "'Image'"); + InstructionDesc[OpFragmentFetchAMD].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpFragmentFetchAMD].operands.push(OperandId, "'Fragment Index'"); +#endif + +#ifdef NV_EXTENSIONS + InstructionDesc[OpGroupNonUniformPartitionNV].operands.push(OperandId, "X"); +#endif } }; // end spv namespace diff --git a/Externals/glslang/SPIRV/doc.h b/Externals/glslang/SPIRV/doc.h index cf9e059bcd..7d0475d3eb 100644 --- a/Externals/glslang/SPIRV/doc.h +++ b/Externals/glslang/SPIRV/doc.h @@ -1,11 +1,11 @@ // -//Copyright (C) 2014-2015 LunarG, Inc. +// Copyright (C) 2014-2015 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,23 +19,25 @@ // 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. +// 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. // // Parameterize the SPIR-V enumerants. // +#pragma once + #include "spirv.hpp" #include @@ -149,7 +151,7 @@ enum OperandClass { OperandMemorySemantics, OperandMemoryAccess, OperandScope, - OperandGroupOperation, + OperandGroupOperation, OperandKernelEnqueueFlags, OperandKernelProfilingInfo, OperandCapability, @@ -188,7 +190,6 @@ protected: class EnumParameters { public: EnumParameters() : desc(0) { } - EnumCaps caps; const char* desc; }; @@ -233,7 +234,6 @@ public: bool hasType() const { return typePresent != 0; } const char* opDesc; - EnumCaps capabilities; OpcodeClass opClass; OperandParameters operands; @@ -242,8 +242,6 @@ protected: int resultPresent : 1; }; -const int OpcodeCeiling = 321; - // The set of objects that hold all the instruction/operand // parameterization information. extern InstructionParameters InstructionDesc[]; diff --git a/Externals/glslang/SPIRV/hex_float.h b/Externals/glslang/SPIRV/hex_float.h new file mode 100644 index 0000000000..905b21a45a --- /dev/null +++ b/Externals/glslang/SPIRV/hex_float.h @@ -0,0 +1,1078 @@ +// Copyright (c) 2015-2016 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef LIBSPIRV_UTIL_HEX_FLOAT_H_ +#define LIBSPIRV_UTIL_HEX_FLOAT_H_ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1800 +namespace std { +bool isnan(double f) +{ + return ::_isnan(f) != 0; +} +bool isinf(double f) +{ + return ::_finite(f) == 0; +} +} +#endif + +#include "bitutils.h" + +namespace spvutils { + +class Float16 { + public: + Float16(uint16_t v) : val(v) {} + Float16() {} + static bool isNan(const Float16& val) { + return ((val.val & 0x7C00) == 0x7C00) && ((val.val & 0x3FF) != 0); + } + // Returns true if the given value is any kind of infinity. + static bool isInfinity(const Float16& val) { + return ((val.val & 0x7C00) == 0x7C00) && ((val.val & 0x3FF) == 0); + } + Float16(const Float16& other) { val = other.val; } + uint16_t get_value() const { return val; } + + // Returns the maximum normal value. + static Float16 max() { return Float16(0x7bff); } + // Returns the lowest normal value. + static Float16 lowest() { return Float16(0xfbff); } + + private: + uint16_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 +// a value is Nan. +template +struct FloatProxyTraits { + typedef void uint_type; +}; + +template <> +struct FloatProxyTraits { + typedef uint32_t uint_type; + static bool isNan(float f) { return std::isnan(f); } + // Returns true if the given value is any kind of infinity. + static bool isInfinity(float f) { return std::isinf(f); } + // Returns the maximum normal value. + static float max() { return std::numeric_limits::max(); } + // Returns the lowest normal value. + static float lowest() { return std::numeric_limits::lowest(); } +}; + +template <> +struct FloatProxyTraits { + typedef uint64_t uint_type; + static bool isNan(double f) { return std::isnan(f); } + // Returns true if the given value is any kind of infinity. + static bool isInfinity(double f) { return std::isinf(f); } + // Returns the maximum normal value. + static double max() { return std::numeric_limits::max(); } + // Returns the lowest normal value. + static double lowest() { return std::numeric_limits::lowest(); } +}; + +template <> +struct FloatProxyTraits { + typedef uint16_t uint_type; + static bool isNan(Float16 f) { return Float16::isNan(f); } + // Returns true if the given value is any kind of infinity. + static bool isInfinity(Float16 f) { return Float16::isInfinity(f); } + // Returns the maximum normal value. + static Float16 max() { return Float16::max(); } + // Returns the lowest normal value. + static Float16 lowest() { return Float16::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. +template +class FloatProxy { + public: + typedef typename FloatProxyTraits::uint_type uint_type; + + // Since this is to act similar to the normal floats, + // do not initialize the data by default. + FloatProxy() {} + + // Intentionally non-explicit. This is a proxy type so + // implicit conversions allow us to use it more transparently. + FloatProxy(T val) { data_ = BitwiseCast(val); } + + // Intentionally non-explicit. This is a proxy type so + // implicit conversions allow us to use it more transparently. + FloatProxy(uint_type val) { data_ = val; } + + // This is helpful to have and is guaranteed not to stomp bits. + FloatProxy operator-() const { + return static_cast(data_ ^ + (uint_type(0x1) << (sizeof(T) * 8 - 1))); + } + + // Returns the data as a floating point value. + T getAsFloat() const { return BitwiseCast(data_); } + + // Returns the raw data. + uint_type data() const { return data_; } + + // Returns true if the value represents any type of NaN. + bool isNan() { return FloatProxyTraits::isNan(getAsFloat()); } + // Returns true if the value represents any type of infinity. + bool isInfinity() { return FloatProxyTraits::isInfinity(getAsFloat()); } + + // Returns the maximum normal value. + static FloatProxy max() { + return FloatProxy(FloatProxyTraits::max()); + } + // Returns the lowest normal value. + static FloatProxy lowest() { + return FloatProxy(FloatProxyTraits::lowest()); + } + + private: + uint_type data_; +}; + +template +bool operator==(const FloatProxy& first, const FloatProxy& second) { + return first.data() == second.data(); +} + +// Reads a FloatProxy value as a normal float from a stream. +template +std::istream& operator>>(std::istream& is, FloatProxy& value) { + T float_val; + is >> float_val; + value = FloatProxy(float_val); + return is; +} + +// This is an example traits. It is not meant to be used in practice, but will +// be the default for any non-specialized type. +template +struct HexFloatTraits { + // Integer type that can store this hex-float. + typedef void uint_type; + // Signed integer type that can store this hex-float. + typedef void int_type; + // The numerical type that this HexFloat represents. + typedef void underlying_type; + // The type needed to construct the underlying type. + typedef void native_type; + // The number of bits that are actually relevant in the uint_type. + // This allows us to deal with, for example, 24-bit values in a 32-bit + // integer. + static const uint32_t num_used_bits = 0; + // Number of bits that represent the exponent. + static const uint32_t num_exponent_bits = 0; + // Number of bits that represent the fractional part. + static const uint32_t num_fraction_bits = 0; + // 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; +}; + +// Traits for IEEE float. +// 1 sign bit, 8 exponent bits, 23 fractional bits. +template <> +struct HexFloatTraits> { + typedef uint32_t uint_type; + typedef int32_t int_type; + typedef FloatProxy underlying_type; + typedef float native_type; + static const uint_type num_used_bits = 32; + static const uint_type num_exponent_bits = 8; + static const uint_type num_fraction_bits = 23; + static const uint_type exponent_bias = 127; +}; + +// Traits for IEEE double. +// 1 sign bit, 11 exponent bits, 52 fractional bits. +template <> +struct HexFloatTraits> { + typedef uint64_t uint_type; + typedef int64_t int_type; + typedef FloatProxy underlying_type; + typedef double native_type; + static const uint_type num_used_bits = 64; + static const uint_type num_exponent_bits = 11; + static const uint_type num_fraction_bits = 52; + static const uint_type exponent_bias = 1023; +}; + +// Traits for IEEE half. +// 1 sign bit, 5 exponent bits, 10 fractional bits. +template <> +struct HexFloatTraits> { + typedef uint16_t uint_type; + typedef int16_t int_type; + typedef uint16_t underlying_type; + typedef uint16_t native_type; + static const uint_type num_used_bits = 16; + static const uint_type num_exponent_bits = 5; + static const uint_type num_fraction_bits = 10; + static const uint_type exponent_bias = 15; +}; + +enum round_direction { + kRoundToZero, + kRoundToNearestEven, + kRoundToPositiveInfinity, + kRoundToNegativeInfinity +}; + +// Template class that houses a floating pointer number. +// It exposes a number of constants based on the provided traits to +// assist in interpreting the bits of the value. +template > +class HexFloat { + public: + typedef typename Traits::uint_type uint_type; + typedef typename Traits::int_type int_type; + typedef typename Traits::underlying_type underlying_type; + typedef typename Traits::native_type native_type; + + explicit HexFloat(T f) : value_(f) {} + + T value() const { return value_; } + void set_value(T f) { value_ = f; } + + // These are all written like this because it is convenient to have + // compile-time constants for all of these values. + + // Pass-through values to save typing. + static const uint32_t num_used_bits = Traits::num_used_bits; + static const uint32_t exponent_bias = Traits::exponent_bias; + static const uint32_t num_exponent_bits = Traits::num_exponent_bits; + static const uint32_t num_fraction_bits = Traits::num_fraction_bits; + + // Number of bits to shift left to set the highest relevant bit. + static const uint32_t top_bit_left_shift = num_used_bits - 1; + // How many nibbles (hex characters) the fractional part takes up. + static const uint32_t fraction_nibbles = (num_fraction_bits + 3) / 4; + // If the fractional part does not fit evenly into a hex character (4-bits) + // then we have to left-shift to get rid of leading 0s. This is the amount + // we have to shift (might be 0). + static const uint32_t num_overflow_bits = + fraction_nibbles * 4 - num_fraction_bits; + + // The representation of the fraction, not the actual bits. This + // includes the leading bit that is usually implicit. + static const uint_type fraction_represent_mask = + spvutils::SetBits::get; + + // The topmost bit in the nibble-aligned fraction. + static const uint_type fraction_top_bit = + uint_type(1) << (num_fraction_bits + num_overflow_bits - 1); + + // The least significant bit in the exponent, which is also the bit + // immediately to the left of the significand. + static const uint_type first_exponent_bit = uint_type(1) + << (num_fraction_bits); + + // The mask for the encoded fraction. It does not include the + // implicit bit. + static const uint_type fraction_encode_mask = + spvutils::SetBits::get; + + // The bit that is used as a sign. + static const uint_type sign_mask = uint_type(1) << top_bit_left_shift; + + // The bits that represent the exponent. + static const uint_type exponent_mask = + spvutils::SetBits::get; + + // How far left the exponent is shifted. + static const uint32_t exponent_left_shift = num_fraction_bits; + + // How far from the right edge the fraction is shifted. + static const uint32_t fraction_right_shift = + static_cast(sizeof(uint_type) * 8) - num_fraction_bits; + + // The maximum representable unbiased exponent. + static const int_type max_exponent = + (exponent_mask >> num_fraction_bits) - exponent_bias; + // The minimum representable exponent for normalized numbers. + static const int_type min_exponent = -static_cast(exponent_bias); + + // Returns the bits associated with the value. + uint_type getBits() const { return spvutils::BitwiseCast(value_); } + + // Returns the bits associated with the value, without the leading sign bit. + uint_type getUnsignedBits() const { + return static_cast(spvutils::BitwiseCast(value_) & + ~sign_mask); + } + + // Returns the bits associated with the exponent, shifted to start at the + // lsb of the type. + const uint_type getExponentBits() const { + return static_cast((getBits() & exponent_mask) >> + num_fraction_bits); + } + + // Returns the exponent in unbiased form. This is the exponent in the + // human-friendly form. + const int_type getUnbiasedExponent() const { + return static_cast(getExponentBits() - exponent_bias); + } + + // Returns just the significand bits from the value. + const uint_type getSignificandBits() const { + return getBits() & fraction_encode_mask; + } + + // If the number was normalized, returns the unbiased exponent. + // If the number was denormal, normalize the exponent first. + const int_type getUnbiasedNormalizedExponent() const { + if ((getBits() & ~sign_mask) == 0) { // special case if everything is 0 + return 0; + } + int_type exp = getUnbiasedExponent(); + if (exp == min_exponent) { // We are in denorm land. + uint_type significand_bits = getSignificandBits(); + while ((significand_bits & (first_exponent_bit >> 1)) == 0) { + significand_bits = static_cast(significand_bits << 1); + exp = static_cast(exp - 1); + } + significand_bits &= fraction_encode_mask; + } + return exp; + } + + // Returns the signficand after it has been normalized. + const uint_type getNormalizedSignificand() const { + int_type unbiased_exponent = getUnbiasedNormalizedExponent(); + uint_type significand = getSignificandBits(); + for (int_type i = unbiased_exponent; i <= min_exponent; ++i) { + significand = static_cast(significand << 1); + } + significand &= fraction_encode_mask; + return significand; + } + + // Returns true if this number represents a negative value. + bool isNegative() const { return (getBits() & sign_mask) != 0; } + + // Sets this HexFloat from the individual components. + // Note this assumes EVERY significand is normalized, and has an implicit + // leading one. This means that the only way that this method will set 0, + // is if you set a number so denormalized that it underflows. + // Do not use this method with raw bits extracted from a subnormal number, + // since subnormals do not have an implicit leading 1 in the significand. + // The significand is also expected to be in the + // lowest-most num_fraction_bits of the uint_type. + // The exponent is expected to be unbiased, meaning an exponent of + // 0 actually means 0. + // If underflow_round_up is set, then on underflow, if a number is non-0 + // and would underflow, we round up to the smallest denorm. + void setFromSignUnbiasedExponentAndNormalizedSignificand( + bool negative, int_type exponent, uint_type significand, + bool round_denorm_up) { + bool significand_is_zero = significand == 0; + + if (exponent <= min_exponent) { + // If this was denormalized, then we have to shift the bit on, meaning + // the significand is not zero. + significand_is_zero = false; + significand |= first_exponent_bit; + significand = static_cast(significand >> 1); + } + + while (exponent < min_exponent) { + significand = static_cast(significand >> 1); + ++exponent; + } + + if (exponent == min_exponent) { + if (significand == 0 && !significand_is_zero && round_denorm_up) { + significand = static_cast(0x1); + } + } + + uint_type new_value = 0; + if (negative) { + new_value = static_cast(new_value | sign_mask); + } + exponent = static_cast(exponent + exponent_bias); + assert(exponent >= 0); + + // put it all together + exponent = static_cast((exponent << exponent_left_shift) & + exponent_mask); + significand = static_cast(significand & fraction_encode_mask); + new_value = static_cast(new_value | (exponent | significand)); + value_ = BitwiseCast(new_value); + } + + // Increments the significand of this number by the given amount. + // If this would spill the significand into the implicit bit, + // carry is set to true and the significand is shifted to fit into + // the correct location, otherwise carry is set to false. + // All significands and to_increment are assumed to be within the bounds + // for a valid significand. + static uint_type incrementSignificand(uint_type significand, + uint_type to_increment, bool* carry) { + significand = static_cast(significand + to_increment); + *carry = false; + if (significand & first_exponent_bit) { + *carry = true; + // The implicit 1-bit will have carried, so we should zero-out the + // top bit and shift back. + significand = static_cast(significand & ~first_exponent_bit); + significand = static_cast(significand >> 1); + } + return significand; + } + + // These exist because MSVC throws warnings on negative right-shifts + // even if they are not going to be executed. Eg: + // constant_number < 0? 0: constant_number + // These convert the negative left-shifts into right shifts. + + template + uint_type negatable_left_shift(int_type N, uint_type val) + { + if(N >= 0) + return val << N; + + return val >> -N; + } + + template + uint_type negatable_right_shift(int_type N, uint_type val) + { + if(N >= 0) + return val >> N; + + return val << -N; + } + + // Returns the significand, rounded to fit in a significand in + // other_T. This is shifted so that the most significant + // bit of the rounded number lines up with the most significant bit + // of the returned significand. + template + typename other_T::uint_type getRoundedNormalizedSignificand( + round_direction dir, bool* carry_bit) { + typedef typename other_T::uint_type other_uint_type; + static const int_type num_throwaway_bits = + static_cast(num_fraction_bits) - + static_cast(other_T::num_fraction_bits); + + static const uint_type last_significant_bit = + (num_throwaway_bits < 0) + ? 0 + : negatable_left_shift(num_throwaway_bits, 1u); + static const uint_type first_rounded_bit = + (num_throwaway_bits < 1) + ? 0 + : negatable_left_shift(num_throwaway_bits - 1, 1u); + + static const uint_type throwaway_mask_bits = + num_throwaway_bits > 0 ? num_throwaway_bits : 0; + static const uint_type throwaway_mask = + spvutils::SetBits::get; + + *carry_bit = false; + other_uint_type out_val = 0; + uint_type significand = getNormalizedSignificand(); + // If we are up-casting, then we just have to shift to the right location. + if (num_throwaway_bits <= 0) { + out_val = static_cast(significand); + uint_type shift_amount = static_cast(-num_throwaway_bits); + out_val = static_cast(out_val << shift_amount); + return out_val; + } + + // If every non-representable bit is 0, then we don't have any casting to + // do. + if ((significand & throwaway_mask) == 0) { + return static_cast( + negatable_right_shift(num_throwaway_bits, significand)); + } + + bool round_away_from_zero = false; + // We actually have to narrow the significand here, so we have to follow the + // rounding rules. + switch (dir) { + case kRoundToZero: + break; + case kRoundToPositiveInfinity: + round_away_from_zero = !isNegative(); + break; + case kRoundToNegativeInfinity: + round_away_from_zero = isNegative(); + break; + case kRoundToNearestEven: + // Have to round down, round bit is 0 + if ((first_rounded_bit & significand) == 0) { + break; + } + if (((significand & throwaway_mask) & ~first_rounded_bit) != 0) { + // If any subsequent bit of the rounded portion is non-0 then we round + // up. + round_away_from_zero = true; + break; + } + // We are exactly half-way between 2 numbers, pick even. + if ((significand & last_significant_bit) != 0) { + // 1 for our last bit, round up. + round_away_from_zero = true; + break; + } + break; + } + + if (round_away_from_zero) { + return static_cast( + negatable_right_shift(num_throwaway_bits, incrementSignificand( + significand, last_significant_bit, carry_bit))); + } else { + return static_cast( + negatable_right_shift(num_throwaway_bits, significand)); + } + } + + // Casts this value to another HexFloat. If the cast is widening, + // then round_dir is ignored. If the cast is narrowing, then + // the result is rounded in the direction specified. + // This number will retain Nan and Inf values. + // It will also saturate to Inf if the number overflows, and + // underflow to (0 or min depending on rounding) if the number underflows. + template + void castTo(other_T& other, round_direction round_dir) { + other = other_T(static_cast(0)); + bool negate = isNegative(); + if (getUnsignedBits() == 0) { + if (negate) { + other.set_value(-other.value()); + } + return; + } + uint_type significand = getSignificandBits(); + bool carried = false; + typename other_T::uint_type rounded_significand = + getRoundedNormalizedSignificand(round_dir, &carried); + + int_type exponent = getUnbiasedExponent(); + if (exponent == min_exponent) { + // If we are denormal, normalize the exponent, so that we can encode + // easily. + exponent = static_cast(exponent + 1); + for (uint_type check_bit = first_exponent_bit >> 1; check_bit != 0; + check_bit = static_cast(check_bit >> 1)) { + exponent = static_cast(exponent - 1); + if (check_bit & significand) break; + } + } + + bool is_nan = + (getBits() & exponent_mask) == exponent_mask && significand != 0; + bool is_inf = + !is_nan && + ((exponent + carried) > static_cast(other_T::exponent_bias) || + (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( + static_cast( + (negate ? other_T::sign_mask : 0) | other_T::exponent_mask))); + return; + } + if (is_nan) { + typename other_T::uint_type shifted_significand; + shifted_significand = static_cast( + negatable_left_shift( + static_cast(other_T::num_fraction_bits) - + static_cast(num_fraction_bits), significand)); + + // We are some sort of Nan. We try to keep the bit-pattern of the Nan + // as close as possible. If we had to shift off bits so we are 0, then we + // just set the last bit. + other.set_value(BitwiseCast( + static_cast( + (negate ? other_T::sign_mask : 0) | other_T::exponent_mask | + (shifted_significand == 0 ? 0x1 : shifted_significand)))); + return; + } + + bool round_underflow_up = + isNegative() ? round_dir == kRoundToNegativeInfinity + : round_dir == kRoundToPositiveInfinity; + typedef typename other_T::int_type other_int_type; + // setFromSignUnbiasedExponentAndNormalizedSignificand will + // zero out any underflowing value (but retain the sign). + other.setFromSignUnbiasedExponentAndNormalizedSignificand( + negate, static_cast(exponent), rounded_significand, + round_underflow_up); + return; + } + + private: + T value_; + + static_assert(num_used_bits == + Traits::num_exponent_bits + Traits::num_fraction_bits + 1, + "The number of bits do not fit"); + static_assert(sizeof(T) == sizeof(uint_type), "The type sizes do not match"); +}; + +// Returns 4 bits represented by the hex character. +inline uint8_t get_nibble_from_character(int character) { + const char* dec = "0123456789"; + const char* lower = "abcdef"; + const char* upper = "ABCDEF"; + const char* p = nullptr; + if ((p = strchr(dec, character))) { + return static_cast(p - dec); + } else if ((p = strchr(lower, character))) { + return static_cast(p - lower + 0xa); + } else if ((p = strchr(upper, character))) { + return static_cast(p - upper + 0xa); + } + + assert(false && "This was called with a non-hex character"); + return 0; +} + +// Outputs the given HexFloat to the stream. +template +std::ostream& operator<<(std::ostream& os, const HexFloat& value) { + typedef HexFloat HF; + typedef typename HF::uint_type uint_type; + typedef typename HF::int_type int_type; + + static_assert(HF::num_used_bits != 0, + "num_used_bits must be non-zero for a valid float"); + static_assert(HF::num_exponent_bits != 0, + "num_exponent_bits must be non-zero for a valid float"); + static_assert(HF::num_fraction_bits != 0, + "num_fractin_bits must be non-zero for a valid float"); + + const uint_type bits = spvutils::BitwiseCast(value.value()); + const char* const sign = (bits & HF::sign_mask) ? "-" : ""; + const uint_type exponent = static_cast( + (bits & HF::exponent_mask) >> HF::num_fraction_bits); + + uint_type fraction = static_cast((bits & HF::fraction_encode_mask) + << HF::num_overflow_bits); + + const bool is_zero = exponent == 0 && fraction == 0; + const bool is_denorm = exponent == 0 && !is_zero; + + // exponent contains the biased exponent we have to convert it back into + // the normal range. + int_type int_exponent = static_cast(exponent - HF::exponent_bias); + // If the number is all zeros, then we actually have to NOT shift the + // exponent. + int_exponent = is_zero ? 0 : int_exponent; + + // If we are denorm, then start shifting, and decreasing the exponent until + // our leading bit is 1. + + if (is_denorm) { + while ((fraction & HF::fraction_top_bit) == 0) { + fraction = static_cast(fraction << 1); + int_exponent = static_cast(int_exponent - 1); + } + // Since this is denormalized, we have to consume the leading 1 since it + // will end up being implicit. + fraction = static_cast(fraction << 1); // eat the leading 1 + fraction &= HF::fraction_represent_mask; + } + + uint_type fraction_nibbles = HF::fraction_nibbles; + // We do not have to display any trailing 0s, since this represents the + // fractional part. + while (fraction_nibbles > 0 && (fraction & 0xF) == 0) { + // Shift off any trailing values; + fraction = static_cast(fraction >> 4); + --fraction_nibbles; + } + + const auto saved_flags = os.flags(); + const auto saved_fill = os.fill(); + + os << sign << "0x" << (is_zero ? '0' : '1'); + if (fraction_nibbles) { + // Make sure to keep the leading 0s in place, since this is the fractional + // part. + os << "." << std::setw(static_cast(fraction_nibbles)) + << std::setfill('0') << std::hex << fraction; + } + os << "p" << std::dec << (int_exponent >= 0 ? "+" : "") << int_exponent; + + os.flags(saved_flags); + os.fill(saved_fill); + + return os; +} + +// Returns true if negate_value is true and the next character on the +// input stream is a plus or minus sign. In that case we also set the fail bit +// on the stream and set the value to the zero value for its type. +template +inline bool RejectParseDueToLeadingSign(std::istream& is, bool negate_value, + HexFloat& value) { + if (negate_value) { + auto next_char = is.peek(); + if (next_char == '-' || next_char == '+') { + // Fail the parse. Emulate standard behaviour by setting the value to + // the zero value, and set the fail bit on the stream. + value = HexFloat(typename HexFloat::uint_type(0)); + is.setstate(std::ios_base::failbit); + return true; + } + } + return false; +} + +// Parses a floating point number from the given stream and stores it into the +// value parameter. +// If negate_value is true then the number may not have a leading minus or +// plus, and if it successfully parses, then the number is negated before +// being stored into the value parameter. +// If the value cannot be correctly parsed or overflows the target floating +// point type, then set the fail bit on the stream. +// TODO(dneto): Promise C++11 standard behavior in how the value is set in +// the error case, but only after all target platforms implement it correctly. +// In particular, the Microsoft C++ runtime appears to be out of spec. +template +inline std::istream& ParseNormalFloat(std::istream& is, bool negate_value, + HexFloat& value) { + if (RejectParseDueToLeadingSign(is, negate_value, value)) { + return is; + } + T val; + is >> val; + if (negate_value) { + val = -val; + } + value.set_value(val); + // In the failure case, map -0.0 to 0.0. + if (is.fail() && value.getUnsignedBits() == 0u) { + value = HexFloat(typename HexFloat::uint_type(0)); + } + if (val.isInfinity()) { + // Fail the parse. Emulate standard behaviour by setting the value to + // the closest normal value, and set the fail bit on the stream. + value.set_value((value.isNegative() | negate_value) ? T::lowest() + : T::max()); + is.setstate(std::ios_base::failbit); + } + return is; +} + +// Specialization of ParseNormalFloat for FloatProxy values. +// This will parse the float as it were a 32-bit floating point number, +// and then round it down to fit into a Float16 value. +// The number is rounded towards zero. +// If negate_value is true then the number may not have a leading minus or +// plus, and if it successfully parses, then the number is negated before +// being stored into the value parameter. +// If the value cannot be correctly parsed or overflows the target floating +// point type, then set the fail bit on the stream. +// TODO(dneto): Promise C++11 standard behavior in how the value is set in +// the error case, but only after all target platforms implement it correctly. +// In particular, the Microsoft C++ runtime appears to be out of spec. +template <> +inline std::istream& +ParseNormalFloat, HexFloatTraits>>( + std::istream& is, bool negate_value, + HexFloat, HexFloatTraits>>& value) { + // First parse as a 32-bit float. + HexFloat> float_val(0.0f); + ParseNormalFloat(is, negate_value, float_val); + + // Then convert to 16-bit float, saturating at infinities, and + // rounding toward zero. + float_val.castTo(value, kRoundToZero); + + // Overflow on 16-bit behaves the same as for 32- and 64-bit: set the + // fail bit and set the lowest or highest value. + if (Float16::isInfinity(value.value().getAsFloat())) { + value.set_value(value.isNegative() ? Float16::lowest() : Float16::max()); + is.setstate(std::ios_base::failbit); + } + return is; +} + +// Reads a HexFloat from the given stream. +// If the float is not encoded as a hex-float then it will be parsed +// as a regular float. +// This may fail if your stream does not support at least one unget. +// Nan values can be encoded with "0x1.p+exponent_bias". +// This would normally overflow a float and round to +// infinity but this special pattern is the exact representation for a NaN, +// and therefore is actually encoded as the correct NaN. To encode inf, +// either 0x0p+exponent_bias can be specified or any exponent greater than +// exponent_bias. +// Examples using IEEE 32-bit float encoding. +// 0x1.0p+128 (+inf) +// -0x1.0p-128 (-inf) +// +// 0x1.1p+128 (+Nan) +// -0x1.1p+128 (-Nan) +// +// 0x1p+129 (+inf) +// -0x1p+129 (-inf) +template +std::istream& operator>>(std::istream& is, HexFloat& value) { + using HF = HexFloat; + using uint_type = typename HF::uint_type; + using int_type = typename HF::int_type; + + value.set_value(static_cast(0.f)); + + if (is.flags() & std::ios::skipws) { + // If the user wants to skip whitespace , then we should obey that. + while (std::isspace(is.peek())) { + is.get(); + } + } + + auto next_char = is.peek(); + bool negate_value = false; + + if (next_char != '-' && next_char != '0') { + return ParseNormalFloat(is, negate_value, value); + } + + if (next_char == '-') { + negate_value = true; + is.get(); + next_char = is.peek(); + } + + if (next_char == '0') { + is.get(); // We may have to unget this. + auto maybe_hex_start = is.peek(); + if (maybe_hex_start != 'x' && maybe_hex_start != 'X') { + is.unget(); + return ParseNormalFloat(is, negate_value, value); + } else { + is.get(); // Throw away the 'x'; + } + } else { + return ParseNormalFloat(is, negate_value, value); + } + + // This "looks" like a hex-float so treat it as one. + bool seen_p = false; + bool seen_dot = false; + uint_type fraction_index = 0; + + uint_type fraction = 0; + int_type exponent = HF::exponent_bias; + + // Strip off leading zeros so we don't have to special-case them later. + while ((next_char = is.peek()) == '0') { + is.get(); + } + + bool is_denorm = + true; // Assume denorm "representation" until we hear otherwise. + // NB: This does not mean the value is actually denorm, + // it just means that it was written 0. + bool bits_written = false; // Stays false until we write a bit. + while (!seen_p && !seen_dot) { + // Handle characters that are left of the fractional part. + if (next_char == '.') { + seen_dot = true; + } else if (next_char == 'p') { + seen_p = true; + } else if (::isxdigit(next_char)) { + // We know this is not denormalized since we have stripped all leading + // zeroes and we are not a ".". + is_denorm = false; + int number = get_nibble_from_character(next_char); + for (int i = 0; i < 4; ++i, number <<= 1) { + uint_type write_bit = (number & 0x8) ? 0x1 : 0x0; + if (bits_written) { + // If we are here the bits represented belong in the fractional + // part of the float, and we have to adjust the exponent accordingly. + fraction = static_cast( + fraction | + static_cast( + write_bit << (HF::top_bit_left_shift - fraction_index++))); + exponent = static_cast(exponent + 1); + } + bits_written |= write_bit != 0; + } + } else { + // We have not found our exponent yet, so we have to fail. + is.setstate(std::ios::failbit); + return is; + } + is.get(); + next_char = is.peek(); + } + bits_written = false; + while (seen_dot && !seen_p) { + // Handle only fractional parts now. + if (next_char == 'p') { + seen_p = true; + } else if (::isxdigit(next_char)) { + int number = get_nibble_from_character(next_char); + for (int i = 0; i < 4; ++i, number <<= 1) { + uint_type write_bit = (number & 0x8) ? 0x01 : 0x00; + bits_written |= write_bit != 0; + if (is_denorm && !bits_written) { + // Handle modifying the exponent here this way we can handle + // an arbitrary number of hex values without overflowing our + // integer. + exponent = static_cast(exponent - 1); + } else { + fraction = static_cast( + fraction | + static_cast( + write_bit << (HF::top_bit_left_shift - fraction_index++))); + } + } + } else { + // We still have not found our 'p' exponent yet, so this is not a valid + // hex-float. + is.setstate(std::ios::failbit); + return is; + } + is.get(); + next_char = is.peek(); + } + + bool seen_sign = false; + int8_t exponent_sign = 1; + int_type written_exponent = 0; + while (true) { + if ((next_char == '-' || next_char == '+')) { + if (seen_sign) { + is.setstate(std::ios::failbit); + return is; + } + seen_sign = true; + exponent_sign = (next_char == '-') ? -1 : 1; + } else if (::isdigit(next_char)) { + // Hex-floats express their exponent as decimal. + written_exponent = static_cast(written_exponent * 10); + written_exponent = + static_cast(written_exponent + (next_char - '0')); + } else { + break; + } + is.get(); + next_char = is.peek(); + } + + written_exponent = static_cast(written_exponent * exponent_sign); + exponent = static_cast(exponent + written_exponent); + + bool is_zero = is_denorm && (fraction == 0); + if (is_denorm && !is_zero) { + fraction = static_cast(fraction << 1); + exponent = static_cast(exponent - 1); + } else if (is_zero) { + exponent = 0; + } + + if (exponent <= 0 && !is_zero) { + fraction = static_cast(fraction >> 1); + fraction |= static_cast(1) << HF::top_bit_left_shift; + } + + fraction = (fraction >> HF::fraction_right_shift) & HF::fraction_encode_mask; + + const int_type max_exponent = + SetBits::get; + + // Handle actual denorm numbers + while (exponent < 0 && !is_zero) { + fraction = static_cast(fraction >> 1); + exponent = static_cast(exponent + 1); + + fraction &= HF::fraction_encode_mask; + if (fraction == 0) { + // We have underflowed our fraction. We should clamp to zero. + is_zero = true; + exponent = 0; + } + } + + // We have overflowed so we should be inf/-inf. + if (exponent > max_exponent) { + exponent = max_exponent; + fraction = 0; + } + + uint_type output_bits = static_cast( + static_cast(negate_value ? 1 : 0) << HF::top_bit_left_shift); + output_bits |= fraction; + + uint_type shifted_exponent = static_cast( + static_cast(exponent << HF::exponent_left_shift) & + HF::exponent_mask); + output_bits |= shifted_exponent; + + T output_float = spvutils::BitwiseCast(output_bits); + value.set_value(output_float); + + return is; +} + +// Writes a FloatProxy value to a stream. +// Zero and normal numbers are printed in the usual notation, but with +// enough digits to fully reproduce the value. Other values (subnormal, +// NaN, and infinity) are printed as a hex float. +template +std::ostream& operator<<(std::ostream& os, const FloatProxy& value) { + auto float_val = value.getAsFloat(); + switch (std::fpclassify(float_val)) { + case FP_ZERO: + case FP_NORMAL: { + auto saved_precision = os.precision(); + os.precision(std::numeric_limits::digits10); + os << float_val; + os.precision(saved_precision); + } break; + default: + os << HexFloat>(value); + break; + } + return os; +} + +template <> +inline std::ostream& operator<<(std::ostream& os, + const FloatProxy& value) { + os << HexFloat>(value); + return os; +} +} + +#endif // LIBSPIRV_UTIL_HEX_FLOAT_H_ diff --git a/Externals/glslang/SPIRV/spirv.hpp b/Externals/glslang/SPIRV/spirv.hpp old mode 100755 new mode 100644 index e3d134257f..e21762dbec --- a/Externals/glslang/SPIRV/spirv.hpp +++ b/Externals/glslang/SPIRV/spirv.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2016 The Khronos Group Inc. +// Copyright (c) 2014-2018 The Khronos Group Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and/or associated documentation files (the "Materials"), @@ -46,12 +46,12 @@ namespace spv { typedef unsigned int Id; -#define SPV_VERSION 0x10000 -#define SPV_REVISION 6 +#define SPV_VERSION 0x10300 +#define SPV_REVISION 1 static const unsigned int MagicNumber = 0x07230203; -static const unsigned int Version = 0x00010000; -static const unsigned int Revision = 6; +static const unsigned int Version = 0x00010300; +static const unsigned int Revision = 1; static const unsigned int OpCodeMask = 0xffff; static const unsigned int WordCountShift = 16; @@ -122,6 +122,15 @@ enum ExecutionMode { ExecutionModeOutputTriangleStrip = 29, ExecutionModeVecTypeHint = 30, ExecutionModeContractionOff = 31, + ExecutionModeInitializer = 33, + ExecutionModeFinalizer = 34, + ExecutionModeSubgroupSize = 35, + ExecutionModeSubgroupsPerWorkgroup = 36, + ExecutionModeSubgroupsPerWorkgroupId = 37, + ExecutionModeLocalSizeId = 38, + ExecutionModeLocalSizeHintId = 39, + ExecutionModePostDepthCoverage = 4446, + ExecutionModeStencilRefReplacingEXT = 5027, ExecutionModeMax = 0x7fffffff, }; @@ -138,6 +147,7 @@ enum StorageClass { StorageClassPushConstant = 9, StorageClassAtomicCounter = 10, StorageClassImage = 11, + StorageClassStorageBuffer = 12, StorageClassMax = 0x7fffffff, }; @@ -375,6 +385,17 @@ enum Decoration { DecorationNoContraction = 42, DecorationInputAttachmentIndex = 43, DecorationAlignment = 44, + DecorationMaxByteOffset = 45, + DecorationAlignmentId = 46, + DecorationMaxByteOffsetId = 47, + DecorationExplicitInterpAMD = 4999, + DecorationOverrideCoverageNV = 5248, + DecorationPassthroughNV = 5250, + DecorationViewportRelativeNV = 5252, + DecorationSecondaryViewportRelativeNV = 5256, + DecorationNonUniformEXT = 5300, + DecorationHlslCounterBufferGOOGLE = 5634, + DecorationHlslSemanticGOOGLE = 5635, DecorationMax = 0x7fffffff, }; @@ -420,6 +441,35 @@ enum BuiltIn { BuiltInSubgroupLocalInvocationId = 41, BuiltInVertexIndex = 42, BuiltInInstanceIndex = 43, + BuiltInSubgroupEqMask = 4416, + BuiltInSubgroupEqMaskKHR = 4416, + BuiltInSubgroupGeMask = 4417, + BuiltInSubgroupGeMaskKHR = 4417, + BuiltInSubgroupGtMask = 4418, + BuiltInSubgroupGtMaskKHR = 4418, + BuiltInSubgroupLeMask = 4419, + BuiltInSubgroupLeMaskKHR = 4419, + BuiltInSubgroupLtMask = 4420, + BuiltInSubgroupLtMaskKHR = 4420, + BuiltInBaseVertex = 4424, + BuiltInBaseInstance = 4425, + BuiltInDrawIndex = 4426, + BuiltInDeviceIndex = 4438, + BuiltInViewIndex = 4440, + BuiltInBaryCoordNoPerspAMD = 4992, + BuiltInBaryCoordNoPerspCentroidAMD = 4993, + BuiltInBaryCoordNoPerspSampleAMD = 4994, + BuiltInBaryCoordSmoothAMD = 4995, + BuiltInBaryCoordSmoothCentroidAMD = 4996, + BuiltInBaryCoordSmoothSampleAMD = 4997, + BuiltInBaryCoordPullModelAMD = 4998, + BuiltInFragStencilRefEXT = 5014, + BuiltInViewportMaskNV = 5253, + BuiltInSecondaryPositionNV = 5257, + BuiltInSecondaryViewportMaskNV = 5258, + BuiltInPositionPerViewNV = 5261, + BuiltInViewportMaskPerViewNV = 5262, + BuiltInFullyCoveredEXT = 5264, BuiltInMax = 0x7fffffff, }; @@ -438,6 +488,8 @@ enum SelectionControlMask { enum LoopControlShift { LoopControlUnrollShift = 0, LoopControlDontUnrollShift = 1, + LoopControlDependencyInfiniteShift = 2, + LoopControlDependencyLengthShift = 3, LoopControlMax = 0x7fffffff, }; @@ -445,6 +497,8 @@ enum LoopControlMask { LoopControlMaskNone = 0, LoopControlUnrollMask = 0x00000001, LoopControlDontUnrollMask = 0x00000002, + LoopControlDependencyInfiniteMask = 0x00000004, + LoopControlDependencyLengthMask = 0x00000008, }; enum FunctionControlShift { @@ -518,6 +572,10 @@ enum GroupOperation { GroupOperationReduce = 0, GroupOperationInclusiveScan = 1, GroupOperationExclusiveScan = 2, + GroupOperationClusteredReduce = 3, + GroupOperationPartitionedReduceNV = 6, + GroupOperationPartitionedInclusiveScanNV = 7, + GroupOperationPartitionedExclusiveScanNV = 8, GroupOperationMax = 0x7fffffff, }; @@ -595,6 +653,61 @@ enum Capability { CapabilityStorageImageReadWithoutFormat = 55, CapabilityStorageImageWriteWithoutFormat = 56, CapabilityMultiViewport = 57, + CapabilitySubgroupDispatch = 58, + CapabilityNamedBarrier = 59, + CapabilityPipeStorage = 60, + CapabilityGroupNonUniform = 61, + CapabilityGroupNonUniformVote = 62, + CapabilityGroupNonUniformArithmetic = 63, + CapabilityGroupNonUniformBallot = 64, + CapabilityGroupNonUniformShuffle = 65, + CapabilityGroupNonUniformShuffleRelative = 66, + CapabilityGroupNonUniformClustered = 67, + CapabilityGroupNonUniformQuad = 68, + CapabilitySubgroupBallotKHR = 4423, + CapabilityDrawParameters = 4427, + CapabilitySubgroupVoteKHR = 4431, + CapabilityStorageBuffer16BitAccess = 4433, + CapabilityStorageUniformBufferBlock16 = 4433, + CapabilityStorageUniform16 = 4434, + CapabilityUniformAndStorageBuffer16BitAccess = 4434, + CapabilityStoragePushConstant16 = 4435, + CapabilityStorageInputOutput16 = 4436, + CapabilityDeviceGroup = 4437, + CapabilityMultiView = 4439, + CapabilityVariablePointersStorageBuffer = 4441, + CapabilityVariablePointers = 4442, + CapabilityAtomicStorageOps = 4445, + CapabilitySampleMaskPostDepthCoverage = 4447, + CapabilityFloat16ImageAMD = 5008, + CapabilityImageGatherBiasLodAMD = 5009, + CapabilityFragmentMaskAMD = 5010, + CapabilityStencilExportEXT = 5013, + CapabilityImageReadWriteLodAMD = 5015, + CapabilitySampleMaskOverrideCoverageNV = 5249, + CapabilityGeometryShaderPassthroughNV = 5251, + CapabilityShaderViewportIndexLayerEXT = 5254, + CapabilityShaderViewportIndexLayerNV = 5254, + CapabilityShaderViewportMaskNV = 5255, + CapabilityShaderStereoViewNV = 5259, + CapabilityPerViewAttributesNV = 5260, + CapabilityFragmentFullyCoveredEXT = 5265, + CapabilityGroupNonUniformPartitionedNV = 5297, + CapabilityShaderNonUniformEXT = 5301, + CapabilityRuntimeDescriptorArrayEXT = 5302, + CapabilityInputAttachmentArrayDynamicIndexingEXT = 5303, + CapabilityUniformTexelBufferArrayDynamicIndexingEXT = 5304, + CapabilityStorageTexelBufferArrayDynamicIndexingEXT = 5305, + CapabilityUniformBufferArrayNonUniformIndexingEXT = 5306, + CapabilitySampledImageArrayNonUniformIndexingEXT = 5307, + CapabilityStorageBufferArrayNonUniformIndexingEXT = 5308, + CapabilityStorageImageArrayNonUniformIndexingEXT = 5309, + CapabilityInputAttachmentArrayNonUniformIndexingEXT = 5310, + CapabilityUniformTexelBufferArrayNonUniformIndexingEXT = 5311, + CapabilityStorageTexelBufferArrayNonUniformIndexingEXT = 5312, + CapabilitySubgroupShuffleINTEL = 5568, + CapabilitySubgroupBufferBlockIOINTEL = 5569, + CapabilitySubgroupImageBlockIOINTEL = 5570, CapabilityMax = 0x7fffffff, }; @@ -893,6 +1006,79 @@ enum Op { OpAtomicFlagTestAndSet = 318, OpAtomicFlagClear = 319, OpImageSparseRead = 320, + OpSizeOf = 321, + OpTypePipeStorage = 322, + OpConstantPipeStorage = 323, + OpCreatePipeFromPipeStorage = 324, + OpGetKernelLocalSizeForSubgroupCount = 325, + OpGetKernelMaxNumSubgroups = 326, + OpTypeNamedBarrier = 327, + OpNamedBarrierInitialize = 328, + OpMemoryNamedBarrier = 329, + OpModuleProcessed = 330, + OpExecutionModeId = 331, + OpDecorateId = 332, + OpGroupNonUniformElect = 333, + OpGroupNonUniformAll = 334, + OpGroupNonUniformAny = 335, + OpGroupNonUniformAllEqual = 336, + OpGroupNonUniformBroadcast = 337, + OpGroupNonUniformBroadcastFirst = 338, + OpGroupNonUniformBallot = 339, + OpGroupNonUniformInverseBallot = 340, + OpGroupNonUniformBallotBitExtract = 341, + OpGroupNonUniformBallotBitCount = 342, + OpGroupNonUniformBallotFindLSB = 343, + OpGroupNonUniformBallotFindMSB = 344, + OpGroupNonUniformShuffle = 345, + OpGroupNonUniformShuffleXor = 346, + OpGroupNonUniformShuffleUp = 347, + OpGroupNonUniformShuffleDown = 348, + OpGroupNonUniformIAdd = 349, + OpGroupNonUniformFAdd = 350, + OpGroupNonUniformIMul = 351, + OpGroupNonUniformFMul = 352, + OpGroupNonUniformSMin = 353, + OpGroupNonUniformUMin = 354, + OpGroupNonUniformFMin = 355, + OpGroupNonUniformSMax = 356, + OpGroupNonUniformUMax = 357, + OpGroupNonUniformFMax = 358, + OpGroupNonUniformBitwiseAnd = 359, + OpGroupNonUniformBitwiseOr = 360, + OpGroupNonUniformBitwiseXor = 361, + OpGroupNonUniformLogicalAnd = 362, + OpGroupNonUniformLogicalOr = 363, + OpGroupNonUniformLogicalXor = 364, + OpGroupNonUniformQuadBroadcast = 365, + OpGroupNonUniformQuadSwap = 366, + OpSubgroupBallotKHR = 4421, + OpSubgroupFirstInvocationKHR = 4422, + OpSubgroupAllKHR = 4428, + OpSubgroupAnyKHR = 4429, + OpSubgroupAllEqualKHR = 4430, + OpSubgroupReadInvocationKHR = 4432, + OpGroupIAddNonUniformAMD = 5000, + OpGroupFAddNonUniformAMD = 5001, + OpGroupFMinNonUniformAMD = 5002, + OpGroupUMinNonUniformAMD = 5003, + OpGroupSMinNonUniformAMD = 5004, + OpGroupFMaxNonUniformAMD = 5005, + OpGroupUMaxNonUniformAMD = 5006, + OpGroupSMaxNonUniformAMD = 5007, + OpFragmentMaskFetchAMD = 5011, + OpFragmentFetchAMD = 5012, + OpGroupNonUniformPartitionNV = 5296, + OpSubgroupShuffleINTEL = 5571, + OpSubgroupShuffleDownINTEL = 5572, + OpSubgroupShuffleUpINTEL = 5573, + OpSubgroupShuffleXorINTEL = 5574, + OpSubgroupBlockReadINTEL = 5575, + OpSubgroupBlockWriteINTEL = 5576, + OpSubgroupImageBlockReadINTEL = 5577, + OpSubgroupImageBlockWriteINTEL = 5578, + OpDecorateStringGOOGLE = 5632, + OpMemberDecorateStringGOOGLE = 5633, OpMax = 0x7fffffff, }; diff --git a/Externals/glslang/SPIRV/spvIR.h b/Externals/glslang/SPIRV/spvIR.h index c584c9dcb4..8b6c6447f4 100755 --- a/Externals/glslang/SPIRV/spvIR.h +++ b/Externals/glslang/SPIRV/spvIR.h @@ -1,11 +1,11 @@ // -//Copyright (C) 2014 LunarG, Inc. +// Copyright (C) 2014 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,26 +19,26 @@ // 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. +// 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. // SPIRV-IR // // Simple in-memory representation (IR) of SPIRV. Just for holding // Each function's CFG of blocks. Has this hierarchy: -// - Module, which is a list of -// - Function, which is a list of -// - Block, which is a list of +// - Module, which is a list of +// - Function, which is a list of +// - Block, which is a list of // - Instruction // @@ -65,12 +65,17 @@ const Id NoResult = 0; const Id NoType = 0; const Decoration NoPrecision = DecorationMax; -const MemorySemanticsMask MemorySemanticsAllMemory = - (MemorySemanticsMask)(MemorySemanticsSequentiallyConsistentMask | - MemorySemanticsUniformMemoryMask | - MemorySemanticsSubgroupMemoryMask | + +#ifdef __GNUC__ +# define POTENTIALLY_UNUSED __attribute__((unused)) +#else +# define POTENTIALLY_UNUSED +#endif + +POTENTIALLY_UNUSED +const MemorySemanticsMask MemorySemanticsAllMemory = + (MemorySemanticsMask)(MemorySemanticsUniformMemoryMask | MemorySemanticsWorkgroupMemoryMask | - MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsAtomicCounterMemoryMask | MemorySemanticsImageMemoryMask); @@ -87,7 +92,6 @@ public: void addImmediateOperand(unsigned int immediate) { operands.push_back(immediate); } void addStringOperand(const char* str) { - originalString = str; unsigned int word; char* wordString = (char*)&word; char* wordPtr = wordString; @@ -120,7 +124,6 @@ public: Id getTypeId() const { return typeId; } Id getIdOperand(int op) const { return operands[op]; } unsigned int getImmediateOperand(int op) const { return operands[op]; } - const char* getStringOperand() const { return originalString.c_str(); } // Write out the binary form. void dump(std::vector& out) const @@ -151,7 +154,6 @@ protected: Id typeId; Op opCode; std::vector operands; - std::string originalString; // could be optimized away; convenience for getting string operand Block* block; }; @@ -229,7 +231,7 @@ protected: std::vector > localVariables; Function& parent; - // track whether this block is known to be uncreachable (not necessarily + // track whether this block is known to be uncreachable (not necessarily // true for all unreachable blocks, but should be set at least // for the extraneous ones introduced by the builder). bool unreachable; @@ -256,7 +258,8 @@ public: delete blocks[i]; } Id getId() const { return functionInstruction.getResultId(); } - Id getParamId(int p) { return parameterInstructions[p]->getResultId(); } + Id getParamId(int p) const { return parameterInstructions[p]->getResultId(); } + Id getParamType(int p) const { return parameterInstructions[p]->getTypeId(); } void addBlock(Block* block) { blocks.push_back(block); } void removeBlock(Block* block) @@ -273,6 +276,10 @@ public: const std::vector& getBlocks() const { return blocks; } void addLocalVariable(std::unique_ptr inst); Id getReturnType() const { return functionInstruction.getTypeId(); } + + void setImplicitThis() { implicitThis = true; } + bool hasImplicitThis() const { return implicitThis; } + void dump(std::vector& out) const { // OpFunction @@ -296,6 +303,7 @@ protected: Instruction functionInstruction; std::vector parameterInstructions; std::vector blocks; + bool implicitThis; // true if this is a member function expecting to be passed a 'this' as the first argument }; // @@ -354,7 +362,7 @@ protected: // - the OpFunction instruction // - all the OpFunctionParameter instructions __inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, Module& parent) - : parent(parent), functionInstruction(id, resultType, OpFunction) + : parent(parent), functionInstruction(id, resultType, OpFunction), implicitThis(false) { // OpFunction functionInstruction.addImmediateOperand(FunctionControlMaskNone); diff --git a/Externals/glslang/StandAlone/CMakeLists.txt b/Externals/glslang/StandAlone/CMakeLists.txt old mode 100644 new mode 100755 index d69351ef3c..d500121df5 --- a/Externals/glslang/StandAlone/CMakeLists.txt +++ b/Externals/glslang/StandAlone/CMakeLists.txt @@ -1,14 +1,13 @@ add_library(glslang-default-resource-limits - ${CMAKE_CURRENT_SOURCE_DIR}/ResourceLimits.cpp -) + ${CMAKE_CURRENT_SOURCE_DIR}/ResourceLimits.cpp) set_property(TARGET glslang-default-resource-limits PROPERTY FOLDER glslang) +set_property(TARGET glslang-default-resource-limits PROPERTY POSITION_INDEPENDENT_CODE ON) target_include_directories(glslang-default-resource-limits - PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} - PUBLIC ${PROJECT_SOURCE_DIR} -) + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + PUBLIC ${PROJECT_SOURCE_DIR}) -set(SOURCES StandAlone.cpp) +set(SOURCES StandAlone.cpp DirStackFileIncluder.h) set(REMAPPER_SOURCES spirv-remap.cpp) add_executable(glslangValidator ${SOURCES}) @@ -20,10 +19,8 @@ glslang_set_link_args(spirv-remap) set(LIBRARIES glslang - OGLCompiler - OSDependent - HLSL SPIRV + SPVRemapper glslang-default-resource-limits) if(WIN32) @@ -41,8 +38,15 @@ if(WIN32) source_group("Source" FILES ${SOURCES}) endif(WIN32) -install(TARGETS glslangValidator - RUNTIME DESTINATION bin) +if(ENABLE_GLSLANG_INSTALL) + install(TARGETS glslangValidator + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -install(TARGETS spirv-remap - RUNTIME DESTINATION bin) + install(TARGETS spirv-remap + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + + if(BUILD_SHARED_LIBS) + install(TARGETS glslang-default-resource-limits + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif() +endif(ENABLE_GLSLANG_INSTALL) diff --git a/Externals/glslang/StandAlone/DirStackFileIncluder.h b/Externals/glslang/StandAlone/DirStackFileIncluder.h new file mode 100644 index 0000000000..18734130e7 --- /dev/null +++ b/Externals/glslang/StandAlone/DirStackFileIncluder.h @@ -0,0 +1,141 @@ +// +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2017 Google, 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. +// + +#pragma once + +#include +#include +#include +#include + +#include "./../glslang/Public/ShaderLang.h" + +// Default include class for normal include convention of search backward +// through the stack of active include paths (for nested includes). +// Can be overridden to customize. +class DirStackFileIncluder : public glslang::TShader::Includer { +public: + DirStackFileIncluder() : externalLocalDirectoryCount(0) { } + + virtual IncludeResult* includeLocal(const char* headerName, + const char* includerName, + size_t inclusionDepth) override + { + return readLocalPath(headerName, includerName, (int)inclusionDepth); + } + + virtual IncludeResult* includeSystem(const char* headerName, + const char* /*includerName*/, + size_t /*inclusionDepth*/) override + { + return readSystemPath(headerName); + } + + // Externally set directories. E.g., from a command-line -I. + // - Most-recently pushed are checked first. + // - All these are checked after the parse-time stack of local directories + // is checked. + // - This only applies to the "local" form of #include. + // - Makes its own copy of the path. + virtual void pushExternalLocalDirectory(const std::string& dir) + { + directoryStack.push_back(dir); + externalLocalDirectoryCount = (int)directoryStack.size(); + } + + virtual void releaseInclude(IncludeResult* result) override + { + if (result != nullptr) { + delete [] static_cast(result->userData); + delete result; + } + } + + virtual ~DirStackFileIncluder() override { } + +protected: + typedef char tUserDataElement; + std::vector directoryStack; + int externalLocalDirectoryCount; + + // Search for a valid "local" path based on combining the stack of include + // directories and the nominal name of the header. + virtual IncludeResult* readLocalPath(const char* headerName, const char* includerName, int depth) + { + // Discard popped include directories, and + // initialize when at parse-time first level. + directoryStack.resize(depth + externalLocalDirectoryCount); + if (depth == 1) + directoryStack.back() = getDirectory(includerName); + + // Find a directory that works, using a reverse search of the include stack. + for (auto it = directoryStack.rbegin(); it != directoryStack.rend(); ++it) { + std::string path = *it + '/' + headerName; + std::replace(path.begin(), path.end(), '\\', '/'); + std::ifstream file(path, std::ios_base::binary | std::ios_base::ate); + if (file) { + directoryStack.push_back(getDirectory(path)); + return newIncludeResult(path, file, (int)file.tellg()); + } + } + + return nullptr; + } + + // Search for a valid path. + // Not implemented yet; returning nullptr signals failure to find. + virtual IncludeResult* readSystemPath(const char* /*headerName*/) const + { + return nullptr; + } + + // Do actual reading of the file, filling in a new include result. + virtual IncludeResult* newIncludeResult(const std::string& path, std::ifstream& file, int length) const + { + char* content = new tUserDataElement [length]; + file.seekg(0, file.beg); + file.read(content, length); + return new IncludeResult(path, content, length, content); + } + + // If no path markers, return current working directory. + // Otherwise, strip file name and return path leading up to it. + virtual std::string getDirectory(const std::string path) const + { + size_t last = path.find_last_of("/\\"); + return last == std::string::npos ? "." : path.substr(0, last); + } +}; diff --git a/Externals/glslang/StandAlone/ResourceLimits.cpp b/Externals/glslang/StandAlone/ResourceLimits.cpp index 80198634e0..e22ec8015c 100644 --- a/Externals/glslang/StandAlone/ResourceLimits.cpp +++ b/Externals/glslang/StandAlone/ResourceLimits.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include "ResourceLimits.h" @@ -240,205 +241,217 @@ std::string GetDefaultTBuiltInResourceString() void DecodeResourceLimits(TBuiltInResource* resources, char* config) { - const char* delims = " \t\n\r"; - const char* token = strtok(config, delims); - while (token) { - const char* valueStr = strtok(0, delims); - if (valueStr == 0 || ! (valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) { - printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n", valueStr ? valueStr : ""); + static const char* delims = " \t\n\r"; + + size_t pos = 0; + std::string configStr(config); + + while ((pos = configStr.find_first_not_of(delims, pos)) != std::string::npos) { + const size_t token_s = pos; + const size_t token_e = configStr.find_first_of(delims, token_s); + const size_t value_s = configStr.find_first_not_of(delims, token_e); + const size_t value_e = configStr.find_first_of(delims, value_s); + pos = value_e; + + // Faster to use compare(), but prefering readability. + const std::string tokenStr = configStr.substr(token_s, token_e-token_s); + const std::string valueStr = configStr.substr(value_s, value_e-value_s); + + if (value_s == std::string::npos || ! (valueStr[0] == '-' || isdigit(valueStr[0]))) { + printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n", + valueStr.c_str()); return; } - int value = atoi(valueStr); - if (strcmp(token, "MaxLights") == 0) + const int value = std::atoi(valueStr.c_str()); + + if (tokenStr == "MaxLights") resources->maxLights = value; - else if (strcmp(token, "MaxClipPlanes") == 0) + else if (tokenStr == "MaxClipPlanes") resources->maxClipPlanes = value; - else if (strcmp(token, "MaxTextureUnits") == 0) + else if (tokenStr == "MaxTextureUnits") resources->maxTextureUnits = value; - else if (strcmp(token, "MaxTextureCoords") == 0) + else if (tokenStr == "MaxTextureCoords") resources->maxTextureCoords = value; - else if (strcmp(token, "MaxVertexAttribs") == 0) + else if (tokenStr == "MaxVertexAttribs") resources->maxVertexAttribs = value; - else if (strcmp(token, "MaxVertexUniformComponents") == 0) + else if (tokenStr == "MaxVertexUniformComponents") resources->maxVertexUniformComponents = value; - else if (strcmp(token, "MaxVaryingFloats") == 0) + else if (tokenStr == "MaxVaryingFloats") resources->maxVaryingFloats = value; - else if (strcmp(token, "MaxVertexTextureImageUnits") == 0) + else if (tokenStr == "MaxVertexTextureImageUnits") resources->maxVertexTextureImageUnits = value; - else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0) + else if (tokenStr == "MaxCombinedTextureImageUnits") resources->maxCombinedTextureImageUnits = value; - else if (strcmp(token, "MaxTextureImageUnits") == 0) + else if (tokenStr == "MaxTextureImageUnits") resources->maxTextureImageUnits = value; - else if (strcmp(token, "MaxFragmentUniformComponents") == 0) + else if (tokenStr == "MaxFragmentUniformComponents") resources->maxFragmentUniformComponents = value; - else if (strcmp(token, "MaxDrawBuffers") == 0) + else if (tokenStr == "MaxDrawBuffers") resources->maxDrawBuffers = value; - else if (strcmp(token, "MaxVertexUniformVectors") == 0) + else if (tokenStr == "MaxVertexUniformVectors") resources->maxVertexUniformVectors = value; - else if (strcmp(token, "MaxVaryingVectors") == 0) + else if (tokenStr == "MaxVaryingVectors") resources->maxVaryingVectors = value; - else if (strcmp(token, "MaxFragmentUniformVectors") == 0) + else if (tokenStr == "MaxFragmentUniformVectors") resources->maxFragmentUniformVectors = value; - else if (strcmp(token, "MaxVertexOutputVectors") == 0) + else if (tokenStr == "MaxVertexOutputVectors") resources->maxVertexOutputVectors = value; - else if (strcmp(token, "MaxFragmentInputVectors") == 0) + else if (tokenStr == "MaxFragmentInputVectors") resources->maxFragmentInputVectors = value; - else if (strcmp(token, "MinProgramTexelOffset") == 0) + else if (tokenStr == "MinProgramTexelOffset") resources->minProgramTexelOffset = value; - else if (strcmp(token, "MaxProgramTexelOffset") == 0) + else if (tokenStr == "MaxProgramTexelOffset") resources->maxProgramTexelOffset = value; - else if (strcmp(token, "MaxClipDistances") == 0) + else if (tokenStr == "MaxClipDistances") resources->maxClipDistances = value; - else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0) + else if (tokenStr == "MaxComputeWorkGroupCountX") resources->maxComputeWorkGroupCountX = value; - else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0) + else if (tokenStr == "MaxComputeWorkGroupCountY") resources->maxComputeWorkGroupCountY = value; - else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0) + else if (tokenStr == "MaxComputeWorkGroupCountZ") resources->maxComputeWorkGroupCountZ = value; - else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0) + else if (tokenStr == "MaxComputeWorkGroupSizeX") resources->maxComputeWorkGroupSizeX = value; - else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0) + else if (tokenStr == "MaxComputeWorkGroupSizeY") resources->maxComputeWorkGroupSizeY = value; - else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0) + else if (tokenStr == "MaxComputeWorkGroupSizeZ") resources->maxComputeWorkGroupSizeZ = value; - else if (strcmp(token, "MaxComputeUniformComponents") == 0) + else if (tokenStr == "MaxComputeUniformComponents") resources->maxComputeUniformComponents = value; - else if (strcmp(token, "MaxComputeTextureImageUnits") == 0) + else if (tokenStr == "MaxComputeTextureImageUnits") resources->maxComputeTextureImageUnits = value; - else if (strcmp(token, "MaxComputeImageUniforms") == 0) + else if (tokenStr == "MaxComputeImageUniforms") resources->maxComputeImageUniforms = value; - else if (strcmp(token, "MaxComputeAtomicCounters") == 0) + else if (tokenStr == "MaxComputeAtomicCounters") resources->maxComputeAtomicCounters = value; - else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0) + else if (tokenStr == "MaxComputeAtomicCounterBuffers") resources->maxComputeAtomicCounterBuffers = value; - else if (strcmp(token, "MaxVaryingComponents") == 0) + else if (tokenStr == "MaxVaryingComponents") resources->maxVaryingComponents = value; - else if (strcmp(token, "MaxVertexOutputComponents") == 0) + else if (tokenStr == "MaxVertexOutputComponents") resources->maxVertexOutputComponents = value; - else if (strcmp(token, "MaxGeometryInputComponents") == 0) + else if (tokenStr == "MaxGeometryInputComponents") resources->maxGeometryInputComponents = value; - else if (strcmp(token, "MaxGeometryOutputComponents") == 0) + else if (tokenStr == "MaxGeometryOutputComponents") resources->maxGeometryOutputComponents = value; - else if (strcmp(token, "MaxFragmentInputComponents") == 0) + else if (tokenStr == "MaxFragmentInputComponents") resources->maxFragmentInputComponents = value; - else if (strcmp(token, "MaxImageUnits") == 0) + else if (tokenStr == "MaxImageUnits") resources->maxImageUnits = value; - else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0) + else if (tokenStr == "MaxCombinedImageUnitsAndFragmentOutputs") resources->maxCombinedImageUnitsAndFragmentOutputs = value; - else if (strcmp(token, "MaxCombinedShaderOutputResources") == 0) + else if (tokenStr == "MaxCombinedShaderOutputResources") resources->maxCombinedShaderOutputResources = value; - else if (strcmp(token, "MaxImageSamples") == 0) + else if (tokenStr == "MaxImageSamples") resources->maxImageSamples = value; - else if (strcmp(token, "MaxVertexImageUniforms") == 0) + else if (tokenStr == "MaxVertexImageUniforms") resources->maxVertexImageUniforms = value; - else if (strcmp(token, "MaxTessControlImageUniforms") == 0) + else if (tokenStr == "MaxTessControlImageUniforms") resources->maxTessControlImageUniforms = value; - else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0) + else if (tokenStr == "MaxTessEvaluationImageUniforms") resources->maxTessEvaluationImageUniforms = value; - else if (strcmp(token, "MaxGeometryImageUniforms") == 0) + else if (tokenStr == "MaxGeometryImageUniforms") resources->maxGeometryImageUniforms = value; - else if (strcmp(token, "MaxFragmentImageUniforms") == 0) + else if (tokenStr == "MaxFragmentImageUniforms") resources->maxFragmentImageUniforms = value; - else if (strcmp(token, "MaxCombinedImageUniforms") == 0) + else if (tokenStr == "MaxCombinedImageUniforms") resources->maxCombinedImageUniforms = value; - else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0) + else if (tokenStr == "MaxGeometryTextureImageUnits") resources->maxGeometryTextureImageUnits = value; - else if (strcmp(token, "MaxGeometryOutputVertices") == 0) + else if (tokenStr == "MaxGeometryOutputVertices") resources->maxGeometryOutputVertices = value; - else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0) + else if (tokenStr == "MaxGeometryTotalOutputComponents") resources->maxGeometryTotalOutputComponents = value; - else if (strcmp(token, "MaxGeometryUniformComponents") == 0) + else if (tokenStr == "MaxGeometryUniformComponents") resources->maxGeometryUniformComponents = value; - else if (strcmp(token, "MaxGeometryVaryingComponents") == 0) + else if (tokenStr == "MaxGeometryVaryingComponents") resources->maxGeometryVaryingComponents = value; - else if (strcmp(token, "MaxTessControlInputComponents") == 0) + else if (tokenStr == "MaxTessControlInputComponents") resources->maxTessControlInputComponents = value; - else if (strcmp(token, "MaxTessControlOutputComponents") == 0) + else if (tokenStr == "MaxTessControlOutputComponents") resources->maxTessControlOutputComponents = value; - else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0) + else if (tokenStr == "MaxTessControlTextureImageUnits") resources->maxTessControlTextureImageUnits = value; - else if (strcmp(token, "MaxTessControlUniformComponents") == 0) + else if (tokenStr == "MaxTessControlUniformComponents") resources->maxTessControlUniformComponents = value; - else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0) + else if (tokenStr == "MaxTessControlTotalOutputComponents") resources->maxTessControlTotalOutputComponents = value; - else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0) + else if (tokenStr == "MaxTessEvaluationInputComponents") resources->maxTessEvaluationInputComponents = value; - else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0) + else if (tokenStr == "MaxTessEvaluationOutputComponents") resources->maxTessEvaluationOutputComponents = value; - else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0) + else if (tokenStr == "MaxTessEvaluationTextureImageUnits") resources->maxTessEvaluationTextureImageUnits = value; - else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0) + else if (tokenStr == "MaxTessEvaluationUniformComponents") resources->maxTessEvaluationUniformComponents = value; - else if (strcmp(token, "MaxTessPatchComponents") == 0) + else if (tokenStr == "MaxTessPatchComponents") resources->maxTessPatchComponents = value; - else if (strcmp(token, "MaxPatchVertices") == 0) + else if (tokenStr == "MaxPatchVertices") resources->maxPatchVertices = value; - else if (strcmp(token, "MaxTessGenLevel") == 0) + else if (tokenStr == "MaxTessGenLevel") resources->maxTessGenLevel = value; - else if (strcmp(token, "MaxViewports") == 0) + else if (tokenStr == "MaxViewports") resources->maxViewports = value; - else if (strcmp(token, "MaxVertexAtomicCounters") == 0) + else if (tokenStr == "MaxVertexAtomicCounters") resources->maxVertexAtomicCounters = value; - else if (strcmp(token, "MaxTessControlAtomicCounters") == 0) + else if (tokenStr == "MaxTessControlAtomicCounters") resources->maxTessControlAtomicCounters = value; - else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0) + else if (tokenStr == "MaxTessEvaluationAtomicCounters") resources->maxTessEvaluationAtomicCounters = value; - else if (strcmp(token, "MaxGeometryAtomicCounters") == 0) + else if (tokenStr == "MaxGeometryAtomicCounters") resources->maxGeometryAtomicCounters = value; - else if (strcmp(token, "MaxFragmentAtomicCounters") == 0) + else if (tokenStr == "MaxFragmentAtomicCounters") resources->maxFragmentAtomicCounters = value; - else if (strcmp(token, "MaxCombinedAtomicCounters") == 0) + else if (tokenStr == "MaxCombinedAtomicCounters") resources->maxCombinedAtomicCounters = value; - else if (strcmp(token, "MaxAtomicCounterBindings") == 0) + else if (tokenStr == "MaxAtomicCounterBindings") resources->maxAtomicCounterBindings = value; - else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0) + else if (tokenStr == "MaxVertexAtomicCounterBuffers") resources->maxVertexAtomicCounterBuffers = value; - else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0) + else if (tokenStr == "MaxTessControlAtomicCounterBuffers") resources->maxTessControlAtomicCounterBuffers = value; - else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0) + else if (tokenStr == "MaxTessEvaluationAtomicCounterBuffers") resources->maxTessEvaluationAtomicCounterBuffers = value; - else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0) + else if (tokenStr == "MaxGeometryAtomicCounterBuffers") resources->maxGeometryAtomicCounterBuffers = value; - else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0) + else if (tokenStr == "MaxFragmentAtomicCounterBuffers") resources->maxFragmentAtomicCounterBuffers = value; - else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0) + else if (tokenStr == "MaxCombinedAtomicCounterBuffers") resources->maxCombinedAtomicCounterBuffers = value; - else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0) + else if (tokenStr == "MaxAtomicCounterBufferSize") resources->maxAtomicCounterBufferSize = value; - else if (strcmp(token, "MaxTransformFeedbackBuffers") == 0) + else if (tokenStr == "MaxTransformFeedbackBuffers") resources->maxTransformFeedbackBuffers = value; - else if (strcmp(token, "MaxTransformFeedbackInterleavedComponents") == 0) + else if (tokenStr == "MaxTransformFeedbackInterleavedComponents") resources->maxTransformFeedbackInterleavedComponents = value; - else if (strcmp(token, "MaxCullDistances") == 0) + else if (tokenStr == "MaxCullDistances") resources->maxCullDistances = value; - else if (strcmp(token, "MaxCombinedClipAndCullDistances") == 0) + else if (tokenStr == "MaxCombinedClipAndCullDistances") resources->maxCombinedClipAndCullDistances = value; - else if (strcmp(token, "MaxSamples") == 0) + else if (tokenStr == "MaxSamples") resources->maxSamples = value; - - else if (strcmp(token, "nonInductiveForLoops") == 0) + else if (tokenStr == "nonInductiveForLoops") resources->limits.nonInductiveForLoops = (value != 0); - else if (strcmp(token, "whileLoops") == 0) + else if (tokenStr == "whileLoops") resources->limits.whileLoops = (value != 0); - else if (strcmp(token, "doWhileLoops") == 0) + else if (tokenStr == "doWhileLoops") resources->limits.doWhileLoops = (value != 0); - else if (strcmp(token, "generalUniformIndexing") == 0) + else if (tokenStr == "generalUniformIndexing") resources->limits.generalUniformIndexing = (value != 0); - else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0) + else if (tokenStr == "generalAttributeMatrixVectorIndexing") resources->limits.generalAttributeMatrixVectorIndexing = (value != 0); - else if (strcmp(token, "generalVaryingIndexing") == 0) + else if (tokenStr == "generalVaryingIndexing") resources->limits.generalVaryingIndexing = (value != 0); - else if (strcmp(token, "generalSamplerIndexing") == 0) + else if (tokenStr == "generalSamplerIndexing") resources->limits.generalSamplerIndexing = (value != 0); - else if (strcmp(token, "generalVariableIndexing") == 0) + else if (tokenStr == "generalVariableIndexing") resources->limits.generalVariableIndexing = (value != 0); - else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0) + else if (tokenStr == "generalConstantMatrixVectorIndexing") resources->limits.generalConstantMatrixVectorIndexing = (value != 0); else - printf("Warning: unrecognized limit (%s) in configuration file.\n", token); + printf("Warning: unrecognized limit (%s) in configuration file.\n", tokenStr.c_str()); - token = strtok(0, delims); } } diff --git a/Externals/glslang/StandAlone/StandAlone.cpp b/Externals/glslang/StandAlone/StandAlone.cpp index 63e9878a5e..6736dbcbf3 100644 --- a/Externals/glslang/StandAlone/StandAlone.cpp +++ b/Externals/glslang/StandAlone/StandAlone.cpp @@ -1,12 +1,12 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2013 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2013-2016 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,25 +20,28 @@ // 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. +// 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. // // this only applies to the standalone wrapper, not the front end in general +#ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS +#endif #include "ResourceLimits.h" #include "Worklist.h" +#include "DirStackFileIncluder.h" #include "./../glslang/Include/ShHandle.h" #include "./../glslang/Include/revision.h" #include "./../glslang/Public/ShaderLang.h" @@ -46,9 +49,15 @@ #include "../SPIRV/GLSL.std.450.h" #include "../SPIRV/doc.h" #include "../SPIRV/disassemble.h" -#include -#include -#include + +#include +#include +#include +#include +#include +#include +#include +#include #include "../glslang/OSDependent/osinclude.h" @@ -58,27 +67,41 @@ extern "C" { // Command-line options enum TOptions { - EOptionNone = 0, - EOptionIntermediate = (1 << 0), - EOptionSuppressInfolog = (1 << 1), - EOptionMemoryLeakMode = (1 << 2), - EOptionRelaxedErrors = (1 << 3), - EOptionGiveWarnings = (1 << 4), - EOptionLinkProgram = (1 << 5), - EOptionMultiThreaded = (1 << 6), - EOptionDumpConfig = (1 << 7), - EOptionDumpReflection = (1 << 8), - EOptionSuppressWarnings = (1 << 9), - EOptionDumpVersions = (1 << 10), - EOptionSpv = (1 << 11), - EOptionHumanReadableSpv = (1 << 12), - EOptionVulkanRules = (1 << 13), - EOptionDefaultDesktop = (1 << 14), - EOptionOutputPreprocessed = (1 << 15), - EOptionOutputHexadecimal = (1 << 16), - EOptionReadHlsl = (1 << 17), - EOptionCascadingErrors = (1 << 18), + EOptionNone = 0, + EOptionIntermediate = (1 << 0), + EOptionSuppressInfolog = (1 << 1), + EOptionMemoryLeakMode = (1 << 2), + EOptionRelaxedErrors = (1 << 3), + EOptionGiveWarnings = (1 << 4), + EOptionLinkProgram = (1 << 5), + EOptionMultiThreaded = (1 << 6), + EOptionDumpConfig = (1 << 7), + EOptionDumpReflection = (1 << 8), + EOptionSuppressWarnings = (1 << 9), + EOptionDumpVersions = (1 << 10), + EOptionSpv = (1 << 11), + EOptionHumanReadableSpv = (1 << 12), + EOptionVulkanRules = (1 << 13), + EOptionDefaultDesktop = (1 << 14), + EOptionOutputPreprocessed = (1 << 15), + EOptionOutputHexadecimal = (1 << 16), + EOptionReadHlsl = (1 << 17), + EOptionCascadingErrors = (1 << 18), + EOptionAutoMapBindings = (1 << 19), + EOptionFlattenUniformArrays = (1 << 20), + EOptionNoStorageFormat = (1 << 21), + EOptionKeepUncalled = (1 << 22), + EOptionHlslOffsets = (1 << 23), + EOptionHlslIoMapping = (1 << 24), + EOptionAutoMapLocations = (1 << 25), + EOptionDebug = (1 << 26), + EOptionStdin = (1 << 27), + EOptionOptimizeDisable = (1 << 28), + EOptionOptimizeSize = (1 << 29), + EOptionInvertY = (1 << 30), + EOptionDumpBareVersion = (1 << 31), }; +bool targetHlslFunctionality1 = false; // // Return codes from main/exit(). @@ -96,20 +119,19 @@ enum TFailCode { // // Forward declarations. // -EShLanguage FindLanguage(const std::string& name); +EShLanguage FindLanguage(const std::string& name, bool parseSuffix=true); void CompileFile(const char* fileName, ShHandle); void usage(); -void FreeFileData(char** data); -char** ReadFileData(const char* fileName); +char* ReadFileData(const char* fileName); +void FreeFileData(char* data); void InfoLogMsg(const char* msg, const char* name, const int num); // Globally track if any compile or link failure. bool CompileFailed = false; bool LinkFailed = false; -// Use to test breaking up a single shader file into multiple strings. -// Set in ReadFileData(). -int NumShaderStrings; +// array of unique places to leave the shader names and infologs for the asynchronous compiles +std::vector> WorkItems; TBuiltInResource Resources; std::string ConfigFile; @@ -119,42 +141,92 @@ std::string ConfigFile; // void ProcessConfigFile() { - char** configStrings = 0; - char* config = 0; - if (ConfigFile.size() > 0) { - configStrings = ReadFileData(ConfigFile.c_str()); - if (configStrings) - config = *configStrings; - else { - printf("Error opening configuration file; will instead use the default configuration\n"); - usage(); - } - } - - if (config == 0) { + if (ConfigFile.size() == 0) Resources = glslang::DefaultTBuiltInResource; - return; + else { + char* configString = ReadFileData(ConfigFile.c_str()); + glslang::DecodeResourceLimits(&Resources, configString); + FreeFileData(configString); } - - glslang::DecodeResourceLimits(&Resources, config); - - if (configStrings) - FreeFileData(configStrings); - else - delete[] config; } -// thread-safe list of shaders to asynchronously grab and compile -glslang::TWorklist Worklist; - -// array of unique places to leave the shader names and infologs for the asynchronous compiles -glslang::TWorkItem** Work = 0; -int NumWorkItems = 0; - int Options = 0; const char* ExecutableName = nullptr; const char* binaryFileName = nullptr; const char* entryPointName = nullptr; +const char* sourceEntryPointName = nullptr; +const char* shaderStageName = nullptr; +const char* variableName = nullptr; +bool HlslEnable16BitTypes = false; +std::vector IncludeDirectoryList; +int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100 +glslang::EShTargetClientVersion VulkanClientVersion = + glslang::EShTargetVulkan_1_0; // would map to, say, Vulkan 1.0 +glslang::EShTargetClientVersion OpenGLClientVersion = + glslang::EShTargetOpenGL_450; // doesn't influence anything yet, but maps to OpenGL 4.50 +glslang::EShTargetLanguageVersion TargetVersion = + glslang::EShTargetSpv_1_0; // maps to, say, SPIR-V 1.0 +std::vector Processes; // what should be recorded by OpModuleProcessed, or equivalent + +// Per descriptor-set binding base data +typedef std::map TPerSetBaseBinding; + +std::array, glslang::EResCount> baseBinding; +std::array, glslang::EResCount> baseBindingForSet; +std::array, EShLangCount> baseResourceSetBinding; + +// Add things like "#define ..." to a preamble to use in the beginning of the shader. +class TPreamble { +public: + TPreamble() { } + + bool isSet() const { return text.size() > 0; } + const char* get() const { return text.c_str(); } + + // #define... + void addDef(std::string def) + { + text.append("#define "); + fixLine(def); + + Processes.push_back("D"); + Processes.back().append(def); + + // The first "=" needs to turn into a space + const size_t equal = def.find_first_of("="); + if (equal != def.npos) + def[equal] = ' '; + + text.append(def); + text.append("\n"); + } + + // #undef... + void addUndef(std::string undef) + { + text.append("#undef "); + fixLine(undef); + + Processes.push_back("U"); + Processes.back().append(undef); + + text.append(undef); + text.append("\n"); + } + +protected: + void fixLine(std::string& line) + { + // Can't go past a newline in the line + const size_t end = line.find_first_of("\n"); + if (end != line.npos) + line = line.substr(0, end); + } + + std::string text; // contents of preamble +}; + +TPreamble UserPreamble; // // Create the default name for saving a binary if -o is not provided. @@ -199,73 +271,357 @@ bool SetConfigFile(const std::string& name) // void Error(const char* message) { - printf("%s: Error %s (use -h for usage)\n", ExecutableName, message); + fprintf(stderr, "%s: Error %s (use -h for usage)\n", ExecutableName, message); exit(EFailUsage); } +// +// Process an optional binding base of one the forms: +// --argname [stage] base // base for stage (if given) or all stages (if not) +// --argname [stage] [base set]... // set/base pairs: set the base for given binding set. + +// Where stage is one of the forms accepted by FindLanguage, and base is an integer +// +void ProcessBindingBase(int& argc, char**& argv, glslang::TResourceType res) +{ + if (argc < 2) + usage(); + + EShLanguage lang = EShLangCount; + int singleBase = 0; + TPerSetBaseBinding perSetBase; + int arg = 1; + + // Parse stage, if given + if (!isdigit(argv[arg][0])) { + if (argc < 3) // this form needs one more argument + usage(); + + lang = FindLanguage(argv[arg++], false); + } + + if ((argc - arg) > 2 && isdigit(argv[arg+0][0]) && isdigit(argv[arg+1][0])) { + // Parse a per-set binding base + while ((argc - arg) > 2 && isdigit(argv[arg+0][0]) && isdigit(argv[arg+1][0])) { + const int baseNum = atoi(argv[arg++]); + const int setNum = atoi(argv[arg++]); + perSetBase[setNum] = baseNum; + } + } else { + // Parse single binding base + singleBase = atoi(argv[arg++]); + } + + argc -= (arg-1); + argv += (arg-1); + + // Set one or all languages + const int langMin = (lang < EShLangCount) ? lang+0 : 0; + const int langMax = (lang < EShLangCount) ? lang+1 : EShLangCount; + + for (int lang = langMin; lang < langMax; ++lang) { + if (!perSetBase.empty()) + baseBindingForSet[res][lang] = perSetBase; + else + baseBinding[res][lang] = singleBase; + } +} + +void ProcessResourceSetBindingBase(int& argc, char**& argv, std::array, EShLangCount>& base) +{ + if (argc < 2) + usage(); + + if (!isdigit(argv[1][0])) { + if (argc < 3) // this form needs one more argument + usage(); + + // Parse form: --argname stage [regname set base...], or: + // --argname stage set + const EShLanguage lang = FindLanguage(argv[1], false); + + argc--; + argv++; + + while (argc > 1 && argv[1] != nullptr && argv[1][0] != '-') { + base[lang].push_back(argv[1]); + + argc--; + argv++; + } + + // Must have one arg, or a multiple of three (for [regname set binding] triples) + if (base[lang].size() != 1 && (base[lang].size() % 3) != 0) + usage(); + + } else { + // Parse form: --argname set + for (int lang=0; lang>& workItems, int argc, char* argv[]) { - ExecutableName = argv[0]; - NumWorkItems = argc; // will include some empties where the '-' options were, but it doesn't matter, they'll be 0 - Work = new glslang::TWorkItem*[NumWorkItems]; - for (int w = 0; w < NumWorkItems; ++w) - Work[w] = 0; + for (int res = 0; res < glslang::EResCount; ++res) + baseBinding[res].fill(0); - argc--; - argv++; - for (; argc >= 1; argc--, argv++) { + ExecutableName = argv[0]; + workItems.reserve(argc); + + const auto bumpArg = [&]() { + if (argc > 0) { + argc--; + argv++; + } + }; + + // read a string directly attached to a single-letter option + const auto getStringOperand = [&](const char* desc) { + if (argv[0][2] == 0) { + printf("%s must immediately follow option (no spaces)\n", desc); + exit(EFailUsage); + } + return argv[0] + 2; + }; + + // read a number attached to a single-letter option + const auto getAttachedNumber = [&](const char* desc) { + int num = atoi(argv[0] + 2); + if (num == 0) { + printf("%s: expected attached non-0 number\n", desc); + exit(EFailUsage); + } + return num; + }; + + // minimum needed (without overriding something else) to target Vulkan SPIR-V + const auto setVulkanSpv = []() { + Options |= EOptionSpv; + Options |= EOptionVulkanRules; + Options |= EOptionLinkProgram; + }; + + // minimum needed (without overriding something else) to target OpenGL SPIR-V + const auto setOpenGlSpv = []() { + Options |= EOptionSpv; + Options |= EOptionLinkProgram; + // undo a -H default to Vulkan + Options &= ~EOptionVulkanRules; + }; + + for (bumpArg(); argc >= 1; bumpArg()) { if (argv[0][0] == '-') { switch (argv[0][1]) { - case 'H': - Options |= EOptionHumanReadableSpv; - if ((Options & EOptionSpv) == 0) { - // default to Vulkan - Options |= EOptionSpv; - Options |= EOptionVulkanRules; - Options |= EOptionLinkProgram; + case '-': + { + std::string lowerword(argv[0]+2); + std::transform(lowerword.begin(), lowerword.end(), lowerword.begin(), ::tolower); + + // handle --word style options + if (lowerword == "auto-map-bindings" || // synonyms + lowerword == "auto-map-binding" || + lowerword == "amb") { + Options |= EOptionAutoMapBindings; + } else if (lowerword == "auto-map-locations" || // synonyms + lowerword == "aml") { + Options |= EOptionAutoMapLocations; + } else if (lowerword == "client") { + if (argc > 1) { + if (strcmp(argv[1], "vulkan100") == 0) + setVulkanSpv(); + else if (strcmp(argv[1], "opengl100") == 0) + setOpenGlSpv(); + else + Error("--client expects vulkan100 or opengl100"); + } + bumpArg(); + } else if (lowerword == "flatten-uniform-arrays" || // synonyms + lowerword == "flatten-uniform-array" || + lowerword == "fua") { + Options |= EOptionFlattenUniformArrays; + } else if (lowerword == "hlsl-offsets") { + Options |= EOptionHlslOffsets; + } else if (lowerword == "hlsl-iomap" || + lowerword == "hlsl-iomapper" || + lowerword == "hlsl-iomapping") { + Options |= EOptionHlslIoMapping; + } else if (lowerword == "hlsl-enable-16bit-types") { + HlslEnable16BitTypes = true; + } else if (lowerword == "invert-y" || // synonyms + lowerword == "iy") { + Options |= EOptionInvertY; + } else if (lowerword == "keep-uncalled" || // synonyms + lowerword == "ku") { + Options |= EOptionKeepUncalled; + } else if (lowerword == "no-storage-format" || // synonyms + lowerword == "nsf") { + Options |= EOptionNoStorageFormat; + } else if (lowerword == "relaxed-errors") { + Options |= EOptionRelaxedErrors; + } else if (lowerword == "resource-set-bindings" || // synonyms + lowerword == "resource-set-binding" || + lowerword == "rsb") { + ProcessResourceSetBindingBase(argc, argv, baseResourceSetBinding); + } else if (lowerword == "shift-image-bindings" || // synonyms + lowerword == "shift-image-binding" || + lowerword == "sib") { + ProcessBindingBase(argc, argv, glslang::EResImage); + } else if (lowerword == "shift-sampler-bindings" || // synonyms + lowerword == "shift-sampler-binding" || + lowerword == "ssb") { + ProcessBindingBase(argc, argv, glslang::EResSampler); + } else if (lowerword == "shift-uav-bindings" || // synonyms + lowerword == "shift-uav-binding" || + lowerword == "suavb") { + ProcessBindingBase(argc, argv, glslang::EResUav); + } else if (lowerword == "shift-texture-bindings" || // synonyms + lowerword == "shift-texture-binding" || + lowerword == "stb") { + ProcessBindingBase(argc, argv, glslang::EResTexture); + } else if (lowerword == "shift-ubo-bindings" || // synonyms + lowerword == "shift-ubo-binding" || + lowerword == "shift-cbuffer-bindings" || + lowerword == "shift-cbuffer-binding" || + lowerword == "sub" || + lowerword == "scb") { + ProcessBindingBase(argc, argv, glslang::EResUbo); + } else if (lowerword == "shift-ssbo-bindings" || // synonyms + lowerword == "shift-ssbo-binding" || + lowerword == "sbb") { + ProcessBindingBase(argc, argv, glslang::EResSsbo); + } else if (lowerword == "source-entrypoint" || // synonyms + lowerword == "sep") { + if (argc <= 1) + Error("no provided for --source-entrypoint"); + sourceEntryPointName = argv[1]; + bumpArg(); + break; + } else if (lowerword == "stdin") { + Options |= EOptionStdin; + shaderStageName = argv[1]; + } else if (lowerword == "suppress-warnings") { + Options |= EOptionSuppressWarnings; + } else if (lowerword == "target-env") { + if (argc > 1) { + if (strcmp(argv[1], "vulkan1.0") == 0) { + setVulkanSpv(); + VulkanClientVersion = glslang::EShTargetVulkan_1_0; + } else if (strcmp(argv[1], "vulkan1.1") == 0) { + setVulkanSpv(); + TargetVersion = glslang::EShTargetSpv_1_3; + VulkanClientVersion = glslang::EShTargetVulkan_1_1; + } else if (strcmp(argv[1], "opengl") == 0) { + setOpenGlSpv(); + OpenGLClientVersion = glslang::EShTargetOpenGL_450; + } else + Error("--target-env expected vulkan1.0, vulkan1.1, or opengl"); + } + bumpArg(); + } else if (lowerword == "variable-name" || // synonyms + lowerword == "vn") { + Options |= EOptionOutputHexadecimal; + if (argc <= 1) + Error("no provided for --variable-name"); + variableName = argv[1]; + bumpArg(); + break; + } else if (lowerword == "version") { + Options |= EOptionDumpVersions; + } else { + usage(); + } } break; - case 'V': - Options |= EOptionSpv; - Options |= EOptionVulkanRules; - Options |= EOptionLinkProgram; - break; - case 'G': - Options |= EOptionSpv; - Options |= EOptionLinkProgram; - // undo a -H default to Vulkan - Options &= ~EOptionVulkanRules; - break; - case 'E': - Options |= EOptionOutputPreprocessed; - break; - case 'c': - Options |= EOptionDumpConfig; - break; case 'C': Options |= EOptionCascadingErrors; break; - case 'd': - Options |= EOptionDefaultDesktop; - break; case 'D': - Options |= EOptionReadHlsl; + if (argv[0][2] == 0) + Options |= EOptionReadHlsl; + else + UserPreamble.addDef(getStringOperand("-D macro name")); + break; + case 'E': + Options |= EOptionOutputPreprocessed; + break; + case 'G': + // OpenGL Client + setOpenGlSpv(); + if (argv[0][2] != 0) + ClientInputSemanticsVersion = getAttachedNumber("-G client input semantics"); + break; + case 'H': + Options |= EOptionHumanReadableSpv; + if ((Options & EOptionSpv) == 0) { + // default to Vulkan + setVulkanSpv(); + } + break; + case 'I': + IncludeDirectoryList.push_back(getStringOperand("-I include path")); + break; + case 'O': + if (argv[0][2] == 'd') + Options |= EOptionOptimizeDisable; + else if (argv[0][2] == 's') +#if ENABLE_OPT + Options |= EOptionOptimizeSize; +#else + Error("-Os not available; optimizer not linked"); +#endif + else + Error("unknown -O option"); + break; + case 'S': + if (argc <= 1) + Error("no specified for -S"); + shaderStageName = argv[1]; + bumpArg(); + break; + case 'U': + UserPreamble.addUndef(getStringOperand("-U: macro name")); + break; + case 'V': + setVulkanSpv(); + if (argv[0][2] != 0) + ClientInputSemanticsVersion = getAttachedNumber("-V client input semantics"); + break; + case 'c': + Options |= EOptionDumpConfig; + break; + case 'd': + if (strncmp(&argv[0][1], "dumpversion", strlen(&argv[0][1]) + 1) == 0 || + strncmp(&argv[0][1], "dumpfullversion", strlen(&argv[0][1]) + 1) == 0) + Options |= EOptionDumpBareVersion; + else + Options |= EOptionDefaultDesktop; break; case 'e': // HLSL todo: entry point handle needs much more sophistication. // This is okay for one compilation unit with one entry point. entryPointName = argv[1]; - if (argc > 0) { - argc--; - argv++; - } else - Error("no provided for -e"); + if (argc <= 1) + Error("no provided for -e"); + bumpArg(); + break; + case 'f': + if (strcmp(&argv[0][2], "hlsl_functionality1") == 0) + targetHlslFunctionality1 = true; + else + Error("-f: expected hlsl_functionality1"); + break; + case 'g': + Options |= EOptionDebug; break; case 'h': usage(); @@ -280,12 +636,10 @@ void ProcessArguments(int argc, char* argv[]) Options |= EOptionMemoryLeakMode; break; case 'o': - binaryFileName = argv[1]; - if (argc > 0) { - argc--; - argv++; - } else + if (argc <= 1) Error("no provided for -o"); + binaryFileName = argv[1]; + bumpArg(); break; case 'q': Options |= EOptionDumpReflection; @@ -297,9 +651,7 @@ void ProcessArguments(int argc, char* argv[]) Options |= EOptionSuppressInfolog; break; case 't': - #ifdef _WIN32 - Options |= EOptionMultiThreaded; - #endif + Options |= EOptionMultiThreaded; break; case 'v': Options |= EOptionDumpVersions; @@ -317,12 +669,15 @@ void ProcessArguments(int argc, char* argv[]) } else { std::string name(argv[0]); if (! SetConfigFile(name)) { - Work[argc] = new glslang::TWorkItem(name); - Worklist.add(Work[argc]); + workItems.push_back(std::unique_ptr(new glslang::TWorkItem(name))); } } } + // Make sure that -S is always specified if --stdin is specified + if ((Options & EOptionStdin) && shaderStageName == nullptr) + Error("must provide -S when --stdin is given"); + // Make sure that -E is not specified alongside linking (which includes SPV generation) if ((Options & EOptionOutputPreprocessed) && (Options & EOptionLinkProgram)) Error("can't use -E when linking is selected"); @@ -330,6 +685,10 @@ void ProcessArguments(int argc, char* argv[]) // -o or -x makes no sense if there is no target binary if (binaryFileName && (Options & EOptionSpv) == 0) Error("no binary generation requested (e.g., -V)"); + + if ((Options & EOptionFlattenUniformArrays) != 0 && + (Options & EOptionReadHlsl) == 0) + Error("uniform array flattening only valid when compiling HLSL source."); } // @@ -353,30 +712,53 @@ void SetMessageOptions(EShMessages& messages) messages = (EShMessages)(messages | EShMsgReadHlsl); if (Options & EOptionCascadingErrors) messages = (EShMessages)(messages | EShMsgCascadingErrors); + if (Options & EOptionKeepUncalled) + messages = (EShMessages)(messages | EShMsgKeepUncalled); + if (Options & EOptionHlslOffsets) + messages = (EShMessages)(messages | EShMsgHlslOffsets); + if (Options & EOptionDebug) + messages = (EShMessages)(messages | EShMsgDebugInfo); + if (HlslEnable16BitTypes) + messages = (EShMessages)(messages | EShMsgHlslEnable16BitTypes); + if ((Options & EOptionOptimizeDisable) || !ENABLE_OPT) + messages = (EShMessages)(messages | EShMsgHlslLegalization); } // // Thread entry point, for non-linking asynchronous mode. // -// Return 0 for failure, 1 for success. -// -unsigned int CompileShaders(void*) +void CompileShaders(glslang::TWorklist& worklist) { + if (Options & EOptionDebug) + Error("cannot generate debug information unless linking to generate code"); + glslang::TWorkItem* workItem; - while (Worklist.remove(workItem)) { - ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options); + if (Options & EOptionStdin) { + worklist.remove(workItem); + ShHandle compiler = ShConstructCompiler(FindLanguage("stdin"), Options); if (compiler == 0) - return 0; + return; - CompileFile(workItem->name.c_str(), compiler); + CompileFile("stdin", compiler); - if (! (Options & EOptionSuppressInfolog)) - workItem->results = ShGetInfoLog(compiler); + if (! (Options & EOptionSuppressInfolog)) + workItem->results = ShGetInfoLog(compiler); ShDestruct(compiler); - } + } else { + while (worklist.remove(workItem)) { + ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options); + if (compiler == 0) + return; - return 0; + CompileFile(workItem->name.c_str(), compiler); + + if (! (Options & EOptionSuppressInfolog)) + workItem->results = ShGetInfoLog(compiler); + + ShDestruct(compiler); + } + } } // Outputs the given string, but only if it is non-null and non-empty. @@ -392,17 +774,41 @@ void PutsIfNonEmpty(const char* str) // This prevents erroneous newlines from appearing. void StderrIfNonEmpty(const char* str) { - if (str && str[0]) { - fprintf(stderr, "%s\n", str); - } + if (str && str[0]) + fprintf(stderr, "%s\n", str); } // Simple bundling of what makes a compilation unit for ease in passing around, // and separation of handling file IO versus API (programmatic) compilation. struct ShaderCompUnit { EShLanguage stage; - std::string fileName; - char** text; // memory owned/managed externally + static const int maxCount = 1; + int count; // live number of strings/names + const char* text[maxCount]; // memory owned/managed externally + std::string fileName[maxCount]; // hold's the memory, but... + const char* fileNameList[maxCount]; // downstream interface wants pointers + + ShaderCompUnit(EShLanguage stage) : stage(stage), count(0) { } + + ShaderCompUnit(const ShaderCompUnit& rhs) + { + stage = rhs.stage; + count = rhs.count; + for (int i = 0; i < count; ++i) { + fileName[i] = rhs.fileName[i]; + text[i] = rhs.text[i]; + fileNameList[i] = rhs.fileName[i].c_str(); + } + } + + void addString(std::string& ifileName, const char* itext) + { + assert(count < maxCount); + fileName[count] = ifileName; + text[count] = itext; + fileNameList[count] = fileName[count].c_str(); + ++count; + } }; // @@ -429,16 +835,77 @@ void CompileAndLinkShaderUnits(std::vector compUnits) for (auto it = compUnits.cbegin(); it != compUnits.cend(); ++it) { const auto &compUnit = *it; glslang::TShader* shader = new glslang::TShader(compUnit.stage); - shader->setStrings(compUnit.text, 1); + shader->setStringsWithLengthsAndNames(compUnit.text, NULL, compUnit.fileNameList, compUnit.count); if (entryPointName) // HLSL todo: this needs to be tracked per compUnits shader->setEntryPoint(entryPointName); + if (sourceEntryPointName) { + if (entryPointName == nullptr) + printf("Warning: Changing source entry point name without setting an entry-point name.\n" + "Use '-e '.\n"); + shader->setSourceEntryPoint(sourceEntryPointName); + } + if (UserPreamble.isSet()) + shader->setPreamble(UserPreamble.get()); + shader->addProcesses(Processes); + + // Set IO mapper binding shift values + for (int r = 0; r < glslang::EResCount; ++r) { + const glslang::TResourceType res = glslang::TResourceType(r); + + // Set base bindings + shader->setShiftBinding(res, baseBinding[res][compUnit.stage]); + + // Set bindings for particular resource sets + // TODO: use a range based for loop here, when available in all environments. + for (auto i = baseBindingForSet[res][compUnit.stage].begin(); + i != baseBindingForSet[res][compUnit.stage].end(); ++i) + shader->setShiftBindingForSet(res, i->second, i->first); + } + + shader->setFlattenUniformArrays((Options & EOptionFlattenUniformArrays) != 0); + shader->setNoStorageFormat((Options & EOptionNoStorageFormat) != 0); + shader->setResourceSetBinding(baseResourceSetBinding[compUnit.stage]); + + if (Options & EOptionHlslIoMapping) + shader->setHlslIoMapping(true); + + if (Options & EOptionAutoMapBindings) + shader->setAutoMapBindings(true); + + if (Options & EOptionAutoMapLocations) + shader->setAutoMapLocations(true); + + if (Options & EOptionInvertY) + shader->setInvertY(true); + + // Set up the environment, some subsettings take precedence over earlier + // ways of setting things. + if (Options & EOptionSpv) { + if (Options & EOptionVulkanRules) { + shader->setEnvInput((Options & EOptionReadHlsl) ? glslang::EShSourceHlsl + : glslang::EShSourceGlsl, + compUnit.stage, glslang::EShClientVulkan, ClientInputSemanticsVersion); + shader->setEnvClient(glslang::EShClientVulkan, VulkanClientVersion); + } else { + shader->setEnvInput((Options & EOptionReadHlsl) ? glslang::EShSourceHlsl + : glslang::EShSourceGlsl, + compUnit.stage, glslang::EShClientOpenGL, ClientInputSemanticsVersion); + shader->setEnvClient(glslang::EShClientOpenGL, OpenGLClientVersion); + } + shader->setEnvTarget(glslang::EShTargetSpv, TargetVersion); + if (targetHlslFunctionality1) + shader->setEnvTargetHlslFunctionality1(); + } + shaders.push_back(shader); - const int defaultVersion = Options & EOptionDefaultDesktop? 110: 100; + const int defaultVersion = Options & EOptionDefaultDesktop ? 110 : 100; + DirStackFileIncluder includer; + std::for_each(IncludeDirectoryList.rbegin(), IncludeDirectoryList.rend(), [&includer](const std::string& dir) { + includer.pushExternalLocalDirectory(dir); }); if (Options & EOptionOutputPreprocessed) { std::string str; - glslang::TShader::ForbidInclude includer; if (shader->preprocess(&Resources, defaultVersion, ENoProfile, false, false, messages, &str, includer)) { PutsIfNonEmpty(str.c_str()); @@ -449,14 +916,14 @@ void CompileAndLinkShaderUnits(std::vector compUnits) StderrIfNonEmpty(shader->getInfoDebugLog()); continue; } - if (! shader->parse(&Resources, defaultVersion, false, messages)) + if (! shader->parse(&Resources, defaultVersion, false, messages, includer)) CompileFailed = true; program.addShader(shader); if (! (Options & EOptionSuppressInfolog) && ! (Options & EOptionMemoryLeakMode)) { - PutsIfNonEmpty(compUnit.fileName.c_str()); + PutsIfNonEmpty(compUnit.fileName[0].c_str()); PutsIfNonEmpty(shader->getInfoLog()); PutsIfNonEmpty(shader->getInfoDebugLog()); } @@ -470,6 +937,12 @@ void CompileAndLinkShaderUnits(std::vector compUnits) if (! (Options & EOptionOutputPreprocessed) && ! program.link(messages)) LinkFailed = true; + // Map IO + if (Options & EOptionSpv) { + if (!program.mapIO()) + LinkFailed = true; + } + // Report if (! (Options & EOptionSuppressInfolog) && ! (Options & EOptionMemoryLeakMode)) { @@ -493,14 +966,19 @@ void CompileAndLinkShaderUnits(std::vector compUnits) std::vector spirv; std::string warningsErrors; spv::SpvBuildLogger logger; - glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv, &logger); + glslang::SpvOptions spvOptions; + if (Options & EOptionDebug) + spvOptions.generateDebugInfo = true; + spvOptions.disableOptimizer = (Options & EOptionOptimizeDisable) != 0; + spvOptions.optimizeSize = (Options & EOptionOptimizeSize) != 0; + glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv, &logger, &spvOptions); // Dump the spv to a file or stdout, etc., but only if not doing // memory/perf testing, as it's not internal to programmatic use. if (! (Options & EOptionMemoryLeakMode)) { printf("%s", logger.getAllMessages().c_str()); if (Options & EOptionOutputHexadecimal) { - glslang::OutputSpvHex(spirv, GetBinaryName((EShLanguage)stage)); + glslang::OutputSpvHex(spirv, GetBinaryName((EShLanguage)stage), variableName); } else { glslang::OutputSpvBin(spirv, GetBinaryName((EShLanguage)stage)); } @@ -537,29 +1015,36 @@ void CompileAndLinkShaderUnits(std::vector compUnits) // performance and memory testing, the actual compile/link can be put in // a loop, independent of processing the work items and file IO. // -void CompileAndLinkShaderFiles() +void CompileAndLinkShaderFiles(glslang::TWorklist& Worklist) { std::vector compUnits; - // Transfer all the work items from to a simple list of - // of compilation units. (We don't care about the thread - // work-item distribution properties in this path, which - // is okay due to the limited number of shaders, know since - // they are all getting linked together.) - glslang::TWorkItem* workItem; - while (Worklist.remove(workItem)) { - ShaderCompUnit compUnit = { - FindLanguage(workItem->name), - workItem->name, - ReadFileData(workItem->name.c_str()) - }; - - if (! compUnit.text) { - usage(); - return; - } - + // If this is using stdin, we can't really detect multiple different file + // units by input type. We need to assume that we're just being given one + // file of a certain type. + if ((Options & EOptionStdin) != 0) { + ShaderCompUnit compUnit(FindLanguage("stdin")); + std::istreambuf_iterator begin(std::cin), end; + std::string tempString(begin, end); + char* fileText = strdup(tempString.c_str()); + std::string fileName = "stdin"; + compUnit.addString(fileName, fileText); compUnits.push_back(compUnit); + } else { + // Transfer all the work items from to a simple list of + // of compilation units. (We don't care about the thread + // work-item distribution properties in this path, which + // is okay due to the limited number of shaders, know since + // they are all getting linked together.) + glslang::TWorkItem* workItem; + while (Worklist.remove(workItem)) { + ShaderCompUnit compUnit(FindLanguage(workItem->name)); + char* fileText = ReadFileData(workItem->name.c_str()); + if (fileText == nullptr) + usage(); + compUnit.addString(workItem->name, fileText); + compUnits.push_back(compUnit); + } } // Actual call to programmatic processing of compile and link, @@ -573,22 +1058,34 @@ void CompileAndLinkShaderFiles() glslang::OS_DumpMemoryCounters(); } + // free memory from ReadFileData, which got stored in a const char* + // as the first string above for (auto it = compUnits.begin(); it != compUnits.end(); ++it) - FreeFileData(it->text); + FreeFileData(const_cast(it->text[0])); } -int C_DECL main(int argc, char* argv[]) +int singleMain() { - ProcessArguments(argc, argv); + glslang::TWorklist workList; + std::for_each(WorkItems.begin(), WorkItems.end(), [&workList](std::unique_ptr& item) { + assert(item); + workList.add(item.get()); + }); if (Options & EOptionDumpConfig) { printf("%s", glslang::GetDefaultTBuiltInResourceString().c_str()); - if (Worklist.empty()) + if (workList.empty()) return ESuccess; } - if (Options & EOptionDumpVersions) { - printf("Glslang Version: %s %s\n", GLSLANG_REVISION, GLSLANG_DATE); + if (Options & EOptionDumpBareVersion) { + printf("%d.%d.%d\n", + glslang::GetSpirvGeneratorVersion(), GLSLANG_MINOR_VERSION, GLSLANG_PATCH_LEVEL); + if (workList.empty()) + return ESuccess; + } else if (Options & EOptionDumpVersions) { + printf("Glslang Version: %d.%d.%d\n", + glslang::GetSpirvGeneratorVersion(), GLSLANG_MINOR_VERSION, GLSLANG_PATCH_LEVEL); printf("ESSL Version: %s\n", glslang::GetEsslVersionString()); printf("GLSL Version: %s\n", glslang::GetGlslVersionString()); std::string spirvVersion; @@ -596,14 +1093,22 @@ int C_DECL main(int argc, char* argv[]) printf("SPIR-V Version %s\n", spirvVersion.c_str()); printf("GLSL.std.450 Version %d, Revision %d\n", GLSLstd450Version, GLSLstd450Revision); printf("Khronos Tool ID %d\n", glslang::GetKhronosToolId()); - if (Worklist.empty()) + printf("SPIR-V Generator Version %d\n", glslang::GetSpirvGeneratorVersion()); + printf("GL_KHR_vulkan_glsl version %d\n", 100); + printf("ARB_GL_gl_spirv version %d\n", 100); + if (workList.empty()) return ESuccess; } - if (Worklist.empty()) { + if (workList.empty() && ((Options & EOptionStdin) == 0)) { usage(); } + if (Options & EOptionStdin) { + WorkItems.push_back(std::unique_ptr{new glslang::TWorkItem("stdin")}); + workList.add(WorkItems.back().get()); + } + ProcessConfigFile(); // @@ -614,47 +1119,45 @@ int C_DECL main(int argc, char* argv[]) if (Options & EOptionLinkProgram || Options & EOptionOutputPreprocessed) { glslang::InitializeProcess(); - CompileAndLinkShaderFiles(); + glslang::InitializeProcess(); // also test reference counting of users + glslang::InitializeProcess(); // also test reference counting of users + glslang::FinalizeProcess(); // also test reference counting of users + glslang::FinalizeProcess(); // also test reference counting of users + CompileAndLinkShaderFiles(workList); glslang::FinalizeProcess(); - for (int w = 0; w < NumWorkItems; ++w) { - if (Work[w]) { - delete Work[w]; - } - } } else { ShInitialize(); + ShInitialize(); // also test reference counting of users + ShFinalize(); // also test reference counting of users - bool printShaderNames = Worklist.size() > 1; + bool printShaderNames = workList.size() > 1; if (Options & EOptionMultiThreaded) { - const int NumThreads = 16; - void* threads[NumThreads]; - for (int t = 0; t < NumThreads; ++t) { - threads[t] = glslang::OS_CreateThread(&CompileShaders); - if (! threads[t]) { - printf("Failed to create thread\n"); + std::array threads; + for (unsigned int t = 0; t < threads.size(); ++t) { + threads[t] = std::thread(CompileShaders, std::ref(workList)); + if (threads[t].get_id() == std::thread::id()) { + fprintf(stderr, "Failed to create thread\n"); return EFailThreadCreate; } } - glslang::OS_WaitForAllThreads(threads, NumThreads); + + std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); }); } else - CompileShaders(0); + CompileShaders(workList); // Print out all the resulting infologs - for (int w = 0; w < NumWorkItems; ++w) { - if (Work[w]) { - if (printShaderNames || Work[w]->results.size() > 0) - PutsIfNonEmpty(Work[w]->name.c_str()); - PutsIfNonEmpty(Work[w]->results.c_str()); - delete Work[w]; + for (size_t w = 0; w < WorkItems.size(); ++w) { + if (WorkItems[w]) { + if (printShaderNames || WorkItems[w]->results.size() > 0) + PutsIfNonEmpty(WorkItems[w]->name.c_str()); + PutsIfNonEmpty(WorkItems[w]->results.c_str()); } } ShFinalize(); } - delete[] Work; - if (CompileFailed) return EFailCompile; if (LinkFailed) @@ -663,6 +1166,25 @@ int C_DECL main(int argc, char* argv[]) return 0; } +int C_DECL main(int argc, char* argv[]) +{ + ProcessArguments(WorkItems, argc, argv); + + int ret = 0; + + // Loop over the entire init/finalize cycle to watch memory changes + const int iterations = 1; + if (iterations > 1) + glslang::OS_DumpMemoryCounters(); + for (int i = 0; i < iterations; ++i) { + ret = singleMain(); + if (iterations > 1) + glslang::OS_DumpMemoryCounters(); + } + + return ret; +} + // // Deduce the language from the filename. Files must end in one of the // following extensions: @@ -674,26 +1196,48 @@ int C_DECL main(int argc, char* argv[]) // .frag = fragment // .comp = compute // -EShLanguage FindLanguage(const std::string& name) +// Additionally, the file names may end in ..glsl and ..hlsl +// where is one of the stages listed above. +// +EShLanguage FindLanguage(const std::string& name, bool parseStageName) { - size_t ext = name.rfind('.'); - if (ext == std::string::npos) { - usage(); - return EShLangVertex; - } + std::string stageName; + if (shaderStageName) + stageName = shaderStageName; + else if (parseStageName) { + // Note: "first" extension means "first from the end", i.e. + // if the file is named foo.vert.glsl, then "glsl" is first, + // "vert" is second. + size_t firstExtStart = name.find_last_of("."); + bool hasFirstExt = firstExtStart != std::string::npos; + size_t secondExtStart = hasFirstExt ? name.find_last_of(".", firstExtStart - 1) : std::string::npos; + bool hasSecondExt = secondExtStart != std::string::npos; + std::string firstExt = name.substr(firstExtStart + 1, std::string::npos); + bool usesUnifiedExt = hasFirstExt && (firstExt == "glsl" || firstExt == "hlsl"); + if (usesUnifiedExt && firstExt == "hlsl") + Options |= EOptionReadHlsl; + if (hasFirstExt && !usesUnifiedExt) + stageName = firstExt; + else if (usesUnifiedExt && hasSecondExt) + stageName = name.substr(secondExtStart + 1, firstExtStart - secondExtStart - 1); + else { + usage(); + return EShLangVertex; + } + } else + stageName = name; - std::string suffix = name.substr(ext + 1, std::string::npos); - if (suffix == "vert") + if (stageName == "vert") return EShLangVertex; - else if (suffix == "tesc") + else if (stageName == "tesc") return EShLangTessControl; - else if (suffix == "tese") + else if (stageName == "tese") return EShLangTessEvaluation; - else if (suffix == "geom") + else if (stageName == "geom") return EShLangGeometry; - else if (suffix == "frag") + else if (stageName == "frag") return EShLangFragment; - else if (suffix == "comp") + else if (stageName == "comp") return EShLangCompute; usage(); @@ -701,40 +1245,40 @@ EShLanguage FindLanguage(const std::string& name) } // -// Read a file's data into a string, and compile it using the old interface ShCompile, +// Read a file's data into a string, and compile it using the old interface ShCompile, // for non-linkable results. // void CompileFile(const char* fileName, ShHandle compiler) { int ret = 0; - char** shaderStrings = ReadFileData(fileName); - if (! shaderStrings) { - usage(); + char* shaderString; + if ((Options & EOptionStdin) != 0) { + std::istreambuf_iterator begin(std::cin), end; + std::string tempString(begin, end); + shaderString = strdup(tempString.c_str()); + } else { + shaderString = ReadFileData(fileName); } - int* lengths = new int[NumShaderStrings]; - // move to length-based strings, rather than null-terminated strings - for (int s = 0; s < NumShaderStrings; ++s) - lengths[s] = (int)strlen(shaderStrings[s]); - - if (! shaderStrings) { - CompileFailed = true; - return; - } + int* lengths = new int[1]; + lengths[0] = (int)strlen(shaderString); EShMessages messages = EShMsgDefault; SetMessageOptions(messages); - + + if (UserPreamble.isSet()) + Error("-D and -U options require -l (linking)\n"); + for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) { for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) { - //ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages); - ret = ShCompile(compiler, shaderStrings, NumShaderStrings, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages); - //const char* multi[12] = { "# ve", "rsion", " 300 e", "s", "\n#err", - // "or should be l", "ine 1", "string 5\n", "float glo", "bal", + // ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages); + ret = ShCompile(compiler, &shaderString, 1, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages); + // const char* multi[12] = { "# ve", "rsion", " 300 e", "s", "\n#err", + // "or should be l", "ine 1", "string 5\n", "float glo", "bal", // ";\n#error should be line 2\n void main() {", "global = 2.3;}" }; - //const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" }; - //ret = ShCompile(compiler, multi, 7, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages); + // const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" }; + // ret = ShCompile(compiler, multi, 7, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages); } if (Options & EOptionMemoryLeakMode) @@ -742,7 +1286,7 @@ void CompileFile(const char* fileName, ShHandle compiler) } delete [] lengths; - FreeFileData(shaderStrings); + FreeFileData(shaderString); if (ret == 0) CompileFailed = true; @@ -755,8 +1299,8 @@ void usage() { printf("Usage: glslangValidator [option]... [file]...\n" "\n" - "Where: each 'file' ends in ., where is one of\n" - " .conf to provide an optional config file that replaces the default configuration\n" + "'file' can end in . for auto-stage classification, where is:\n" + " .conf to provide a config file that replaces the default configuration\n" " (see -c option below for generating a template)\n" " .vert for a vertex shader\n" " .tesc for a tessellation control shader\n" @@ -764,37 +1308,123 @@ void usage() " .geom for a geometry shader\n" " .frag for a fragment shader\n" " .comp for a compute shader\n" + " .glsl for .vert.glsl, .tesc.glsl, ..., .comp.glsl compound suffixes\n" + " .hlsl for .vert.hlsl, .tesc.hlsl, ..., .comp.hlsl compound suffixes\n" "\n" - "Compilation warnings and errors will be printed to stdout.\n" - "\n" - "To get other information, use one of the following options:\n" - "Each option must be specified separately.\n" - " -V create SPIR-V binary, under Vulkan semantics; turns on -l;\n" - " default file name is .spv (-o overrides this)\n" - " -G create SPIR-V binary, under OpenGL semantics; turns on -l;\n" - " default file name is .spv (-o overrides this)\n" - " -H print human readable form of SPIR-V; turns on -V\n" + "Options:\n" + " -C cascading errors; risk crash from accumulation of error recoveries\n" + " -D input is HLSL (default when any suffix is .hlsl)\n" + " -D\n" + " -D define a pre-processor macro\n" " -E print pre-processed GLSL; cannot be used with -l;\n" " errors will appear on stderr.\n" + " -G[ver] create SPIR-V binary, under OpenGL semantics; turns on -l;\n" + " default file name is .spv (-o overrides this)\n" + " 'ver', when present, is the version of the input semantics,\n" + " which will appear in #define GL_SPIRV ver\n" + " '--client opengl100' is the same as -G100\n" + " a '--target-env' for OpenGL will also imply '-G'\n" + " -H print human readable form of SPIR-V; turns on -V\n" + " -I add dir to the include search path; includer's directory\n" + " is searched first, followed by left-to-right order of -I\n" + " -Od disables optimization. May cause illegal SPIR-V for HLSL.\n" + " -Os optimizes SPIR-V to minimize size.\n" + " -S uses specified stage rather than parsing the file extension\n" + " choices for are vert, tesc, tese, geom, frag, or comp\n" + " -U undefine a pre-processor macro\n" + " -V[ver] create SPIR-V binary, under Vulkan semantics; turns on -l;\n" + " default file name is .spv (-o overrides this)\n" + " 'ver', when present, is the version of the input semantics,\n" + " which will appear in #define VULKAN ver\n" + " '--client vulkan100' is the same as -V100\n" + " a '--target-env' for Vulkan will also imply '-V'\n" " -c configuration dump;\n" " creates the default configuration file (redirect to a .conf file)\n" - " -C cascading errors; risks crashes from accumulation of error recoveries\n" " -d default to desktop (#version 110) when there is no shader #version\n" " (default is ES version 100)\n" - " -D input is HLSL\n" - " -e specify entry-point name\n" + " -e specify as the entry-point name\n" + " -f{hlsl_functionality1}\n" + " 'hlsl_functionality1' enables use of the\n" + " SPV_GOOGLE_hlsl_functionality1 extension\n" + " -g generate debug information\n" " -h print this usage message\n" " -i intermediate tree (glslang AST) is printed out\n" " -l link all input files together to form a single module\n" " -m memory leak mode\n" - " -o save binary to , requires a binary option (e.g., -V)\n" + " -o save binary to , requires a binary option (e.g., -V)\n" " -q dump reflection query database\n" - " -r relaxed semantic error-checking mode\n" - " -s silent mode\n" + " -r synonym for --relaxed-errors\n" + " -s silence syntax and semantic error reporting\n" " -t multi-threaded mode\n" " -v print version strings\n" - " -w suppress warnings (except as required by #extension : warn)\n" - " -x save 32-bit hexadecimal numbers as text, requires a binary option (e.g., -V)\n" + " -w synonym for --suppress-warnings\n" + " -x save binary output as text-based 32-bit hexadecimal numbers\n" + " --auto-map-bindings automatically bind uniform variables\n" + " without explicit bindings.\n" + " --amb synonym for --auto-map-bindings\n" + " --auto-map-locations automatically locate input/output lacking\n" + " 'location' (fragile, not cross stage)\n" + " --aml synonym for --auto-map-locations\n" + " --client {vulkan|opengl} see -V and -G\n" + " -dumpfullversion print bare major.minor.patchlevel\n" + " -dumpversion same as -dumpfullversion\n" + " --flatten-uniform-arrays flatten uniform texture/sampler arrays to\n" + " scalars\n" + " --fua synonym for --flatten-uniform-arrays\n" + " --hlsl-offsets Allow block offsets to follow HLSL rules\n" + " Works independently of source language\n" + " --hlsl-iomap Perform IO mapping in HLSL register space\n" + " --hlsl-enable-16bit-types Allow use of 16-bit types in SPIR-V for HLSL\n" + " --invert-y | --iy invert position.Y output in vertex shader\n" + " --keep-uncalled don't eliminate uncalled functions\n" + " --ku synonym for --keep-uncalled\n" + " --no-storage-format use Unknown image format\n" + " --nsf synonym for --no-storage-format\n" + " --relaxed-errors relaxed GLSL semantic error-checking mode\n" + " --resource-set-binding [stage] name set binding\n" + " Set descriptor set and binding for individual resources\n" + " --resource-set-binding [stage] set\n" + " Set descriptor set for all resources\n" + " --rsb [stage] type set binding synonym for --resource-set-binding\n" + " --shift-image-binding [stage] num base binding number for images (uav)\n" + " --shift-image-binding [stage] [num set]... per-descriptor-set shift values\n" + " --sib [stage] num synonym for --shift-image-binding\n" + " --shift-sampler-binding [stage] num base binding number for samplers\n" + " --shift-sampler-binding [stage] [num set]... per-descriptor-set shift values\n" + " --ssb [stage] num synonym for --shift-sampler-binding\n" + " --shift-ssbo-binding [stage] num base binding number for SSBOs\n" + " --shift-ssbo-binding [stage] [num set]... per-descriptor-set shift values\n" + " --sbb [stage] num synonym for --shift-ssbo-binding\n" + " --shift-texture-binding [stage] num base binding number for textures\n" + " --shift-texture-binding [stage] [num set]... per-descriptor-set shift values\n" + " --stb [stage] num synonym for --shift-texture-binding\n" + " --shift-uav-binding [stage] num base binding number for UAVs\n" + " --shift-uav-binding [stage] [num set]... per-descriptor-set shift values\n" + " --suavb [stage] num synonym for --shift-uav-binding\n" + " --shift-UBO-binding [stage] num base binding number for UBOs\n" + " --shift-UBO-binding [stage] [num set]... per-descriptor-set shift values\n" + " --shift-cbuffer-binding [stage] num synonym for --shift-UBO-binding\n" + " --shift-cbuffer-binding [stage] [num set]... per-descriptor-set shift values\n" + " --sub [stage] num synonym for --shift-UBO-binding\n" + " --source-entrypoint the given shader source function is\n" + " renamed to be the given in -e\n" + " --sep synonym for --source-entrypoint\n" + " --stdin Read from stdin instead of from a file.\n" + " You'll have to provide the shader stage\n" + " using -S.\n" + " --suppress-warnings suppress GLSL warnings\n" + " (except as required by #extension : warn)\n" + " --target-env {vulkan1.0 | vulkan1.1 | opengl} \n" + " set execution environment that emitted code\n" + " will execute in (as opposed to the language\n" + " semantics selected by --client) defaults:\n" + " 'vulkan1.0' under '--client vulkan'\n" + " 'opengl' under '--client opengl'\n" + " --variable-name Creates a C header file that contains a\n" + " uint32_t array named \n" + " initialized with the shader binary code.\n" + " --version synonym for -v\n" + " --vn synonym for --variable-name \n" ); exit(EFailUsage); @@ -832,76 +1462,33 @@ int fopen_s( // // Malloc a string of sufficient size and read a string into it. // -char** ReadFileData(const char* fileName) +char* ReadFileData(const char* fileName) { FILE *in = nullptr; int errorCode = fopen_s(&in, fileName, "r"); - - int count = 0; - const int maxSourceStrings = 5; // for testing splitting shader/tokens across multiple strings - char** return_data = (char**)malloc(sizeof(char *) * (maxSourceStrings+1)); // freed in FreeFileData() - if (errorCode || in == nullptr) Error("unable to open input file"); - + + int count = 0; while (fgetc(in) != EOF) count++; fseek(in, 0, SEEK_SET); - char *fdata = (char*)malloc(count+2); // freed before return of this function - if (! fdata) - Error("can't allocate memory"); - - if ((int)fread(fdata, 1, count, in) != count) { - free(fdata); + char* return_data = (char*)malloc(count + 1); // freed in FreeFileData() + if ((int)fread(return_data, 1, count, in) != count) { + free(return_data); Error("can't read input file"); } - fdata[count] = '\0'; + return_data[count] = '\0'; fclose(in); - if (count == 0) { - // recover from empty file - return_data[0] = (char*)malloc(count+2); // freed in FreeFileData() - return_data[0][0]='\0'; - NumShaderStrings = 0; - free(fdata); - - return return_data; - } else - NumShaderStrings = 1; // Set to larger than 1 for testing multiple strings - - // compute how to split up the file into multiple strings, for testing multiple strings - int len = (int)(ceil)((float)count/(float)NumShaderStrings); - int ptr_len = 0; - int i = 0; - while (count > 0) { - return_data[i] = (char*)malloc(len + 2); // freed in FreeFileData() - memcpy(return_data[i], fdata + ptr_len, len); - return_data[i][len] = '\0'; - count -= len; - ptr_len += len; - if (count < len) { - if (count == 0) { - NumShaderStrings = i + 1; - break; - } - len = count; - } - ++i; - } - - free(fdata); - return return_data; } -void FreeFileData(char** data) +void FreeFileData(char* data) { - for(int i = 0; i < NumShaderStrings; i++) - free(data[i]); - free(data); } diff --git a/Externals/glslang/StandAlone/Worklist.h b/Externals/glslang/StandAlone/Worklist.h index 57dc0db7b2..91b6f516be 100644 --- a/Externals/glslang/StandAlone/Worklist.h +++ b/Externals/glslang/StandAlone/Worklist.h @@ -1,11 +1,11 @@ // -//Copyright (C) 2013 LunarG, Inc. +// Copyright (C) 2013 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,25 +19,26 @@ // 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. +// 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 WORKLIST_H_INCLUDED #define WORKLIST_H_INCLUDED #include "../glslang/OSDependent/osinclude.h" -#include #include +#include +#include namespace glslang { @@ -58,23 +59,18 @@ namespace glslang { void add(TWorkItem* item) { - GetGlobalLock(); - + std::lock_guard guard(mutex); worklist.push_back(item); - - ReleaseGlobalLock(); } - + bool remove(TWorkItem*& item) { - GetGlobalLock(); - + std::lock_guard guard(mutex); + if (worklist.empty()) return false; item = worklist.front(); worklist.pop_front(); - - ReleaseGlobalLock(); return true; } @@ -90,6 +86,7 @@ namespace glslang { } protected: + std::mutex mutex; std::list worklist; }; diff --git a/Externals/glslang/StandAlone/spirv-remap.cpp b/Externals/glslang/StandAlone/spirv-remap.cpp index f35b58eda9..998f7428aa 100644 --- a/Externals/glslang/StandAlone/spirv-remap.cpp +++ b/Externals/glslang/StandAlone/spirv-remap.cpp @@ -1,11 +1,11 @@ // -//Copyright (C) 2015 LunarG, Inc. +// Copyright (C) 2015 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,18 +19,18 @@ // 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. +// 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. // #include @@ -143,8 +143,8 @@ namespace { << " [--map (all|types|names|funcs)]" << " [--dce (all|types|funcs)]" << " [--opt (all|loadstore)]" - << " [--strip-all | --strip all | -s]" - << " [--do-everything]" + << " [--strip-all | --strip all | -s]" + << " [--do-everything]" << " --input | -i file1 [file2...] --output|-o DESTDIR" << std::endl; @@ -311,7 +311,6 @@ namespace { } // namespace - int main(int argc, char** argv) { std::vector inputFile; diff --git a/Externals/glslang/glslang.vcxproj b/Externals/glslang/glslang.vcxproj index a6a6e1f7f1..4c82eb869b 100644 --- a/Externals/glslang/glslang.vcxproj +++ b/Externals/glslang/glslang.vcxproj @@ -38,6 +38,7 @@ + @@ -45,17 +46,17 @@ + + - - @@ -65,12 +66,6 @@ - - - - - - @@ -93,9 +88,12 @@ + + + @@ -110,13 +108,6 @@ - - - - - - - @@ -134,4 +125,4 @@ - \ No newline at end of file + diff --git a/Externals/glslang/glslang.vcxproj.filters b/Externals/glslang/glslang.vcxproj.filters index e39f863a5f..65acdecdcd 100644 --- a/Externals/glslang/glslang.vcxproj.filters +++ b/Externals/glslang/glslang.vcxproj.filters @@ -7,15 +7,9 @@ glslang\GenericCodeGen - - glslang\MachineIndependant\preprocessor - glslang\MachineIndependant\preprocessor - - glslang\MachineIndependant\preprocessor - glslang\MachineIndependant\preprocessor @@ -28,6 +22,9 @@ glslang\MachineIndependant\preprocessor + + glslang\MachineIndependant + glslang\MachineIndependant @@ -112,23 +109,11 @@ OGLCompilersDLL - - hlsl + + glslang\MachineIndependant - - hlsl - - - hlsl - - - hlsl - - - hlsl - - - hlsl + + glslang\MachineIndependant @@ -174,6 +159,9 @@ glslang\MachineIndependant\preprocessor + + glslang\MachineIndependant + glslang\MachineIndependant @@ -249,26 +237,11 @@ OGLCompilersDLL - - hlsl + + glslang\MachineIndependant - - hlsl - - - hlsl - - - hlsl - - - hlsl - - - hlsl - - - hlsl + + glslang\MachineIndependant @@ -299,9 +272,6 @@ {7039de2e-63ef-409d-a895-3c0dd307e201} - - {e465129b-44ff-46e1-b876-76c529f3a945} - {8d950cfc-7fb5-4612-b23c-f4d569404955} @@ -311,4 +281,4 @@ glslang\MachineIndependant - \ No newline at end of file + diff --git a/Externals/glslang/glslang/CMakeLists.txt b/Externals/glslang/glslang/CMakeLists.txt old mode 100644 new mode 100755 index f431cc1125..1efde2edd4 --- a/Externals/glslang/glslang/CMakeLists.txt +++ b/Externals/glslang/glslang/CMakeLists.txt @@ -9,11 +9,14 @@ endif(WIN32) set(SOURCES MachineIndependent/glslang.y MachineIndependent/glslang_tab.cpp + MachineIndependent/attribute.cpp MachineIndependent/Constant.cpp + MachineIndependent/iomapper.cpp MachineIndependent/InfoSink.cpp MachineIndependent/Initialize.cpp MachineIndependent/IntermTraverse.cpp MachineIndependent/Intermediate.cpp + MachineIndependent/ParseContextBase.cpp MachineIndependent/ParseHelper.cpp MachineIndependent/PoolAlloc.cpp MachineIndependent/RemoveTree.cpp @@ -29,9 +32,7 @@ set(SOURCES MachineIndependent/preprocessor/Pp.cpp MachineIndependent/preprocessor/PpAtom.cpp MachineIndependent/preprocessor/PpContext.cpp - MachineIndependent/preprocessor/PpMemory.cpp MachineIndependent/preprocessor/PpScanner.cpp - MachineIndependent/preprocessor/PpSymbols.cpp MachineIndependent/preprocessor/PpTokens.cpp MachineIndependent/propagateNoContraction.cpp GenericCodeGen/CodeGen.cpp @@ -51,9 +52,12 @@ set(HEADERS Include/revision.h Include/ShHandle.h Include/Types.h + MachineIndependent/attribute.h MachineIndependent/glslang_tab.cpp.h MachineIndependent/gl_types.h MachineIndependent/Initialize.h + MachineIndependent/iomapper.h + MachineIndependent/LiveTraverser.h MachineIndependent/localintermediate.h MachineIndependent/ParseHelper.h MachineIndependent/reflection.h @@ -76,8 +80,19 @@ set(HEADERS # WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) # set(BISON_GLSLParser_OUTPUT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/MachineIndependent/glslang_tab.cpp) -add_library(glslang STATIC ${BISON_GLSLParser_OUTPUT_SOURCE} ${SOURCES} ${HEADERS}) +add_library(glslang ${LIB_TYPE} ${BISON_GLSLParser_OUTPUT_SOURCE} ${SOURCES} ${HEADERS}) set_property(TARGET glslang PROPERTY FOLDER glslang) +set_property(TARGET glslang PROPERTY POSITION_INDEPENDENT_CODE ON) +target_link_libraries(glslang OGLCompiler OSDependent) +target_include_directories(glslang PUBLIC ..) + +if(WIN32 AND BUILD_SHARED_LIBS) + set_target_properties(glslang PROPERTIES PREFIX "") +endif() + +if(ENABLE_HLSL) + target_link_libraries(glslang HLSL) +endif() if(WIN32) source_group("Public" REGULAR_EXPRESSION "Public/*") @@ -87,5 +102,20 @@ if(WIN32) source_group("MachineIndependent\\Preprocessor" REGULAR_EXPRESSION "MachineIndependent/preprocessor/*") endif(WIN32) -install(TARGETS glslang - ARCHIVE DESTINATION lib) +if(ENABLE_GLSLANG_INSTALL) + if(BUILD_SHARED_LIBS) + install(TARGETS glslang + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + else() + install(TARGETS glslang + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif() +endif(ENABLE_GLSLANG_INSTALL) + +if(ENABLE_GLSLANG_INSTALL) + foreach(file ${HEADERS}) + get_filename_component(dir ${file} DIRECTORY) + install(FILES ${file} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/glslang/${dir}) + endforeach() +endif(ENABLE_GLSLANG_INSTALL) diff --git a/Externals/glslang/glslang/GenericCodeGen/CodeGen.cpp b/Externals/glslang/glslang/GenericCodeGen/CodeGen.cpp index dc78342ac9..b3c7226dfa 100644 --- a/Externals/glslang/glslang/GenericCodeGen/CodeGen.cpp +++ b/Externals/glslang/glslang/GenericCodeGen/CodeGen.cpp @@ -1,10 +1,10 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -18,18 +18,18 @@ // 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. +// 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. // #include "../Include/Common.h" diff --git a/Externals/glslang/glslang/GenericCodeGen/Link.cpp b/Externals/glslang/glslang/GenericCodeGen/Link.cpp index 8160999206..c38db0f69f 100644 --- a/Externals/glslang/glslang/GenericCodeGen/Link.cpp +++ b/Externals/glslang/glslang/GenericCodeGen/Link.cpp @@ -1,10 +1,10 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -18,18 +18,18 @@ // 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. +// 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. // // @@ -46,7 +46,7 @@ class TGenericLinker : public TLinker { public: TGenericLinker(EShExecutable e, int dOptions) : TLinker(e, infoSink), debugOptions(dOptions) { } bool link(TCompilerList&, TUniformMap*) { return true; } - void getAttributeBindings(ShBindingTable const **) const { } + void getAttributeBindings(ShBindingTable const **) const { } TInfoSink infoSink; int debugOptions; }; diff --git a/Externals/glslang/glslang/Include/BaseTypes.h b/Externals/glslang/glslang/Include/BaseTypes.h index 2c2757724b..46fe159b49 100644 --- a/Externals/glslang/glslang/Include/BaseTypes.h +++ b/Externals/glslang/glslang/Include/BaseTypes.h @@ -1,12 +1,13 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2012-2013 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2012-2013 LunarG, Inc. +// Copyright (C) 2017 ARM Limited. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,18 +21,18 @@ // 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. +// 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 _BASICTYPES_INCLUDED_ @@ -46,6 +47,11 @@ enum TBasicType { EbtVoid, EbtFloat, EbtDouble, + EbtFloat16, + EbtInt8, + EbtUint8, + EbtInt16, + EbtUint16, EbtInt, EbtUint, EbtInt64, @@ -55,6 +61,10 @@ enum TBasicType { EbtSampler, EbtStruct, EbtBlock, + + // HLSL types that live only temporarily. + EbtString, + EbtNumTypes }; @@ -77,7 +87,7 @@ enum TStorageQualifier { EvqUniform, // read only, shared with app EvqBuffer, // read/write, shared with app EvqShared, // compute shader's read/write 'shared' qualifier - + // parameters EvqIn, // also, for 'in' in the grammar before we know if it's a pipeline input or an 'in' parameter EvqOut, // also, for 'out' in the grammar before we know if it's a pipeline output or an 'out' parameter @@ -130,6 +140,8 @@ enum TBuiltInVariable { EbvLocalInvocationId, EbvGlobalInvocationId, EbvLocalInvocationIndex, + EbvNumSubgroups, + EbvSubgroupID, EbvSubGroupSize, EbvSubGroupInvocation, EbvSubGroupEqMask, @@ -137,6 +149,13 @@ enum TBuiltInVariable { EbvSubGroupGtMask, EbvSubGroupLeMask, EbvSubGroupLtMask, + EbvSubgroupSize2, + EbvSubgroupInvocation2, + EbvSubgroupEqMask2, + EbvSubgroupGeMask2, + EbvSubgroupGtMask2, + EbvSubgroupLeMask2, + EbvSubgroupLtMask2, EbvVertexId, EbvInstanceId, EbvVertexIndex, @@ -182,16 +201,54 @@ enum TBuiltInVariable { EbvFragColor, EbvFragData, EbvFragDepth, + EbvFragStencilRef, EbvSampleId, EbvSamplePosition, EbvSampleMask, EbvHelperInvocation, +#ifdef AMD_EXTENSIONS + EbvBaryCoordNoPersp, + EbvBaryCoordNoPerspCentroid, + EbvBaryCoordNoPerspSample, + EbvBaryCoordSmooth, + EbvBaryCoordSmoothCentroid, + EbvBaryCoordSmoothSample, + EbvBaryCoordPullModel, +#endif + + EbvViewIndex, + EbvDeviceIndex, + +#ifdef NV_EXTENSIONS + EbvViewportMaskNV, + EbvSecondaryPositionNV, + EbvSecondaryViewportMaskNV, + EbvPositionPerViewNV, + EbvViewportMaskPerViewNV, + EbvFragFullyCoveredNV, +#endif + + // HLSL built-ins that live only temporarily, until they get remapped + // to one of the above. + EbvFragDepthGreater, + EbvFragDepthLesser, + EbvGsOutputStream, + EbvOutputPatch, + EbvInputPatch, + + // structbuffer types + EbvAppendConsume, // no need to differentiate append and consume + EbvRWStructuredBuffer, + EbvStructuredBuffer, + EbvByteAddressBuffer, + EbvRWByteAddressBuffer, + EbvLast }; // These will show up in error messages -__inline const char* GetStorageQualifierString(TStorageQualifier q) +__inline const char* GetStorageQualifierString(TStorageQualifier q) { switch (q) { case EvqTemporary: return "temp"; break; @@ -282,10 +339,33 @@ __inline const char* GetBuiltInVariableString(TBuiltInVariable v) case EbvFragColor: return "FragColor"; case EbvFragData: return "FragData"; case EbvFragDepth: return "FragDepth"; + case EbvFragStencilRef: return "FragStencilRef"; case EbvSampleId: return "SampleId"; case EbvSamplePosition: return "SamplePosition"; case EbvSampleMask: return "SampleMaskIn"; case EbvHelperInvocation: return "HelperInvocation"; + +#ifdef AMD_EXTENSIONS + case EbvBaryCoordNoPersp: return "BaryCoordNoPersp"; + case EbvBaryCoordNoPerspCentroid: return "BaryCoordNoPerspCentroid"; + case EbvBaryCoordNoPerspSample: return "BaryCoordNoPerspSample"; + case EbvBaryCoordSmooth: return "BaryCoordSmooth"; + case EbvBaryCoordSmoothCentroid: return "BaryCoordSmoothCentroid"; + case EbvBaryCoordSmoothSample: return "BaryCoordSmoothSample"; + case EbvBaryCoordPullModel: return "BaryCoordPullModel"; +#endif + + case EbvViewIndex: return "ViewIndex"; + case EbvDeviceIndex: return "DeviceIndex"; + +#ifdef NV_EXTENSIONS + case EbvViewportMaskNV: return "ViewportMaskNV"; + case EbvSecondaryPositionNV: return "SecondaryPositionNV"; + case EbvSecondaryViewportMaskNV: return "SecondaryViewportMaskNV"; + case EbvPositionPerViewNV: return "PositionPerViewNV"; + case EbvViewportMaskPerViewNV: return "ViewportMaskPerViewNV"; + case EbvFragFullyCoveredNV: return "FragFullyCoveredNV"; +#endif default: return "unknown built-in variable"; } } @@ -301,7 +381,7 @@ enum TPrecisionQualifier { __inline const char* GetPrecisionQualifierString(TPrecisionQualifier p) { - switch(p) { + switch (p) { case EpqNone: return ""; break; case EpqLow: return "lowp"; break; case EpqMedium: return "mediump"; break; @@ -310,6 +390,75 @@ __inline const char* GetPrecisionQualifierString(TPrecisionQualifier p) } } +__inline bool isTypeSignedInt(TBasicType type) +{ + switch (type) { + case EbtInt8: + case EbtInt16: + case EbtInt: + case EbtInt64: + return true; + default: + return false; + } +} + +__inline bool isTypeUnsignedInt(TBasicType type) +{ + switch (type) { + case EbtUint8: + case EbtUint16: + case EbtUint: + case EbtUint64: + return true; + default: + return false; + } +} + +__inline bool isTypeInt(TBasicType type) +{ + return isTypeSignedInt(type) || isTypeUnsignedInt(type); +} + +__inline bool isTypeFloat(TBasicType type) +{ + switch (type) { + case EbtFloat: + case EbtDouble: + case EbtFloat16: + return true; + default: + return false; + } +} + +__inline int getTypeRank(TBasicType type) { + int res = -1; + switch(type) { + case EbtInt8: + case EbtUint8: + res = 0; + break; + case EbtInt16: + case EbtUint16: + res = 1; + break; + case EbtInt: + case EbtUint: + res = 2; + break; + case EbtInt64: + case EbtUint64: + res = 3; + break; + default: + assert(false); + break; + } + return res; +} + } // end namespace glslang #endif // _BASICTYPES_INCLUDED_ diff --git a/Externals/glslang/glslang/Include/Common.h b/Externals/glslang/glslang/Include/Common.h index efb78d44f8..35eaa31048 100644 --- a/Externals/glslang/glslang/Include/Common.h +++ b/Externals/glslang/glslang/Include/Common.h @@ -1,12 +1,12 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2012-2013 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2012-2013 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,36 +20,23 @@ // 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. +// 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 _COMMON_INCLUDED_ #define _COMMON_INCLUDED_ -#if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/) || defined MINGW_HAS_SECURE_API - #include - #define snprintf sprintf_s - #define safe_vsprintf(buf,max,format,args) vsnprintf_s((buf), (max), (max), (format), (args)) -#elif defined (solaris) - #define safe_vsprintf(buf,max,format,args) vsnprintf((buf), (max), (format), (args)) - #include - #define UINT_PTR uintptr_t -#else - #define safe_vsprintf(buf,max,format,args) vsnprintf((buf), (max), (format), (args)) - #include - #define UINT_PTR uintptr_t -#endif #if defined(__ANDROID__) || _MSC_VER < 1700 #include @@ -63,15 +50,40 @@ std::string to_string(const T& val) { } #endif -#if defined(_MSC_VER) && _MSC_VER < 1700 -inline long long int strtoll (const char* str, char** endptr, int base) -{ - return _strtoi64(str, endptr, base); -} -inline long long int atoll (const char* str) -{ - return strtoll(str, NULL, 10); -} +#if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/) || defined MINGW_HAS_SECURE_API + #include + #ifndef snprintf + #define snprintf sprintf_s + #endif + #define safe_vsprintf(buf,max,format,args) vsnprintf_s((buf), (max), (max), (format), (args)) +#elif defined (solaris) + #define safe_vsprintf(buf,max,format,args) vsnprintf((buf), (max), (format), (args)) + #include + #define UINT_PTR uintptr_t +#else + #define safe_vsprintf(buf,max,format,args) vsnprintf((buf), (max), (format), (args)) + #include + #define UINT_PTR uintptr_t +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1800 + #include + inline long long int strtoll (const char* str, char** endptr, int base) + { + return _strtoi64(str, endptr, base); + } + inline unsigned long long int strtoull (const char* str, char** endptr, int base) + { + return _strtoui64(str, endptr, base); + } + inline long long int atoll (const char* str) + { + return strtoll(str, NULL, 10); + } +#endif + +#if defined(_MSC_VER) +#define strdup _strdup #endif /* windows only pragma */ @@ -89,8 +101,8 @@ inline long long int atoll (const char* str) #include #include #include -#include -#include +#include +#include #include "PoolAlloc.h" @@ -99,11 +111,11 @@ inline long long int atoll (const char* str) // #define POOL_ALLOCATOR_NEW_DELETE(A) \ void* operator new(size_t s) { return (A).allocate(s); } \ - void* operator new(size_t, void *_Where) { return (_Where); } \ + void* operator new(size_t, void *_Where) { return (_Where); } \ void operator delete(void*) { } \ void operator delete(void *, void *) { } \ void* operator new[](size_t s) { return (A).allocate(s); } \ - void* operator new[](size_t, void *_Where) { return (_Where); } \ + void* operator new[](size_t, void *_Where) { return (_Where); } \ void operator delete[](void*) { } \ void operator delete[](void *, void *) { } @@ -147,7 +159,7 @@ inline TString* NewPoolTString(const char* s) return new(memory) TString(s); } -template inline T* NewPoolObject(T) +template inline T* NewPoolObject(T*) { return new(GetThreadPoolAllocator().allocate(sizeof(T))) T; } @@ -174,7 +186,7 @@ public: template class TList : public std::list > { }; -template > +template > class TMap : public std::map > > { }; @@ -197,22 +209,28 @@ template T Max(const T a, const T b) { return a > b ? a : b; } // // Create a TString object from an integer. // +#if defined _MSC_VER || defined MINGW_HAS_SECURE_API inline const TString String(const int i, const int base = 10) { char text[16]; // 32 bit ints are at most 10 digits in base 10 - - #if defined _MSC_VER || defined MINGW_HAS_SECURE_API - _itoa_s(i, text, sizeof(text), base); - #else - // we assume base 10 for all cases - snprintf(text, sizeof(text), "%d", i); - #endif + _itoa_s(i, text, sizeof(text), base); + return text; +} +#else +inline const TString String(const int i, const int /*base*/ = 10) +{ + char text[16]; // 32 bit ints are at most 10 digits in base 10 + + // we assume base 10 for all cases + snprintf(text, sizeof(text), "%d", i); return text; } +#endif struct TSourceLoc { void init() { name = nullptr; string = 0; line = 0; column = 0; } + void init(int stringNum) { init(); string = stringNum; } // Returns the name if it exists. Otherwise, returns the string number. std::string getStringNameOrNum(bool quoteStringName = true) const { @@ -226,7 +244,10 @@ struct TSourceLoc { int column; }; -typedef TMap TPragmaTable; +class TPragmaTable : public TMap { +public: + POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) +}; const int MaxTokenLength = 1024; diff --git a/Externals/glslang/glslang/Include/ConstantUnion.h b/Externals/glslang/glslang/Include/ConstantUnion.h index 8ee2c84ccf..3e93340151 100644 --- a/Externals/glslang/glslang/Include/ConstantUnion.h +++ b/Externals/glslang/glslang/Include/ConstantUnion.h @@ -1,12 +1,13 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2013 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2013 LunarG, Inc. +// Copyright (C) 2017 ARM Limited. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,23 +21,26 @@ // 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. +// 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 _CONSTANT_UNION_INCLUDED_ #define _CONSTANT_UNION_INCLUDED_ +#include "../Include/Common.h" +#include "../Include/BaseTypes.h" + namespace glslang { class TConstUnion { @@ -45,15 +49,39 @@ public: TConstUnion() : iConst(0), type(EbtInt) { } + void setI8Const(signed char i) + { + i8Const = i; + type = EbtInt8; + } + + void setU8Const(unsigned char u) + { + u8Const = u; + type = EbtUint8; + } + + void setI16Const(signed short i) + { + i16Const = i; + type = EbtInt16; + } + + void setU16Const(unsigned short u) + { + u16Const = u; + type = EbtUint16; + } + void setIConst(int i) - { - iConst = i; + { + iConst = i; type = EbtInt; } void setUConst(unsigned int u) { - uConst = u; + uConst = u; type = EbtUint; } @@ -71,22 +99,65 @@ public: void setDConst(double d) { - dConst = d; + dConst = d; type = EbtDouble; } void setBConst(bool b) { - bConst = b; + bConst = b; type = EbtBool; } + void setSConst(const TString* s) + { + sConst = s; + type = EbtString; + } + + signed char getI8Const() const { return i8Const; } + unsigned char getU8Const() const { return u8Const; } + signed short getI16Const() const { return i16Const; } + unsigned short getU16Const() const { return u16Const; } int getIConst() const { return iConst; } unsigned int getUConst() const { return uConst; } long long getI64Const() const { return i64Const; } unsigned long long getU64Const() const { return u64Const; } double getDConst() const { return dConst; } bool getBConst() const { return bConst; } + const TString* getSConst() const { return sConst; } + + bool operator==(const signed char i) const + { + if (i == i8Const) + return true; + + return false; + } + + bool operator==(const unsigned char u) const + { + if (u == u8Const) + return true; + + return false; + } + + bool operator==(const signed short i) const + { + if (i == i16Const) + return true; + + return false; + } + + bool operator==(const unsigned short u) const + { + if (u == u16Const) + return true; + + return false; + } bool operator==(const int i) const { @@ -142,6 +213,26 @@ public: return false; switch (type) { + case EbtInt16: + if (constant.i16Const == i16Const) + return true; + + break; + case EbtUint16: + if (constant.u16Const == u16Const) + return true; + + break; + case EbtInt8: + if (constant.i8Const == i8Const) + return true; + + break; + case EbtUint8: + if (constant.u8Const == u8Const) + return true; + + break; case EbtInt: if (constant.iConst == iConst) return true; @@ -179,6 +270,26 @@ public: return false; } + bool operator!=(const signed char i) const + { + return !operator==(i); + } + + bool operator!=(const unsigned char u) const + { + return !operator==(u); + } + + bool operator!=(const signed short i) const + { + return !operator==(i); + } + + bool operator!=(const unsigned short u) const + { + return !operator==(u); + } + bool operator!=(const int i) const { return !operator==(i); @@ -215,9 +326,29 @@ public: } bool operator>(const TConstUnion& constant) const - { + { assert(type == constant.type); switch (type) { + case EbtInt8: + if (i8Const > constant.i8Const) + return true; + + return false; + case EbtUint8: + if (u8Const > constant.u8Const) + return true; + + return false; + case EbtInt16: + if (i16Const > constant.i16Const) + return true; + + return false; + case EbtUint16: + if (u16Const > constant.u16Const) + return true; + + return false; case EbtInt: if (iConst > constant.iConst) return true; @@ -250,9 +381,29 @@ public: } bool operator<(const TConstUnion& constant) const - { + { assert(type == constant.type); switch (type) { + case EbtInt8: + if (i8Const < constant.i8Const) + return true; + + return false; + case EbtUint8: + if (u8Const < constant.u8Const) + return true; + + return false; + case EbtInt16: + if (i16Const < constant.i16Const) + return true; + + return false; + case EbtUint16: + if (u16Const < constant.u16Const) + return true; + + return false; case EbtInt: if (iConst < constant.iConst) return true; @@ -285,13 +436,17 @@ public: } TConstUnion operator+(const TConstUnion& constant) const - { + { TConstUnion returnValue; assert(type == constant.type); switch (type) { - case EbtInt: returnValue.setIConst(iConst + constant.iConst); break; - case EbtInt64: returnValue.setI64Const(i64Const + constant.i64Const); break; - case EbtUint: returnValue.setUConst(uConst + constant.uConst); break; + case EbtInt8: returnValue.setI8Const(i8Const + constant.i8Const); break; + case EbtInt16: returnValue.setI16Const(i16Const + constant.i16Const); break; + case EbtInt: returnValue.setIConst(iConst + constant.iConst); break; + case EbtInt64: returnValue.setI64Const(i64Const + constant.i64Const); break; + case EbtUint8: returnValue.setU8Const(u8Const + constant.u8Const); break; + case EbtUint16: returnValue.setU16Const(u16Const + constant.u16Const); break; + case EbtUint: returnValue.setUConst(uConst + constant.uConst); break; case EbtUint64: returnValue.setU64Const(u64Const + constant.u64Const); break; case EbtDouble: returnValue.setDConst(dConst + constant.dConst); break; default: assert(false && "Default missing"); @@ -301,13 +456,17 @@ public: } TConstUnion operator-(const TConstUnion& constant) const - { + { TConstUnion returnValue; assert(type == constant.type); switch (type) { - case EbtInt: returnValue.setIConst(iConst - constant.iConst); break; - case EbtInt64: returnValue.setI64Const(i64Const - constant.i64Const); break; - case EbtUint: returnValue.setUConst(uConst - constant.uConst); break; + case EbtInt8: returnValue.setI8Const(i8Const - constant.i8Const); break; + case EbtInt16: returnValue.setI16Const(i16Const - constant.i16Const); break; + case EbtInt: returnValue.setIConst(iConst - constant.iConst); break; + case EbtInt64: returnValue.setI64Const(i64Const - constant.i64Const); break; + case EbtUint8: returnValue.setU8Const(u8Const - constant.u8Const); break; + case EbtUint16: returnValue.setU16Const(u16Const - constant.u16Const); break; + case EbtUint: returnValue.setUConst(uConst - constant.uConst); break; case EbtUint64: returnValue.setU64Const(u64Const - constant.u64Const); break; case EbtDouble: returnValue.setDConst(dConst - constant.dConst); break; default: assert(false && "Default missing"); @@ -317,15 +476,19 @@ public: } TConstUnion operator*(const TConstUnion& constant) const - { + { TConstUnion returnValue; assert(type == constant.type); switch (type) { - case EbtInt: returnValue.setIConst(iConst * constant.iConst); break; - case EbtInt64: returnValue.setI64Const(i64Const * constant.i64Const); break; - case EbtUint: returnValue.setUConst(uConst * constant.uConst); break; + case EbtInt8: returnValue.setI8Const(i8Const * constant.i8Const); break; + case EbtInt16: returnValue.setI16Const(i16Const * constant.i16Const); break; + case EbtInt: returnValue.setIConst(iConst * constant.iConst); break; + case EbtInt64: returnValue.setI64Const(i64Const * constant.i64Const); break; + case EbtUint8: returnValue.setU8Const(u8Const * constant.u8Const); break; + case EbtUint16: returnValue.setU16Const(u16Const * constant.u16Const); break; + case EbtUint: returnValue.setUConst(uConst * constant.uConst); break; case EbtUint64: returnValue.setU64Const(u64Const * constant.u64Const); break; - case EbtDouble: returnValue.setDConst(dConst * constant.dConst); break; + case EbtDouble: returnValue.setDConst(dConst * constant.dConst); break; default: assert(false && "Default missing"); } @@ -333,13 +496,17 @@ public: } TConstUnion operator%(const TConstUnion& constant) const - { + { TConstUnion returnValue; assert(type == constant.type); switch (type) { - case EbtInt: returnValue.setIConst(iConst % constant.iConst); break; - case EbtInt64: returnValue.setI64Const(i64Const % constant.i64Const); break; - case EbtUint: returnValue.setUConst(uConst % constant.uConst); break; + case EbtInt8: returnValue.setI8Const(i8Const % constant.i8Const); break; + case EbtInt16: returnValue.setI8Const(i8Const % constant.i16Const); break; + case EbtInt: returnValue.setIConst(iConst % constant.iConst); break; + case EbtInt64: returnValue.setI64Const(i64Const % constant.i64Const); break; + case EbtUint8: returnValue.setU8Const(u8Const % constant.u8Const); break; + case EbtUint16: returnValue.setU16Const(u16Const % constant.u16Const); break; + case EbtUint: returnValue.setUConst(uConst % constant.uConst); break; case EbtUint64: returnValue.setU64Const(u64Const % constant.u64Const); break; default: assert(false && "Default missing"); } @@ -348,11 +515,67 @@ public: } TConstUnion operator>>(const TConstUnion& constant) const - { + { TConstUnion returnValue; switch (type) { + case EbtInt8: + switch (constant.type) { + case EbtInt8: returnValue.setI8Const(i8Const >> constant.i8Const); break; + case EbtUint8: returnValue.setI8Const(i8Const >> constant.u8Const); break; + case EbtInt16: returnValue.setI8Const(i8Const >> constant.i16Const); break; + case EbtUint16: returnValue.setI8Const(i8Const >> constant.u16Const); break; + case EbtInt: returnValue.setI8Const(i8Const >> constant.iConst); break; + case EbtUint: returnValue.setI8Const(i8Const >> constant.uConst); break; + case EbtInt64: returnValue.setI8Const(i8Const >> constant.i64Const); break; + case EbtUint64: returnValue.setI8Const(i8Const >> constant.u64Const); break; + default: assert(false && "Default missing"); + } + break; + case EbtUint8: + switch (constant.type) { + case EbtInt8: returnValue.setU8Const(u8Const >> constant.i8Const); break; + case EbtUint8: returnValue.setU8Const(u8Const >> constant.u8Const); break; + case EbtInt16: returnValue.setU8Const(u8Const >> constant.i16Const); break; + case EbtUint16: returnValue.setU8Const(u8Const >> constant.u16Const); break; + case EbtInt: returnValue.setU8Const(u8Const >> constant.iConst); break; + case EbtUint: returnValue.setU8Const(u8Const >> constant.uConst); break; + case EbtInt64: returnValue.setU8Const(u8Const >> constant.i64Const); break; + case EbtUint64: returnValue.setU8Const(u8Const >> constant.u64Const); break; + default: assert(false && "Default missing"); + } + break; + case EbtInt16: + switch (constant.type) { + case EbtInt8: returnValue.setI16Const(i16Const >> constant.i8Const); break; + case EbtUint8: returnValue.setI16Const(i16Const >> constant.u8Const); break; + case EbtInt16: returnValue.setI16Const(i16Const >> constant.i16Const); break; + case EbtUint16: returnValue.setI16Const(i16Const >> constant.u16Const); break; + case EbtInt: returnValue.setI16Const(i16Const >> constant.iConst); break; + case EbtUint: returnValue.setI16Const(i16Const >> constant.uConst); break; + case EbtInt64: returnValue.setI16Const(i16Const >> constant.i64Const); break; + case EbtUint64: returnValue.setI16Const(i16Const >> constant.u64Const); break; + default: assert(false && "Default missing"); + } + break; + case EbtUint16: + switch (constant.type) { + case EbtInt8: returnValue.setU16Const(u16Const >> constant.i8Const); break; + case EbtUint8: returnValue.setU16Const(u16Const >> constant.u8Const); break; + case EbtInt16: returnValue.setU16Const(u16Const >> constant.i16Const); break; + case EbtUint16: returnValue.setU16Const(u16Const >> constant.u16Const); break; + case EbtInt: returnValue.setU16Const(u16Const >> constant.iConst); break; + case EbtUint: returnValue.setU16Const(u16Const >> constant.uConst); break; + case EbtInt64: returnValue.setU16Const(u16Const >> constant.i64Const); break; + case EbtUint64: returnValue.setU16Const(u16Const >> constant.u64Const); break; + default: assert(false && "Default missing"); + } + break; case EbtInt: switch (constant.type) { + case EbtInt8: returnValue.setIConst(iConst >> constant.i8Const); break; + case EbtUint8: returnValue.setIConst(iConst >> constant.u8Const); break; + case EbtInt16: returnValue.setIConst(iConst >> constant.i16Const); break; + case EbtUint16: returnValue.setIConst(iConst >> constant.u16Const); break; case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break; case EbtUint: returnValue.setIConst(iConst >> constant.uConst); break; case EbtInt64: returnValue.setIConst(iConst >> constant.i64Const); break; @@ -362,6 +585,10 @@ public: break; case EbtUint: switch (constant.type) { + case EbtInt8: returnValue.setUConst(uConst >> constant.i8Const); break; + case EbtUint8: returnValue.setUConst(uConst >> constant.u8Const); break; + case EbtInt16: returnValue.setUConst(uConst >> constant.i16Const); break; + case EbtUint16: returnValue.setUConst(uConst >> constant.u16Const); break; case EbtInt: returnValue.setUConst(uConst >> constant.iConst); break; case EbtUint: returnValue.setUConst(uConst >> constant.uConst); break; case EbtInt64: returnValue.setUConst(uConst >> constant.i64Const); break; @@ -371,6 +598,10 @@ public: break; case EbtInt64: switch (constant.type) { + case EbtInt8: returnValue.setI64Const(i64Const >> constant.i8Const); break; + case EbtUint8: returnValue.setI64Const(i64Const >> constant.u8Const); break; + case EbtInt16: returnValue.setI64Const(i64Const >> constant.i16Const); break; + case EbtUint16: returnValue.setI64Const(i64Const >> constant.u16Const); break; case EbtInt: returnValue.setI64Const(i64Const >> constant.iConst); break; case EbtUint: returnValue.setI64Const(i64Const >> constant.uConst); break; case EbtInt64: returnValue.setI64Const(i64Const >> constant.i64Const); break; @@ -380,6 +611,10 @@ public: break; case EbtUint64: switch (constant.type) { + case EbtInt8: returnValue.setU64Const(u64Const >> constant.i8Const); break; + case EbtUint8: returnValue.setU64Const(u64Const >> constant.u8Const); break; + case EbtInt16: returnValue.setU64Const(u64Const >> constant.i16Const); break; + case EbtUint16: returnValue.setU64Const(u64Const >> constant.u16Const); break; case EbtInt: returnValue.setU64Const(u64Const >> constant.iConst); break; case EbtUint: returnValue.setU64Const(u64Const >> constant.uConst); break; case EbtInt64: returnValue.setU64Const(u64Const >> constant.i64Const); break; @@ -394,11 +629,67 @@ public: } TConstUnion operator<<(const TConstUnion& constant) const - { + { TConstUnion returnValue; switch (type) { + case EbtInt8: + switch (constant.type) { + case EbtInt8: returnValue.setI8Const(i8Const << constant.i8Const); break; + case EbtUint8: returnValue.setI8Const(i8Const << constant.u8Const); break; + case EbtInt16: returnValue.setI8Const(i8Const << constant.i16Const); break; + case EbtUint16: returnValue.setI8Const(i8Const << constant.u16Const); break; + case EbtInt: returnValue.setI8Const(i8Const << constant.iConst); break; + case EbtUint: returnValue.setI8Const(i8Const << constant.uConst); break; + case EbtInt64: returnValue.setI8Const(i8Const << constant.i64Const); break; + case EbtUint64: returnValue.setI8Const(i8Const << constant.u64Const); break; + default: assert(false && "Default missing"); + } + break; + case EbtUint8: + switch (constant.type) { + case EbtInt8: returnValue.setU8Const(u8Const << constant.i8Const); break; + case EbtUint8: returnValue.setU8Const(u8Const << constant.u8Const); break; + case EbtInt16: returnValue.setU8Const(u8Const << constant.i16Const); break; + case EbtUint16: returnValue.setU8Const(u8Const << constant.u16Const); break; + case EbtInt: returnValue.setU8Const(u8Const << constant.iConst); break; + case EbtUint: returnValue.setU8Const(u8Const << constant.uConst); break; + case EbtInt64: returnValue.setU8Const(u8Const << constant.i64Const); break; + case EbtUint64: returnValue.setU8Const(u8Const << constant.u64Const); break; + default: assert(false && "Default missing"); + } + break; + case EbtInt16: + switch (constant.type) { + case EbtInt8: returnValue.setI16Const(i16Const << constant.i8Const); break; + case EbtUint8: returnValue.setI16Const(i16Const << constant.u8Const); break; + case EbtInt16: returnValue.setI16Const(i16Const << constant.i16Const); break; + case EbtUint16: returnValue.setI16Const(i16Const << constant.u16Const); break; + case EbtInt: returnValue.setI16Const(i16Const << constant.iConst); break; + case EbtUint: returnValue.setI16Const(i16Const << constant.uConst); break; + case EbtInt64: returnValue.setI16Const(i16Const << constant.i64Const); break; + case EbtUint64: returnValue.setI16Const(i16Const << constant.u64Const); break; + default: assert(false && "Default missing"); + } + break; + case EbtUint16: + switch (constant.type) { + case EbtInt8: returnValue.setU16Const(u16Const << constant.i8Const); break; + case EbtUint8: returnValue.setU16Const(u16Const << constant.u8Const); break; + case EbtInt16: returnValue.setU16Const(u16Const << constant.i16Const); break; + case EbtUint16: returnValue.setU16Const(u16Const << constant.u16Const); break; + case EbtInt: returnValue.setU16Const(u16Const << constant.iConst); break; + case EbtUint: returnValue.setU16Const(u16Const << constant.uConst); break; + case EbtInt64: returnValue.setU16Const(u16Const << constant.i64Const); break; + case EbtUint64: returnValue.setU16Const(u16Const << constant.u64Const); break; + default: assert(false && "Default missing"); + } + break; case EbtInt: switch (constant.type) { + case EbtInt8: returnValue.setIConst(iConst << constant.i8Const); break; + case EbtUint8: returnValue.setIConst(iConst << constant.u8Const); break; + case EbtInt16: returnValue.setIConst(iConst << constant.i16Const); break; + case EbtUint16: returnValue.setIConst(iConst << constant.u16Const); break; case EbtInt: returnValue.setIConst(iConst << constant.iConst); break; case EbtUint: returnValue.setIConst(iConst << constant.uConst); break; case EbtInt64: returnValue.setIConst(iConst << constant.i64Const); break; @@ -408,6 +699,10 @@ public: break; case EbtUint: switch (constant.type) { + case EbtInt8: returnValue.setUConst(uConst << constant.i8Const); break; + case EbtUint8: returnValue.setUConst(uConst << constant.u8Const); break; + case EbtInt16: returnValue.setUConst(uConst << constant.i16Const); break; + case EbtUint16: returnValue.setUConst(uConst << constant.u16Const); break; case EbtInt: returnValue.setUConst(uConst << constant.iConst); break; case EbtUint: returnValue.setUConst(uConst << constant.uConst); break; case EbtInt64: returnValue.setUConst(uConst << constant.i64Const); break; @@ -415,8 +710,12 @@ public: default: assert(false && "Default missing"); } break; - case EbtInt64: + case EbtInt64: switch (constant.type) { + case EbtInt8: returnValue.setI64Const(i64Const << constant.i8Const); break; + case EbtUint8: returnValue.setI64Const(i64Const << constant.u8Const); break; + case EbtInt16: returnValue.setI64Const(i64Const << constant.i16Const); break; + case EbtUint16: returnValue.setI64Const(i64Const << constant.u16Const); break; case EbtInt: returnValue.setI64Const(i64Const << constant.iConst); break; case EbtUint: returnValue.setI64Const(i64Const << constant.uConst); break; case EbtInt64: returnValue.setI64Const(i64Const << constant.i64Const); break; @@ -426,6 +725,10 @@ public: break; case EbtUint64: switch (constant.type) { + case EbtInt8: returnValue.setU64Const(u64Const << constant.i8Const); break; + case EbtUint8: returnValue.setU64Const(u64Const << constant.u8Const); break; + case EbtInt16: returnValue.setU64Const(u64Const << constant.i16Const); break; + case EbtUint16: returnValue.setU64Const(u64Const << constant.u16Const); break; case EbtInt: returnValue.setU64Const(u64Const << constant.iConst); break; case EbtUint: returnValue.setU64Const(u64Const << constant.uConst); break; case EbtInt64: returnValue.setU64Const(u64Const << constant.i64Const); break; @@ -440,12 +743,16 @@ public: } TConstUnion operator&(const TConstUnion& constant) const - { + { TConstUnion returnValue; assert(type == constant.type); switch (type) { - case EbtInt: returnValue.setIConst(iConst & constant.iConst); break; - case EbtUint: returnValue.setUConst(uConst & constant.uConst); break; + case EbtInt8: returnValue.setI8Const(i8Const & constant.i8Const); break; + case EbtUint8: returnValue.setU8Const(u8Const & constant.u8Const); break; + case EbtInt16: returnValue.setI16Const(i16Const & constant.i16Const); break; + case EbtUint16: returnValue.setU16Const(u16Const & constant.u16Const); break; + case EbtInt: returnValue.setIConst(iConst & constant.iConst); break; + case EbtUint: returnValue.setUConst(uConst & constant.uConst); break; case EbtInt64: returnValue.setI64Const(i64Const & constant.i64Const); break; case EbtUint64: returnValue.setU64Const(u64Const & constant.u64Const); break; default: assert(false && "Default missing"); @@ -455,12 +762,16 @@ public: } TConstUnion operator|(const TConstUnion& constant) const - { + { TConstUnion returnValue; assert(type == constant.type); switch (type) { - case EbtInt: returnValue.setIConst(iConst | constant.iConst); break; - case EbtUint: returnValue.setUConst(uConst | constant.uConst); break; + case EbtInt8: returnValue.setI8Const(i8Const | constant.i8Const); break; + case EbtUint8: returnValue.setU8Const(u8Const | constant.u8Const); break; + case EbtInt16: returnValue.setI16Const(i16Const | constant.i16Const); break; + case EbtUint16: returnValue.setU16Const(u16Const | constant.u16Const); break; + case EbtInt: returnValue.setIConst(iConst | constant.iConst); break; + case EbtUint: returnValue.setUConst(uConst | constant.uConst); break; case EbtInt64: returnValue.setI64Const(i64Const | constant.i64Const); break; case EbtUint64: returnValue.setU64Const(u64Const | constant.u64Const); break; default: assert(false && "Default missing"); @@ -470,12 +781,16 @@ public: } TConstUnion operator^(const TConstUnion& constant) const - { + { TConstUnion returnValue; assert(type == constant.type); switch (type) { - case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break; - case EbtUint: returnValue.setUConst(uConst ^ constant.uConst); break; + case EbtInt8: returnValue.setI8Const(i8Const ^ constant.i8Const); break; + case EbtUint8: returnValue.setU8Const(u8Const ^ constant.u8Const); break; + case EbtInt16: returnValue.setI16Const(i16Const ^ constant.i16Const); break; + case EbtUint16: returnValue.setU16Const(u16Const ^ constant.u16Const); break; + case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break; + case EbtUint: returnValue.setUConst(uConst ^ constant.uConst); break; case EbtInt64: returnValue.setI64Const(i64Const ^ constant.i64Const); break; case EbtUint64: returnValue.setU64Const(u64Const ^ constant.u64Const); break; default: assert(false && "Default missing"); @@ -485,11 +800,15 @@ public: } TConstUnion operator~() const - { + { TConstUnion returnValue; switch (type) { - case EbtInt: returnValue.setIConst(~iConst); break; - case EbtUint: returnValue.setUConst(~uConst); break; + case EbtInt8: returnValue.setI8Const(~i8Const); break; + case EbtUint8: returnValue.setU8Const(~u8Const); break; + case EbtInt16: returnValue.setI16Const(~i16Const); break; + case EbtUint16: returnValue.setU16Const(~u16Const); break; + case EbtInt: returnValue.setIConst(~iConst); break; + case EbtUint: returnValue.setUConst(~uConst); break; case EbtInt64: returnValue.setI64Const(~i64Const); break; case EbtUint64: returnValue.setU64Const(~u64Const); break; default: assert(false && "Default missing"); @@ -499,7 +818,7 @@ public: } TConstUnion operator&&(const TConstUnion& constant) const - { + { TConstUnion returnValue; assert(type == constant.type); switch (type) { @@ -511,7 +830,7 @@ public: } TConstUnion operator||(const TConstUnion& constant) const - { + { TConstUnion returnValue; assert(type == constant.type); switch (type) { @@ -526,25 +845,30 @@ public: private: union { + signed char i8Const; // used for i8vec, scalar int8s + unsigned char u8Const; // used for u8vec, scalar uint8s + signed short i16Const; // used for i16vec, scalar int16s + unsigned short u16Const; // used for u16vec, scalar uint16s int iConst; // used for ivec, scalar ints unsigned int uConst; // used for uvec, scalar uints long long i64Const; // used for i64vec, scalar int64s unsigned long long u64Const; // used for u64vec, scalar uint64s bool bConst; // used for bvec, scalar bools double dConst; // used for vec, dvec, mat, dmat, scalar floats and doubles + const TString* sConst; // string constant }; TBasicType type; }; // Encapsulate having a pointer to an array of TConstUnion, -// which only needs to be allocated if it's size is going to be +// which only needs to be allocated if its size is going to be // bigger than 0. // // One convenience is being able to use [] to go inside the array, instead // of C++ assuming it as an array of pointers to vectors. // -// General usage is that the size is known up front, and it is +// General usage is that the size is known up front, and it is // created once with the proper size. // class TConstUnionArray { @@ -587,9 +911,6 @@ public: if (! unionArray || ! rhs.unionArray) return false; - if (! unionArray || ! rhs.unionArray) - return false; - return *unionArray == *rhs.unionArray; } bool operator!=(const TConstUnionArray& rhs) const { return ! operator==(rhs); } diff --git a/Externals/glslang/glslang/Include/InfoSink.h b/Externals/glslang/glslang/Include/InfoSink.h index 5862e5d8a5..dceb603cff 100644 --- a/Externals/glslang/glslang/Include/InfoSink.h +++ b/Externals/glslang/glslang/Include/InfoSink.h @@ -1,10 +1,10 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -18,25 +18,25 @@ // 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. +// 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 _INFOSINK_INCLUDED_ #define _INFOSINK_INCLUDED_ #include "../Include/Common.h" -#include +#include namespace glslang { @@ -74,10 +74,9 @@ public: TInfoSinkBase& operator<<(const char* s) { append(s); return *this; } TInfoSinkBase& operator<<(int n) { append(String(n)); return *this; } TInfoSinkBase& operator<<(unsigned int n) { append(String(n)); return *this; } - TInfoSinkBase& operator<<(long unsigned int n) { append(String(n)); return *this; } - TInfoSinkBase& operator<<(float n) { const int size = 40; char buf[size]; + TInfoSinkBase& operator<<(float n) { const int size = 40; char buf[size]; snprintf(buf, size, (fabs(n) > 1e-8 && fabs(n) < 1e8) || n == 0.0f ? "%f" : "%g", n); - append(buf); + append(buf); return *this; } TInfoSinkBase& operator+(const TPersistString& t) { append(t); return *this; } TInfoSinkBase& operator+(const TString& t) { append(t); return *this; } @@ -114,20 +113,20 @@ public: append(s); append("\n"); } - + void setOutputStream(int output = 4) { outputStream = output; } protected: - void append(const char* s); + void append(const char* s); void append(int count, char c); void append(const TPersistString& t); void append(const TString& t); - void checkMem(size_t growth) { if (sink.capacity() < sink.size() + growth + 2) + void checkMem(size_t growth) { if (sink.capacity() < sink.size() + growth + 2) sink.reserve(sink.capacity() + sink.capacity() / 2); } void appendToStream(const char* s); TPersistString sink; diff --git a/Externals/glslang/glslang/Include/InitializeGlobals.h b/Externals/glslang/glslang/Include/InitializeGlobals.h index 6c9f54a03d..95d0a40e99 100644 --- a/Externals/glslang/glslang/Include/InitializeGlobals.h +++ b/Externals/glslang/glslang/Include/InitializeGlobals.h @@ -1,10 +1,10 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -18,18 +18,18 @@ // 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. +// 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 __INITIALIZE_GLOBALS_INCLUDED_ @@ -37,10 +37,7 @@ namespace glslang { -void InitializeMemoryPools(); -void FreeGlobalPools(); bool InitializePoolIndex(); -void FreePoolIndex(); } // end namespace glslang diff --git a/Externals/glslang/glslang/Include/PoolAlloc.h b/Externals/glslang/glslang/Include/PoolAlloc.h index c3bebc6317..0e237a6a2c 100644 --- a/Externals/glslang/glslang/Include/PoolAlloc.h +++ b/Externals/glslang/glslang/Include/PoolAlloc.h @@ -1,12 +1,12 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2012-2013 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2012-2013 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,18 +20,18 @@ // 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. +// 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 _POOLALLOC_INCLUDED_ @@ -43,8 +43,8 @@ // // This header defines an allocator that can be used to efficiently -// allocate a large number of small requests for heap memory, with the -// intention that they are not individually deallocated, but rather +// allocate a large number of small requests for heap memory, with the +// intention that they are not individually deallocated, but rather // collectively deallocated at one time. // // This simultaneously @@ -61,16 +61,16 @@ // class as the allocator (second) template argument. // -#include -#include +#include +#include #include namespace glslang { -// If we are using guard blocks, we must track each indivual +// If we are using guard blocks, we must track each individual // allocation. If we aren't using guard blocks, these // never get instantiated, so won't have any impact. -// +// class TAllocation { public: @@ -87,7 +87,7 @@ public: memset(postGuard(), guardBlockEndVal, guardBlockSize); # endif } - + void check() const { checkGuardBlock(preGuard(), guardBlockBeginVal, "before"); checkGuardBlock(postGuard(), guardBlockEndVal, "after"); @@ -100,7 +100,7 @@ public: inline static size_t allocationSize(size_t size) { return size + 2 * guardBlockSize + headerSize(); } - + // Offset from surrounding buffer to get to user data buffer. inline static unsigned char* offsetAllocation(unsigned char* m) { return m + guardBlockSize + headerSize(); @@ -123,16 +123,16 @@ private: const static unsigned char userDataFill; const static size_t guardBlockSize; -# ifdef GUARD_BLOCKS +# ifdef GUARD_BLOCKS inline static size_t headerSize() { return sizeof(TAllocation); } # else inline static size_t headerSize() { return 0; } # endif }; - + // // There are several stacks. One is to track the pushing and popping -// of the user, and not yet implemented. The others are simply a +// of the user, and not yet implemented. The others are simply a // repositories of free pages or used pages. // // Page stacks are linked together with a simple header at the beginning @@ -141,7 +141,7 @@ private: // re-use. // // The "page size" used is not, nor must it match, the underlying OS -// page size. But, having it be about that size or equal to a set of +// page size. But, having it be about that size or equal to a set of // pages is likely most optimal. // class TPoolAllocator { @@ -185,7 +185,7 @@ public: protected: friend struct tHeader; - + struct tHeader { tHeader(tHeader* nextPage, size_t pageCount) : #ifdef GUARD_BLOCKS @@ -227,7 +227,7 @@ protected: } size_t pageSize; // granularity of allocation from the OS - size_t alignment; // all returned allocations will be aligned at + size_t alignment; // all returned allocations will be aligned at // this granularity, which will be a power of 2 size_t alignmentMask; size_t headerSkip; // amount of memory to skip to make room for the @@ -245,21 +245,13 @@ private: TPoolAllocator(const TPoolAllocator&); // don't allow default copy constructor }; - // // There could potentially be many pools with pops happening at // different times. But a simple use is to have a global pop // with everyone using the same global allocator. // -typedef TPoolAllocator* PoolAllocatorPointer; extern TPoolAllocator& GetThreadPoolAllocator(); - -struct TThreadMemoryPools -{ - TPoolAllocator* threadPoolAllocator; -}; - -void SetThreadPoolAllocator(TPoolAllocator& poolAllocator); +void SetThreadPoolAllocator(TPoolAllocator* poolAllocator); // // This STL compatible allocator is intended to be used as the allocator @@ -278,7 +270,7 @@ public: typedef T& reference; typedef const T& const_reference; typedef T value_type; - template + template struct rebind { typedef pool_allocator other; }; @@ -292,15 +284,15 @@ public: template pool_allocator(const pool_allocator& p) : allocator(p.getAllocator()) { } - pointer allocate(size_type n) { + pointer allocate(size_type n) { return reinterpret_cast(getAllocator().allocate(n * sizeof(T))); } - pointer allocate(size_type n, const void*) { + pointer allocate(size_type n, const void*) { return reinterpret_cast(getAllocator().allocate(n * sizeof(T))); } - void deallocate(void*, size_type) { } + void deallocate(void*, size_type) { } void deallocate(pointer, size_type) { } - pointer _Charalloc(size_t n) { + pointer _Charalloc(size_t n) { return reinterpret_cast(getAllocator().allocate(n)); } void construct(pointer p, const T& val) { new ((void *)p) T(val); } diff --git a/Externals/glslang/glslang/Include/ResourceLimits.h b/Externals/glslang/glslang/Include/ResourceLimits.h index e8c743d6b7..0d07b8c841 100644 --- a/Externals/glslang/glslang/Include/ResourceLimits.h +++ b/Externals/glslang/glslang/Include/ResourceLimits.h @@ -1,12 +1,12 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2013 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2013 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,18 +20,18 @@ // 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. +// 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 _RESOURCE_LIMITS_INCLUDED_ @@ -81,7 +81,7 @@ struct TBuiltInResource { int maxComputeImageUniforms; int maxComputeAtomicCounters; int maxComputeAtomicCounterBuffers; - int maxVaryingComponents; + int maxVaryingComponents; int maxVertexOutputComponents; int maxGeometryInputComponents; int maxGeometryOutputComponents; diff --git a/Externals/glslang/glslang/Include/ShHandle.h b/Externals/glslang/glslang/Include/ShHandle.h index fee641396c..df07bd8eda 100644 --- a/Externals/glslang/glslang/Include/ShHandle.h +++ b/Externals/glslang/glslang/Include/ShHandle.h @@ -1,10 +1,10 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -18,18 +18,18 @@ // 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. +// 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 _SHHANDLE_INCLUDED_ @@ -42,8 +42,7 @@ // This should not be included by driver code. // - -#define SH_EXPORTING +#define SH_EXPORTING #include "../Public/ShaderLang.h" #include "../MachineIndependent/Versions.h" #include "InfoSink.h" @@ -57,11 +56,14 @@ class TUniformMap; // class TShHandleBase { public: - TShHandleBase() { } - virtual ~TShHandleBase() { } + TShHandleBase() { pool = new glslang::TPoolAllocator; } + virtual ~TShHandleBase() { delete pool; } virtual TCompiler* getAsCompiler() { return 0; } virtual TLinker* getAsLinker() { return 0; } virtual TUniformMap* getAsUniformMap() { return 0; } + virtual glslang::TPoolAllocator* getPool() const { return pool; } +private: + glslang::TPoolAllocator* pool; }; // @@ -73,7 +75,7 @@ public: TUniformMap() { } virtual ~TUniformMap() { } virtual TUniformMap* getAsUniformMap() { return this; } - virtual int getLocation(const char* name) = 0; + virtual int getLocation(const char* name) = 0; virtual TInfoSink& getInfoSink() { return infoSink; } TInfoSink infoSink; }; @@ -95,7 +97,7 @@ public: virtual TCompiler* getAsCompiler() { return this; } virtual bool linkable() { return haveValidObjectCode; } - + TInfoSink& infoSink; protected: TCompiler& operator=(TCompiler&); @@ -117,14 +119,14 @@ typedef glslang::TVector THandleList; class TLinker : public TShHandleBase { public: - TLinker(EShExecutable e, TInfoSink& iSink) : + TLinker(EShExecutable e, TInfoSink& iSink) : infoSink(iSink), - executable(e), + executable(e), haveReturnableObjectCode(false), appAttributeBindings(0), fixedAttributeBindings(0), - excludedAttributes(0), - excludedCount(0), + excludedAttributes(0), + excludedCount(0), uniformBindings(0) { } virtual TLinker* getAsLinker() { return this; } virtual ~TLinker() { } @@ -132,8 +134,8 @@ public: virtual bool link(THandleList&) { return false; } virtual void setAppAttributeBindings(const ShBindingTable* t) { appAttributeBindings = t; } virtual void setFixedAttributeBindings(const ShBindingTable* t) { fixedAttributeBindings = t; } - virtual void getAttributeBindings(ShBindingTable const **t) const = 0; - virtual void setExcludedAttributes(const int* attributes, int count) { excludedAttributes = attributes; excludedCount = count; } + virtual void getAttributeBindings(ShBindingTable const **t) const = 0; + virtual void setExcludedAttributes(const int* attributes, int count) { excludedAttributes = attributes; excludedCount = count; } virtual ShBindingTable* getUniformBindings() const { return uniformBindings; } virtual const void* getObjectCode() const { return 0; } // a real compiler would be returning object code here virtual TInfoSink& getInfoSink() { return infoSink; } @@ -145,9 +147,9 @@ protected: const ShBindingTable* appAttributeBindings; const ShBindingTable* fixedAttributeBindings; - const int* excludedAttributes; - int excludedCount; - ShBindingTable* uniformBindings; // created by the linker + const int* excludedAttributes; + int excludedCount; + ShBindingTable* uniformBindings; // created by the linker }; // @@ -155,7 +157,7 @@ protected: // and the machine dependent code. // // The machine dependent code should derive from the classes -// above. Then Construct*() and Delete*() will create and +// above. Then Construct*() and Delete*() will create and // destroy the machine dependent objects, which contain the // above machine independent information. // @@ -165,7 +167,7 @@ TShHandleBase* ConstructLinker(EShExecutable, int); TShHandleBase* ConstructBindings(); void DeleteLinker(TShHandleBase*); void DeleteBindingList(TShHandleBase* bindingList); - + TUniformMap* ConstructUniformMap(); void DeleteCompiler(TCompiler*); diff --git a/Externals/glslang/glslang/Include/Types.h b/Externals/glslang/glslang/Include/Types.h index f3ea895086..39d6737cfc 100644 --- a/Externals/glslang/glslang/Include/Types.h +++ b/Externals/glslang/glslang/Include/Types.h @@ -1,13 +1,14 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2012-2016 LunarG, Inc. -//Copyright (C) 2015-2016 Google, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2012-2016 LunarG, Inc. +// Copyright (C) 2015-2016 Google, Inc. +// Copyright (C) 2017 ARM Limited. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -21,18 +22,18 @@ // 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. +// 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 _TYPES_INCLUDED @@ -43,6 +44,8 @@ #include "../Public/ShaderLang.h" #include "arrays.h" +#include + namespace glslang { const int GlslangMaxTypeLength = 200; // TODO: need to print block/struct one member per line, so this can stay bounded @@ -78,6 +81,19 @@ struct TSampler { // misnomer now; includes images, textures without sampler, 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 external : 1; // GL_OES_EGL_image_external + unsigned int vectorSize : 3; // vector return type size. + + // Some languages support structures as sample results. Storing the whole structure in the + // TSampler is too large, so there is an index to a separate table. + static const unsigned structReturnIndexBits = 4; // number of index bits to use. + static const unsigned structReturnSlots = (1<= 0 && p <= EpqHigh); + assert(p >= EpqNone && p <= EpqHigh); + assert(!(isMatrix() && vectorSize != 0)); // prevent vectorSize != 0 on matrices } // for turning a TPublicType into a TType, using a shallow copy explicit TType(const TPublicType& p) : @@ -1166,33 +1295,24 @@ public: typeName = copyOf.typeName; } + // Make complete copy of the whole type graph rooted at 'copyOf'. void deepCopy(const TType& copyOf) { - shallowCopy(copyOf); - - if (copyOf.arraySizes) { - arraySizes = new TArraySizes; - *arraySizes = *copyOf.arraySizes; - } - - if (copyOf.structure) { - structure = new TTypeList; - for (unsigned int i = 0; i < copyOf.structure->size(); ++i) { - TTypeLoc typeLoc; - typeLoc.loc = (*copyOf.structure)[i].loc; - typeLoc.type = new TType(); - typeLoc.type->deepCopy(*(*copyOf.structure)[i].type); - structure->push_back(typeLoc); - } - } - - if (copyOf.fieldName) - fieldName = NewPoolTString(copyOf.fieldName->c_str()); - if (copyOf.typeName) - typeName = NewPoolTString(copyOf.typeName->c_str()); + TMap copied; // to enable copying a type graph as a graph, not a tree + deepCopy(copyOf, copied); } - TType* clone() + // Recursively make temporary + void makeTemporary() + { + getQualifier().makeTemporary(); + + if (isStruct()) + for (unsigned int i = 0; i < structure->size(); ++i) + (*structure)[i].type->makeTemporary(); + } + + TType* clone() const { TType *newType = new TType(); newType->deepCopy(*this); @@ -1202,31 +1322,9 @@ public: void makeVector() { vector1 = true; } - // Merge type from parent, where a parentType is at the beginning of a declaration, - // establishing some characteristics for all subsequent names, while this type - // is on the individual names. - void mergeType(const TPublicType& parentType) - { - // arrayness is currently the only child aspect that has to be preserved - basicType = parentType.basicType; - vectorSize = parentType.vectorSize; - matrixCols = parentType.matrixCols; - matrixRows = parentType.matrixRows; - vector1 = false; // TPublicType is only GLSL which so far has no vec1 - qualifier = parentType.qualifier; - sampler = parentType.sampler; - if (parentType.arraySizes) - newArraySizes(*parentType.arraySizes); - if (parentType.userDef) { - structure = parentType.userDef->getWritableStruct(); - setTypeName(parentType.userDef->getTypeName()); - } - } - virtual void hideMember() { basicType = EbtVoid; vectorSize = 1; } virtual bool hiddenMember() const { return basicType == EbtVoid; } - virtual void setTypeName(const TString& n) { typeName = NewPoolTString(n.c_str()); } virtual void setFieldName(const TString& n) { fieldName = NewPoolTString(n.c_str()); } virtual const TString& getTypeName() const { @@ -1242,6 +1340,7 @@ public: virtual TBasicType getBasicType() const { return basicType; } virtual const TSampler& getSampler() const { return sampler; } + virtual TSampler& getSampler() { return sampler; } virtual TQualifier& getQualifier() { return qualifier; } virtual const TQualifier& getQualifier() const { return qualifier; } @@ -1255,127 +1354,122 @@ public: virtual bool isArrayOfArrays() const { return arraySizes != nullptr && arraySizes->getNumDims() > 1; } virtual int getImplicitArraySize() const { return arraySizes->getImplicitSize(); } virtual const TArraySizes* getArraySizes() const { return arraySizes; } - virtual TArraySizes& getArraySizes() { assert(arraySizes != nullptr); return *arraySizes; } + virtual TArraySizes* getArraySizes() { return arraySizes; } virtual bool isScalar() const { return ! isVector() && ! isMatrix() && ! isStruct() && ! isArray(); } + virtual bool isScalarOrVec1() const { return isScalar() || vector1; } virtual bool isVector() const { return vectorSize > 1 || vector1; } virtual bool isMatrix() const { return matrixCols ? true : false; } virtual bool isArray() const { return arraySizes != nullptr; } - virtual bool isExplicitlySizedArray() const { return isArray() && getOuterArraySize() != UnsizedArraySize; } - virtual bool isImplicitlySizedArray() const { return isArray() && getOuterArraySize() == UnsizedArraySize && qualifier.storage != EvqBuffer; } - virtual bool isRuntimeSizedArray() const { return isArray() && getOuterArraySize() == UnsizedArraySize && qualifier.storage == EvqBuffer; } + virtual bool isSizedArray() const { return isArray() && arraySizes->isSized(); } + virtual bool isUnsizedArray() const { return isArray() && !arraySizes->isSized(); } + virtual bool isArrayVariablyIndexed() const { assert(isArray()); return arraySizes->isVariablyIndexed(); } + virtual void setArrayVariablyIndexed() { assert(isArray()); arraySizes->setVariablyIndexed(); } + virtual void updateImplicitArraySize(int size) { assert(isArray()); arraySizes->updateImplicitSize(size); } virtual bool isStruct() const { return structure != nullptr; } - virtual bool isFloatingDomain() const { return basicType == EbtFloat || basicType == EbtDouble; } - + virtual bool isFloatingDomain() const { return basicType == EbtFloat || basicType == EbtDouble || basicType == EbtFloat16; } + virtual bool isIntegerDomain() const + { + switch (basicType) { + case EbtInt8: + case EbtUint8: + case EbtInt16: + case EbtUint16: + case EbtInt: + case EbtUint: + case EbtInt64: + case EbtUint64: + case EbtAtomicUint: + return true; + default: + break; + } + return false; + } virtual bool isOpaque() const { return basicType == EbtSampler || basicType == EbtAtomicUint; } + virtual bool isBuiltIn() const { return getQualifier().builtIn != EbvNone; } // "Image" is a superset of "Subpass" - virtual bool isImage() const { return basicType == EbtSampler && getSampler().isImage(); } + virtual bool isImage() const { return basicType == EbtSampler && getSampler().isImage(); } virtual bool isSubpass() const { return basicType == EbtSampler && getSampler().isSubpass(); } + virtual bool isTexture() const { return basicType == EbtSampler && getSampler().isTexture(); } + + // return true if this type contains any subtype which satisfies the given predicate. + template + bool contains(P predicate) const + { + if (predicate(this)) + return true; + + const auto hasa = [predicate](const TTypeLoc& tl) { return tl.type->contains(predicate); }; + + return structure && std::any_of(structure->begin(), structure->end(), hasa); + } // Recursively checks if the type contains the given basic type virtual bool containsBasicType(TBasicType checkType) const { - if (basicType == checkType) - return true; - if (! structure) - return false; - for (unsigned int i = 0; i < structure->size(); ++i) { - if ((*structure)[i].type->containsBasicType(checkType)) - return true; - } - return false; + return contains([checkType](const TType* t) { return t->basicType == checkType; } ); } // Recursively check the structure for any arrays, needed for some error checks virtual bool containsArray() const { - if (isArray()) - return true; - if (structure == nullptr) - return false; - for (unsigned int i = 0; i < structure->size(); ++i) { - if ((*structure)[i].type->containsArray()) - return true; - } - return false; + return contains([](const TType* t) { return t->isArray(); } ); } // Check the structure for any structures, needed for some error checks virtual bool containsStructure() const { - if (structure == nullptr) - return false; - for (unsigned int i = 0; i < structure->size(); ++i) { - if ((*structure)[i].type->structure) - return true; - } - return false; + return contains([this](const TType* t) { return t != this && t->isStruct(); } ); } - // Recursively check the structure for any implicitly-sized arrays, needed for triggering a copyUp(). - virtual bool containsImplicitlySizedArray() const + // Recursively check the structure for any unsized arrays, needed for triggering a copyUp(). + virtual bool containsUnsizedArray() const { - if (isImplicitlySizedArray()) - return true; - if (structure == nullptr) - return false; - for (unsigned int i = 0; i < structure->size(); ++i) { - if ((*structure)[i].type->containsImplicitlySizedArray()) - return true; - } - return false; + return contains([](const TType* t) { return t->isUnsizedArray(); } ); } virtual bool containsOpaque() const { - if (isOpaque()) - return true; - if (! structure) - return false; - for (unsigned int i = 0; i < structure->size(); ++i) { - if ((*structure)[i].type->containsOpaque()) - return true; - } - return false; + return contains([](const TType* t) { return t->isOpaque(); } ); + } + + // Recursively checks if the type contains a built-in variable + virtual bool containsBuiltIn() const + { + return contains([](const TType* t) { return t->isBuiltIn(); } ); } virtual bool containsNonOpaque() const { - // list all non-opaque types - switch (basicType) { - case EbtVoid: - case EbtFloat: - case EbtDouble: - case EbtInt: - case EbtUint: - case EbtInt64: - case EbtUint64: - case EbtBool: - return true; - default: - break; - } - if (! structure) - return false; - for (unsigned int i = 0; i < structure->size(); ++i) { - if ((*structure)[i].type->containsNonOpaque()) + const auto nonOpaque = [](const TType* t) { + switch (t->basicType) { + case EbtVoid: + case EbtFloat: + case EbtDouble: + case EbtFloat16: + case EbtInt8: + case EbtUint8: + case EbtInt16: + case EbtUint16: + case EbtInt: + case EbtUint: + case EbtInt64: + case EbtUint64: + case EbtBool: return true; - } - return false; + default: + return false; + } + }; + + return contains(nonOpaque); } virtual bool containsSpecializationSize() const { - if (isArray() && arraySizes->containsNode()) - return true; - if (! structure) - return false; - for (unsigned int i = 0; i < structure->size(); ++i) { - if ((*structure)[i].type->containsSpecializationSize()) - return true; - } - return false; + return contains([](const TType* t) { return t->isArray() && t->arraySizes->isOuterSpecialization(); } ); } // Array editing methods. Array descriptors can be shared across @@ -1397,34 +1491,51 @@ public: assert(type.arraySizes != nullptr); *arraySizes = *type.arraySizes; } - void newArraySizes(const TArraySizes& s) + void copyArraySizes(const TArraySizes& s) { // For setting a fresh new set of array sizes, not yet worrying about sharing. arraySizes = new TArraySizes; *arraySizes = s; } + void transferArraySizes(TArraySizes* s) + { + // For setting an already allocated set of sizes that this type can use + // (no copy made). + arraySizes = s; + } void clearArraySizes() { - arraySizes = 0; + arraySizes = nullptr; } - void addArrayOuterSizes(const TArraySizes& s) + + // Add inner array sizes, to any existing sizes, via copy; the + // sizes passed in can still be reused for other purposes. + void copyArrayInnerSizes(const TArraySizes* s) { - if (arraySizes == nullptr) - newArraySizes(s); - else - arraySizes->addOuterSizes(s); + if (s != nullptr) { + if (arraySizes == nullptr) + copyArraySizes(*s); + else + arraySizes->addInnerSizes(*s); + } } void changeOuterArraySize(int s) { arraySizes->changeOuterSize(s); } - void setImplicitArraySize(int s) { arraySizes->setImplicitSize(s); } - // Recursively make the implicit array size the explicit array size, through the type tree. - void adoptImplicitArraySizes() + // Recursively make the implicit array size the explicit array size. + // Expicit arrays are compile-time or link-time sized, never run-time sized. + // Sometimes, policy calls for an array to be run-time sized even if it was + // never variably indexed: Don't turn a 'skipNonvariablyIndexed' array into + // an explicit array. + void adoptImplicitArraySizes(bool skipNonvariablyIndexed) { - if (isImplicitlySizedArray()) + if (isUnsizedArray() && !(skipNonvariablyIndexed || isArrayVariablyIndexed())) changeOuterArraySize(getImplicitArraySize()); - if (isStruct()) { - for (int i = 0; i < (int)structure->size(); ++i) - (*structure)[i].type->adoptImplicitArraySizes(); + if (isStruct() && structure->size() > 0) { + int lastMember = (int)structure->size() - 1; + for (int i = 0; i < lastMember; ++i) + (*structure)[i].type->adoptImplicitArraySizes(false); + // implement the "last member of an SSBO" policy + (*structure)[lastMember].type->adoptImplicitArraySizes(getQualifier().storage == EvqBuffer); } } @@ -1439,6 +1550,11 @@ public: case EbtVoid: return "void"; case EbtFloat: return "float"; case EbtDouble: return "double"; + case EbtFloat16: return "float16_t"; + case EbtInt8: return "int8_t"; + case EbtUint8: return "uint8_t"; + case EbtInt16: return "int16_t"; + case EbtUint16: return "uint16_t"; case EbtInt: return "int"; case EbtUint: return "uint"; case EbtInt64: return "int64_t"; @@ -1454,10 +1570,11 @@ public: TString getCompleteString() const { - const int maxSize = GlslangMaxTypeLength; - char buf[maxSize]; - char* p = &buf[0]; - char* end = &buf[maxSize]; + TString typeString; + + const auto appendStr = [&](const char* s) { typeString.append(s); }; + const auto appendUint = [&](unsigned int u) { typeString.append(std::to_string(u).c_str()); }; + const auto appendInt = [&](int i) { typeString.append(std::to_string(i).c_str()); }; if (qualifier.hasLayout()) { // To reduce noise, skip this if the only layout is an xfb_buffer @@ -1465,123 +1582,185 @@ public: TQualifier noXfbBuffer = qualifier; noXfbBuffer.layoutXfbBuffer = TQualifier::layoutXfbBufferEnd; if (noXfbBuffer.hasLayout()) { - p += snprintf(p, end - p, "layout("); + appendStr("layout("); if (qualifier.hasAnyLocation()) { - p += snprintf(p, end - p, "location=%d ", qualifier.layoutLocation); - if (qualifier.hasComponent()) - p += snprintf(p, end - p, "component=%d ", qualifier.layoutComponent); - if (qualifier.hasIndex()) - p += snprintf(p, end - p, "index=%d ", qualifier.layoutIndex); + appendStr(" location="); + appendUint(qualifier.layoutLocation); + if (qualifier.hasComponent()) { + appendStr(" component="); + appendUint(qualifier.layoutComponent); + } + if (qualifier.hasIndex()) { + appendStr(" index="); + appendUint(qualifier.layoutIndex); + } + } + if (qualifier.hasSet()) { + appendStr(" set="); + appendUint(qualifier.layoutSet); + } + if (qualifier.hasBinding()) { + appendStr(" binding="); + appendUint(qualifier.layoutBinding); + } + if (qualifier.hasStream()) { + appendStr(" stream="); + appendUint(qualifier.layoutStream); + } + if (qualifier.hasMatrix()) { + appendStr(" "); + appendStr(TQualifier::getLayoutMatrixString(qualifier.layoutMatrix)); + } + if (qualifier.hasPacking()) { + appendStr(" "); + appendStr(TQualifier::getLayoutPackingString(qualifier.layoutPacking)); + } + if (qualifier.hasOffset()) { + appendStr(" offset="); + appendInt(qualifier.layoutOffset); + } + if (qualifier.hasAlign()) { + appendStr(" align="); + appendInt(qualifier.layoutAlign); + } + if (qualifier.hasFormat()) { + appendStr(" "); + appendStr(TQualifier::getLayoutFormatString(qualifier.layoutFormat)); + } + if (qualifier.hasXfbBuffer() && qualifier.hasXfbOffset()) { + appendStr(" xfb_buffer="); + appendUint(qualifier.layoutXfbBuffer); + } + if (qualifier.hasXfbOffset()) { + appendStr(" xfb_offset="); + appendUint(qualifier.layoutXfbOffset); + } + if (qualifier.hasXfbStride()) { + appendStr(" xfb_stride="); + appendUint(qualifier.layoutXfbStride); + } + if (qualifier.hasAttachment()) { + appendStr(" input_attachment_index="); + appendUint(qualifier.layoutAttachment); + } + if (qualifier.hasSpecConstantId()) { + appendStr(" constant_id="); + appendUint(qualifier.layoutSpecConstantId); } - if (qualifier.hasSet()) - p += snprintf(p, end - p, "set=%d ", qualifier.layoutSet); - if (qualifier.hasBinding()) - p += snprintf(p, end - p, "binding=%d ", qualifier.layoutBinding); - if (qualifier.hasStream()) - p += snprintf(p, end - p, "stream=%d ", qualifier.layoutStream); - if (qualifier.hasMatrix()) - p += snprintf(p, end - p, "%s ", TQualifier::getLayoutMatrixString(qualifier.layoutMatrix)); - if (qualifier.hasPacking()) - p += snprintf(p, end - p, "%s ", TQualifier::getLayoutPackingString(qualifier.layoutPacking)); - if (qualifier.hasOffset()) - p += snprintf(p, end - p, "offset=%d ", qualifier.layoutOffset); - if (qualifier.hasAlign()) - p += snprintf(p, end - p, "align=%d ", qualifier.layoutAlign); - if (qualifier.hasFormat()) - p += snprintf(p, end - p, "%s ", TQualifier::getLayoutFormatString(qualifier.layoutFormat)); - if (qualifier.hasXfbBuffer() && qualifier.hasXfbOffset()) - p += snprintf(p, end - p, "xfb_buffer=%d ", qualifier.layoutXfbBuffer); - if (qualifier.hasXfbOffset()) - p += snprintf(p, end - p, "xfb_offset=%d ", qualifier.layoutXfbOffset); - if (qualifier.hasXfbStride()) - p += snprintf(p, end - p, "xfb_stride=%d ", qualifier.layoutXfbStride); - if (qualifier.hasAttachment()) - p += snprintf(p, end - p, "input_attachment_index=%d ", qualifier.layoutAttachment); - if (qualifier.hasSpecConstantId()) - p += snprintf(p, end - p, "constant_id=%d ", qualifier.layoutSpecConstantId); if (qualifier.layoutPushConstant) - p += snprintf(p, end - p, "push_constant "); - p += snprintf(p, end - p, ") "); + appendStr(" push_constant"); + +#ifdef NV_EXTENSIONS + if (qualifier.layoutPassthrough) + appendStr(" passthrough"); + if (qualifier.layoutViewportRelative) + appendStr(" layoutViewportRelative"); + if (qualifier.layoutSecondaryViewportRelativeOffset != -2048) { + appendStr(" layoutSecondaryViewportRelativeOffset="); + appendInt(qualifier.layoutSecondaryViewportRelativeOffset); + } +#endif + + appendStr(")"); } } if (qualifier.invariant) - p += snprintf(p, end - p, "invariant "); + appendStr(" invariant"); if (qualifier.noContraction) - p += snprintf(p, end - p, "noContraction "); + appendStr(" noContraction"); if (qualifier.centroid) - p += snprintf(p, end - p, "centroid "); + appendStr(" centroid"); if (qualifier.smooth) - p += snprintf(p, end - p, "smooth "); + appendStr(" smooth"); if (qualifier.flat) - p += snprintf(p, end - p, "flat "); + appendStr(" flat"); if (qualifier.nopersp) - p += snprintf(p, end - p, "noperspective "); + appendStr(" noperspective"); +#ifdef AMD_EXTENSIONS + if (qualifier.explicitInterp) + appendStr(" __explicitInterpAMD"); +#endif if (qualifier.patch) - p += snprintf(p, end - p, "patch "); + appendStr(" patch"); if (qualifier.sample) - p += snprintf(p, end - p, "sample "); + appendStr(" sample"); if (qualifier.coherent) - p += snprintf(p, end - p, "coherent "); + appendStr(" coherent"); if (qualifier.volatil) - p += snprintf(p, end - p, "volatile "); + appendStr(" volatile"); if (qualifier.restrict) - p += snprintf(p, end - p, "restrict "); + appendStr(" restrict"); if (qualifier.readonly) - p += snprintf(p, end - p, "readonly "); + appendStr(" readonly"); if (qualifier.writeonly) - p += snprintf(p, end - p, "writeonly "); + appendStr(" writeonly"); if (qualifier.specConstant) - p += snprintf(p, end - p, "specialization-constant "); - p += snprintf(p, end - p, "%s ", getStorageQualifierString()); + appendStr(" specialization-constant"); + if (qualifier.nonUniform) + appendStr(" nonuniform"); + appendStr(" "); + appendStr(getStorageQualifierString()); if (isArray()) { for(int i = 0; i < (int)arraySizes->getNumDims(); ++i) { int size = arraySizes->getDimSize(i); - if (size == 0) - p += snprintf(p, end - p, "implicitly-sized array of "); - else - p += snprintf(p, end - p, "%d-element array of ", arraySizes->getDimSize(i)); + if (size == UnsizedArraySize && i == 0 && arraySizes->isVariablyIndexed()) + appendStr(" runtime-sized array of"); + else { + if (size == UnsizedArraySize) { + appendStr(" unsized"); + if (i == 0) { + appendStr(" "); + appendInt(arraySizes->getImplicitSize()); + } + } else { + appendStr(" "); + appendInt(arraySizes->getDimSize(i)); + } + appendStr("-element array of"); + } } } - if (qualifier.precision != EpqNone) - p += snprintf(p, end - p, "%s ", getPrecisionQualifierString()); - if (isMatrix()) - p += snprintf(p, end - p, "%dX%d matrix of ", matrixCols, matrixRows); - else if (isVector()) - p += snprintf(p, end - p, "%d-component vector of ", vectorSize); + if (qualifier.precision != EpqNone) { + appendStr(" "); + appendStr(getPrecisionQualifierString()); + } + if (isMatrix()) { + appendStr(" "); + appendInt(matrixCols); + appendStr("X"); + appendInt(matrixRows); + appendStr(" matrix of"); + } else if (isVector()) { + appendStr(" "); + appendInt(vectorSize); + appendStr("-component vector of"); + } - *p = 0; - TString s(buf); - s.append(getBasicTypeString()); + appendStr(" "); + typeString.append(getBasicTypeString()); if (qualifier.builtIn != EbvNone) { - s.append(" "); - s.append(getBuiltInVariableString()); + appendStr(" "); + appendStr(getBuiltInVariableString()); } // Add struct/block members if (structure) { - s.append("{"); + appendStr("{"); for (size_t i = 0; i < structure->size(); ++i) { - if (s.size() > 3 * GlslangMaxTypeLength) { - // If we are getting too long, cut it short, - // just need to draw the line somewhere, as there is no limit to - // how large a struct/block type can get. - s.append("..."); - break; - } if (! (*structure)[i].type->hiddenMember()) { - s.append((*structure)[i].type->getCompleteString()); - s.append(" "); - s.append((*structure)[i].type->getFieldName()); + typeString.append((*structure)[i].type->getCompleteString()); + typeString.append(" "); + typeString.append((*structure)[i].type->getFieldName()); if (i < structure->size() - 1) - s.append(", "); + appendStr(", "); } } - s.append("}"); + appendStr("}"); } - return s; + return typeString; } TString getBasicTypeString() const @@ -1596,6 +1775,7 @@ public: const char* getBuiltInVariableString() const { return GetBuiltInVariableString(qualifier.builtIn); } const char* getPrecisionQualifierString() const { return GetPrecisionQualifierString(qualifier.precision); } const TTypeList* getStruct() const { return structure; } + void setStruct(TTypeList* s) { structure = s; } TTypeList* getWritableStruct() const { return structure; } // This should only be used when known to not be sharing with other threads int computeNumComponents() const @@ -1618,7 +1798,7 @@ public: } // append this type's mangled name to the passed in 'name' - void appendMangledName(TString& name) + void appendMangledName(TString& name) const { buildMangledName(name); name += ';' ; @@ -1706,7 +1886,43 @@ protected: TType(const TType& type); TType& operator=(const TType& type); - void buildMangledName(TString&); + // Recursively copy a type graph, while preserving the graph-like + // quality. That is, don't make more than one copy of a structure that + // gets reused multiple times in the type graph. + void deepCopy(const TType& copyOf, TMap& copiedMap) + { + shallowCopy(copyOf); + + if (copyOf.arraySizes) { + arraySizes = new TArraySizes; + *arraySizes = *copyOf.arraySizes; + } + + if (copyOf.structure) { + auto prevCopy = copiedMap.find(copyOf.structure); + if (prevCopy != copiedMap.end()) + structure = prevCopy->second; + else { + structure = new TTypeList; + copiedMap[copyOf.structure] = structure; + for (unsigned int i = 0; i < copyOf.structure->size(); ++i) { + TTypeLoc typeLoc; + typeLoc.loc = (*copyOf.structure)[i].loc; + typeLoc.type = new TType(); + typeLoc.type->deepCopy(*(*copyOf.structure)[i].type, copiedMap); + structure->push_back(typeLoc); + } + } + } + + if (copyOf.fieldName) + fieldName = NewPoolTString(copyOf.fieldName->c_str()); + if (copyOf.typeName) + typeName = NewPoolTString(copyOf.typeName->c_str()); + } + + + void buildMangledName(TString&) const; TBasicType basicType : 8; int vectorSize : 4; // 1 means either scalar or 1-component vector; see vector1 to disambiguate. diff --git a/Externals/glslang/glslang/Include/arrays.h b/Externals/glslang/glslang/Include/arrays.h index a50088d2db..af8f560b3b 100644 --- a/Externals/glslang/glslang/Include/arrays.h +++ b/Externals/glslang/glslang/Include/arrays.h @@ -1,12 +1,12 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2012-2013 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2012-2013 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,18 +20,18 @@ // 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. +// 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. // // @@ -41,6 +41,8 @@ #ifndef _ARRAYS_INCLUDED #define _ARRAYS_INCLUDED +#include + namespace glslang { // This is used to mean there is no size yet (unsized), it is waiting to get a size from somewhere else. @@ -130,10 +132,10 @@ struct TSmallArrayVector { sizes->push_back(pair); } - void push_front(const TSmallArrayVector& newDims) + void push_back(const TSmallArrayVector& newDims) { alloc(); - sizes->insert(sizes->begin(), newDims.sizes->begin(), newDims.sizes->end()); + sizes->insert(sizes->end(), newDims.sizes->begin(), newDims.sizes->end()); } void pop_front() @@ -220,12 +222,13 @@ protected: struct TArraySizes { POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) - TArraySizes() : implicitArraySize(1) { } + TArraySizes() : implicitArraySize(1), variablyIndexed(false) { } // For breaking into two non-shared copies, independently modifiable. TArraySizes& operator=(const TArraySizes& from) { implicitArraySize = from.implicitArraySize; + variablyIndexed = from.variablyIndexed; sizes = from.sizes; return *this; @@ -252,10 +255,11 @@ struct TArraySizes { void addInnerSize(int s) { addInnerSize((unsigned)s, nullptr); } void addInnerSize(int s, TIntermTyped* n) { sizes.push_back((unsigned)s, n); } void addInnerSize(TArraySize pair) { sizes.push_back(pair.size, pair.node); } + void addInnerSizes(const TArraySizes& s) { sizes.push_back(s.sizes); } void changeOuterSize(int s) { sizes.changeFront((unsigned)s); } - int getImplicitSize() const { return (int)implicitArraySize; } - void setImplicitSize(int s) { implicitArraySize = s; } - bool isInnerImplicit() const + int getImplicitSize() const { return implicitArraySize; } + void updateImplicitSize(int s) { implicitArraySize = std::max(implicitArraySize, s); } + bool isInnerUnsized() const { for (int d = 1; d < sizes.size(); ++d) { if (sizes.getDimSize(d) == (unsigned)UnsizedArraySize) @@ -264,8 +268,31 @@ struct TArraySizes { return false; } - bool isImplicit() const { return getOuterSize() == UnsizedArraySize || isInnerImplicit(); } - void addOuterSizes(const TArraySizes& s) { sizes.push_front(s.sizes); } + bool clearInnerUnsized() + { + for (int d = 1; d < sizes.size(); ++d) { + if (sizes.getDimSize(d) == (unsigned)UnsizedArraySize) + setDimSize(d, 1); + } + + return false; + } + bool isInnerSpecialization() const + { + for (int d = 1; d < sizes.size(); ++d) { + if (sizes.getDimNode(d) != nullptr) + return true; + } + + return false; + } + bool isOuterSpecialization() + { + return sizes.getDimNode(0) != nullptr; + } + + bool hasUnsized() const { return getOuterSize() == UnsizedArraySize || isInnerUnsized(); } + bool isSized() const { return getOuterSize() != UnsizedArraySize; } void dereference() { sizes.pop_front(); } void copyDereferenced(const TArraySizes& rhs) { @@ -288,17 +315,8 @@ struct TArraySizes { return true; } - // Returns true if any of the dimensions of the array is sized with a node - // instead of a front-end compile-time constant. - bool containsNode() - { - for (int d = 0; d < sizes.size(); ++d) { - if (sizes.getDimNode(d) != nullptr) - return true; - } - - return false; - } + void setVariablyIndexed() { variablyIndexed = true; } + bool isVariablyIndexed() const { return variablyIndexed; } bool operator==(const TArraySizes& rhs) { return sizes == rhs.sizes; } bool operator!=(const TArraySizes& rhs) { return sizes != rhs.sizes; } @@ -308,9 +326,12 @@ protected: TArraySizes(const TArraySizes&); - // for tracking maximum referenced index, before an explicit size is given - // applies only to the outer-most dimension + // For tracking maximum referenced compile-time constant index. + // Applies only to the outer-most dimension. Potentially becomes + // the implicit size of the array, if not variably indexed and + // otherwise legal. int implicitArraySize; + bool variablyIndexed; // true if array is indexed with a non compile-time constant }; } // end namespace glslang diff --git a/Externals/glslang/glslang/Include/intermediate.h b/Externals/glslang/glslang/Include/intermediate.h old mode 100644 new mode 100755 index a74b96e999..19eb7aa876 --- a/Externals/glslang/glslang/Include/intermediate.h +++ b/Externals/glslang/glslang/Include/intermediate.h @@ -1,12 +1,13 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2012-2016 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2012-2016 LunarG, Inc. +// Copyright (C) 2017 ARM Limited. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,25 +21,25 @@ // 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. +// 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. // // // Definition of the in-memory high-level intermediate representation // of shaders. This is a tree that parser creates. // -// Nodes in the tree are defined as a hierarchy of classes derived from +// Nodes in the tree are defined as a hierarchy of classes derived from // TIntermNode. Each is a node in a tree. There is no preset branching factor; // each node can have it's own type of list of children. // @@ -46,12 +47,19 @@ #ifndef __INTERMEDIATE_H #define __INTERMEDIATE_H +#if defined(_MSC_VER) && _MSC_VER >= 1900 + #pragma warning(disable : 4464) // relative include path contains '..' + #pragma warning(disable : 5026) // 'glslang::TIntermUnary': move constructor was implicitly defined as deleted +#endif + #include "../Include/Common.h" #include "../Include/Types.h" #include "../Include/ConstantUnion.h" namespace glslang { +class TIntermediate; + // // Operators used by the high-level (parse tree) representation. // @@ -59,14 +67,14 @@ enum TOperator { EOpNull, // if in a node, should only mean a node is still being built EOpSequence, // denotes a list of statements, or parameters, etc. EOpLinkerObjects, // for aggregate node of objects the linker may need, if not reference by the rest of the AST - EOpFunctionCall, + EOpFunctionCall, EOpFunction, // For function definition EOpParameters, // an aggregate listing the parameters to a function // // Unary operators // - + EOpNegative, EOpLogicalNot, EOpVectorLogicalNot, @@ -77,49 +85,190 @@ enum TOperator { EOpPreIncrement, EOpPreDecrement, + // (u)int* -> bool + EOpConvInt8ToBool, + EOpConvUint8ToBool, + EOpConvInt16ToBool, + EOpConvUint16ToBool, EOpConvIntToBool, EOpConvUintToBool, - EOpConvFloatToBool, - EOpConvDoubleToBool, EOpConvInt64ToBool, EOpConvUint64ToBool, - EOpConvBoolToFloat, - EOpConvIntToFloat, - EOpConvUintToFloat, - EOpConvDoubleToFloat, - EOpConvInt64ToFloat, - EOpConvUint64ToFloat, - EOpConvUintToInt, - EOpConvFloatToInt, + + // float* -> bool + EOpConvFloat16ToBool, + EOpConvFloatToBool, + EOpConvDoubleToBool, + + // bool -> (u)int* + EOpConvBoolToInt8, + EOpConvBoolToUint8, + EOpConvBoolToInt16, + EOpConvBoolToUint16, EOpConvBoolToInt, - EOpConvDoubleToInt, - EOpConvInt64ToInt, - EOpConvUint64ToInt, - EOpConvIntToUint, - EOpConvFloatToUint, EOpConvBoolToUint, - EOpConvDoubleToUint, - EOpConvInt64ToUint, - EOpConvUint64ToUint, - EOpConvIntToDouble, - EOpConvUintToDouble, - EOpConvFloatToDouble, - EOpConvBoolToDouble, - EOpConvInt64ToDouble, - EOpConvUint64ToDouble, EOpConvBoolToInt64, - EOpConvIntToInt64, - EOpConvUintToInt64, - EOpConvFloatToInt64, - EOpConvDoubleToInt64, - EOpConvUint64ToInt64, 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, - EOpConvFloatToUint64, - EOpConvDoubleToUint64, + + // 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, + // // binary operations // @@ -160,6 +309,7 @@ enum TOperator { EOpVectorSwizzle, EOpMethod, + EOpScoping, // // Built-in functions mapped to operators @@ -220,6 +370,10 @@ enum TOperator { EOpDoubleBitsToUint64, EOpInt64BitsToDouble, EOpUint64BitsToDouble, + EOpFloat16BitsToInt16, + EOpFloat16BitsToUint16, + EOpInt16BitsToFloat16, + EOpUint16BitsToFloat16, EOpPackSnorm2x16, EOpUnpackSnorm2x16, EOpPackUnorm2x16, @@ -236,6 +390,22 @@ enum TOperator { EOpUnpackInt2x32, EOpPackUint2x32, EOpUnpackUint2x32, + EOpPackFloat2x16, + EOpUnpackFloat2x16, + EOpPackInt2x16, + EOpUnpackInt2x16, + EOpPackUint2x16, + EOpUnpackUint2x16, + EOpPackInt4x16, + EOpUnpackInt4x16, + EOpPackUint4x16, + EOpUnpackUint4x16, + EOpPack16, + EOpPack32, + EOpPack64, + EOpUnpack32, + EOpUnpack16, + EOpUnpack8, EOpLength, EOpDistance, @@ -246,6 +416,12 @@ enum TOperator { EOpReflect, EOpRefract, +#ifdef AMD_EXTENSIONS + EOpMin3, + EOpMax3, + EOpMid3, +#endif + EOpDPdx, // Fragment only EOpDPdy, // Fragment only EOpFwidth, // Fragment only @@ -260,6 +436,10 @@ enum TOperator { EOpInterpolateAtSample, // Fragment only EOpInterpolateAtOffset, // Fragment only +#ifdef AMD_EXTENSIONS + EOpInterpolateAtVertex, +#endif + EOpMatrixTimesMatrix, EOpOuterProduct, EOpDeterminant, @@ -291,6 +471,119 @@ enum TOperator { EOpAllInvocations, EOpAllInvocationsEqual, + EOpSubgroupGuardStart, + EOpSubgroupBarrier, + EOpSubgroupMemoryBarrier, + EOpSubgroupMemoryBarrierBuffer, + EOpSubgroupMemoryBarrierImage, + EOpSubgroupMemoryBarrierShared, // compute only + EOpSubgroupElect, + EOpSubgroupAll, + EOpSubgroupAny, + EOpSubgroupAllEqual, + EOpSubgroupBroadcast, + EOpSubgroupBroadcastFirst, + EOpSubgroupBallot, + EOpSubgroupInverseBallot, + EOpSubgroupBallotBitExtract, + EOpSubgroupBallotBitCount, + EOpSubgroupBallotInclusiveBitCount, + EOpSubgroupBallotExclusiveBitCount, + EOpSubgroupBallotFindLSB, + EOpSubgroupBallotFindMSB, + EOpSubgroupShuffle, + EOpSubgroupShuffleXor, + EOpSubgroupShuffleUp, + EOpSubgroupShuffleDown, + EOpSubgroupAdd, + EOpSubgroupMul, + EOpSubgroupMin, + EOpSubgroupMax, + EOpSubgroupAnd, + EOpSubgroupOr, + EOpSubgroupXor, + EOpSubgroupInclusiveAdd, + EOpSubgroupInclusiveMul, + EOpSubgroupInclusiveMin, + EOpSubgroupInclusiveMax, + EOpSubgroupInclusiveAnd, + EOpSubgroupInclusiveOr, + EOpSubgroupInclusiveXor, + EOpSubgroupExclusiveAdd, + EOpSubgroupExclusiveMul, + EOpSubgroupExclusiveMin, + EOpSubgroupExclusiveMax, + EOpSubgroupExclusiveAnd, + EOpSubgroupExclusiveOr, + EOpSubgroupExclusiveXor, + EOpSubgroupClusteredAdd, + EOpSubgroupClusteredMul, + EOpSubgroupClusteredMin, + EOpSubgroupClusteredMax, + EOpSubgroupClusteredAnd, + EOpSubgroupClusteredOr, + EOpSubgroupClusteredXor, + EOpSubgroupQuadBroadcast, + EOpSubgroupQuadSwapHorizontal, + EOpSubgroupQuadSwapVertical, + EOpSubgroupQuadSwapDiagonal, + +#ifdef NV_EXTENSIONS + EOpSubgroupPartition, + EOpSubgroupPartitionedAdd, + EOpSubgroupPartitionedMul, + EOpSubgroupPartitionedMin, + EOpSubgroupPartitionedMax, + EOpSubgroupPartitionedAnd, + EOpSubgroupPartitionedOr, + EOpSubgroupPartitionedXor, + EOpSubgroupPartitionedInclusiveAdd, + EOpSubgroupPartitionedInclusiveMul, + EOpSubgroupPartitionedInclusiveMin, + EOpSubgroupPartitionedInclusiveMax, + EOpSubgroupPartitionedInclusiveAnd, + EOpSubgroupPartitionedInclusiveOr, + EOpSubgroupPartitionedInclusiveXor, + EOpSubgroupPartitionedExclusiveAdd, + EOpSubgroupPartitionedExclusiveMul, + EOpSubgroupPartitionedExclusiveMin, + EOpSubgroupPartitionedExclusiveMax, + EOpSubgroupPartitionedExclusiveAnd, + EOpSubgroupPartitionedExclusiveOr, + EOpSubgroupPartitionedExclusiveXor, +#endif + + EOpSubgroupGuardStop, + +#ifdef AMD_EXTENSIONS + EOpMinInvocations, + EOpMaxInvocations, + EOpAddInvocations, + EOpMinInvocationsNonUniform, + EOpMaxInvocationsNonUniform, + EOpAddInvocationsNonUniform, + EOpMinInvocationsInclusiveScan, + EOpMaxInvocationsInclusiveScan, + EOpAddInvocationsInclusiveScan, + EOpMinInvocationsInclusiveScanNonUniform, + EOpMaxInvocationsInclusiveScanNonUniform, + EOpAddInvocationsInclusiveScanNonUniform, + EOpMinInvocationsExclusiveScan, + EOpMaxInvocationsExclusiveScan, + EOpAddInvocationsExclusiveScan, + EOpMinInvocationsExclusiveScanNonUniform, + EOpMaxInvocationsExclusiveScanNonUniform, + EOpAddInvocationsExclusiveScanNonUniform, + EOpSwizzleInvocations, + EOpSwizzleInvocationsMasked, + EOpWriteInvocation, + EOpMbcnt, + + EOpCubeFaceIndex, + EOpCubeFaceCoord, + EOpTime, +#endif + EOpAtomicAdd, EOpAtomicMin, EOpAtomicMax, @@ -300,9 +593,18 @@ enum TOperator { EOpAtomicExchange, EOpAtomicCompSwap, - EOpAtomicCounterIncrement, - EOpAtomicCounterDecrement, + EOpAtomicCounterIncrement, // results in pre-increment value + EOpAtomicCounterDecrement, // results in post-decrement value EOpAtomicCounter, + EOpAtomicCounterAdd, + EOpAtomicCounterSubtract, + EOpAtomicCounterMin, + EOpAtomicCounterMax, + EOpAtomicCounterAnd, + EOpAtomicCounterOr, + EOpAtomicCounterXor, + EOpAtomicCounterExchange, + EOpAtomicCounterCompSwap, EOpAny, EOpAll, @@ -325,6 +627,10 @@ enum TOperator { EOpConstructGuardStart, EOpConstructInt, // these first scalar forms also identify what implicit conversion is needed EOpConstructUint, + EOpConstructInt8, + EOpConstructUint8, + EOpConstructInt16, + EOpConstructUint16, EOpConstructInt64, EOpConstructUint64, EOpConstructBool, @@ -339,6 +645,18 @@ enum TOperator { EOpConstructBVec2, EOpConstructBVec3, EOpConstructBVec4, + EOpConstructI8Vec2, + EOpConstructI8Vec3, + EOpConstructI8Vec4, + EOpConstructU8Vec2, + EOpConstructU8Vec3, + EOpConstructU8Vec4, + EOpConstructI16Vec2, + EOpConstructI16Vec3, + EOpConstructI16Vec4, + EOpConstructU16Vec2, + EOpConstructU16Vec3, + EOpConstructU16Vec4, EOpConstructIVec2, EOpConstructIVec3, EOpConstructIVec4, @@ -369,14 +687,55 @@ enum TOperator { EOpConstructDMat4x2, EOpConstructDMat4x3, EOpConstructDMat4x4, + EOpConstructIMat2x2, + EOpConstructIMat2x3, + EOpConstructIMat2x4, + EOpConstructIMat3x2, + EOpConstructIMat3x3, + EOpConstructIMat3x4, + EOpConstructIMat4x2, + EOpConstructIMat4x3, + EOpConstructIMat4x4, + EOpConstructUMat2x2, + EOpConstructUMat2x3, + EOpConstructUMat2x4, + EOpConstructUMat3x2, + EOpConstructUMat3x3, + EOpConstructUMat3x4, + EOpConstructUMat4x2, + EOpConstructUMat4x3, + EOpConstructUMat4x4, + EOpConstructBMat2x2, + EOpConstructBMat2x3, + EOpConstructBMat2x4, + EOpConstructBMat3x2, + EOpConstructBMat3x3, + EOpConstructBMat3x4, + EOpConstructBMat4x2, + EOpConstructBMat4x3, + EOpConstructBMat4x4, + EOpConstructFloat16, + EOpConstructF16Vec2, + EOpConstructF16Vec3, + EOpConstructF16Vec4, + EOpConstructF16Mat2x2, + EOpConstructF16Mat2x3, + EOpConstructF16Mat2x4, + EOpConstructF16Mat3x2, + EOpConstructF16Mat3x3, + EOpConstructF16Mat3x4, + EOpConstructF16Mat4x2, + EOpConstructF16Mat4x3, + EOpConstructF16Mat4x4, EOpConstructStruct, EOpConstructTextureSampler, + EOpConstructNonuniform, // expected to be transformed away, not present in final AST EOpConstructGuardEnd, // // moves // - + EOpAssign, EOpAddAssign, EOpSubAssign, @@ -397,7 +756,11 @@ enum TOperator { // Array operators // - EOpArrayLength, // "Array" distinguishes from length(v) built-in function, but it applies to vectors and matrices as well. + // Can apply to arrays, vectors, or matrices. + // Can be decomposed to a constant at compile time, but this does not always happen, + // due to link-time effects. So, consumer can expect either a link-time sized or + // run-time sized array. + EOpArrayLength, // // Image operations @@ -409,6 +772,10 @@ enum TOperator { EOpImageQuerySamples, EOpImageLoad, EOpImageStore, +#ifdef AMD_EXTENSIONS + EOpImageLoadLod, + EOpImageStoreLod, +#endif EOpImageAtomicAdd, EOpImageAtomicMin, EOpImageAtomicMax, @@ -421,6 +788,9 @@ enum TOperator { EOpSubpassLoad, EOpSubpassLoadMS, EOpSparseImageLoad, +#ifdef AMD_EXTENSIONS + EOpSparseImageLoadLod, +#endif EOpImageGuardEnd, @@ -434,6 +804,9 @@ enum TOperator { EOpTextureQueryLod, EOpTextureQueryLevels, EOpTextureQuerySamples, + + EOpSamplingGuardBegin, + EOpTexture, EOpTextureProj, EOpTextureLod, @@ -455,6 +828,13 @@ enum TOperator { EOpTextureOffsetClamp, EOpTextureGradClamp, EOpTextureGradOffsetClamp, +#ifdef AMD_EXTENSIONS + EOpTextureGatherLod, + EOpTextureGatherLodOffset, + EOpTextureGatherLodOffsets, + EOpFragmentMaskFetch, + EOpFragmentFetch, +#endif EOpSparseTextureGuardBegin, @@ -474,9 +854,14 @@ enum TOperator { EOpSparseTextureOffsetClamp, EOpSparseTextureGradClamp, EOpSparseTextureGradOffsetClamp, +#ifdef AMD_EXTENSIONS + EOpSparseTextureGatherLod, + EOpSparseTextureGatherLodOffset, + EOpSparseTextureGatherLodOffsets, +#endif EOpSparseTextureGuardEnd, - + EOpSamplingGuardEnd, EOpTextureGuardEnd, // @@ -516,7 +901,8 @@ enum TOperator { EOpInterlockedOr, // ... EOpInterlockedXor, // ... EOpAllMemoryBarrierWithGroupSync, // memory barriers without non-hlsl AST equivalents - EOpGroupMemoryBarrierWithGroupSync, // ... + EOpDeviceMemoryBarrier, // ... + EOpDeviceMemoryBarrierWithGroupSync, // ... EOpWorkgroupMemoryBarrier, // ... EOpWorkgroupMemoryBarrierWithGroupSync, // ... EOpEvaluateAttributeSnapped, // InterpolateAtOffset with int position on 16x16 grid @@ -525,6 +911,7 @@ enum TOperator { EOpLit, // HLSL lighting coefficient vector EOpTextureBias, // HLSL texture bias: will be lowered to EOpTexture EOpAsDouble, // slightly different from EOpUint64BitsToDouble + EOpD3DCOLORtoUBYTE4, // convert and swizzle 4-component color to UBYTE4 range EOpMethodSample, // Texture object methods. These are translated to existing EOpMethodSampleBias, // AST methods, and exist to represent HLSL semantics until that @@ -538,6 +925,43 @@ enum TOperator { EOpMethodGather, // ... EOpMethodCalculateLevelOfDetail, // ... EOpMethodCalculateLevelOfDetailUnclamped, // ... + + // Load already defined above for textures + EOpMethodLoad2, // Structure buffer object methods. These are translated to existing + EOpMethodLoad3, // AST methods, and exist to represent HLSL semantics until that + EOpMethodLoad4, // translation is performed. See HlslParseContext::decomposeSampleMethods(). + EOpMethodStore, // ... + EOpMethodStore2, // ... + EOpMethodStore3, // ... + EOpMethodStore4, // ... + EOpMethodIncrementCounter, // ... + EOpMethodDecrementCounter, // ... + // EOpMethodAppend is defined for geo shaders below + EOpMethodConsume, + + // SM5 texture methods + EOpMethodGatherRed, // These are covered under the above EOpMethodSample comment about + EOpMethodGatherGreen, // translation to existing AST opcodes. They exist temporarily + EOpMethodGatherBlue, // because HLSL arguments are slightly different. + EOpMethodGatherAlpha, // ... + EOpMethodGatherCmp, // ... + EOpMethodGatherCmpRed, // ... + EOpMethodGatherCmpGreen, // ... + EOpMethodGatherCmpBlue, // ... + EOpMethodGatherCmpAlpha, // ... + + // geometry methods + EOpMethodAppend, // Geometry shader methods + EOpMethodRestartStrip, // ... + + // matrix + EOpMatrixSwizzle, // select multiple matrix components (non-column) + + // SM6 wave ops + EOpWaveGetLaneCount, // Will decompose to gl_SubgroupSize. + EOpWaveGetLaneIndex, // Will decompose to gl_SubgroupInvocationID. + EOpWaveActiveCountBits, // Will decompose to subgroupBallotBitCount(subgroupBallot()). + EOpWavePrefixCountBits, // Will decompose to subgroupBallotInclusiveBitCount(subgroupBallot()). }; class TIntermTraverser; @@ -552,6 +976,7 @@ class TIntermBranch; class TIntermTyped; class TIntermMethod; class TIntermSymbol; +class TIntermLoop; } // end namespace glslang @@ -579,6 +1004,7 @@ public: virtual glslang::TIntermMethod* getAsMethodNode() { return 0; } virtual glslang::TIntermSymbol* getAsSymbolNode() { return 0; } virtual glslang::TIntermBranch* getAsBranchNode() { return 0; } + virtual glslang::TIntermLoop* getAsLoopNode() { return 0; } virtual const glslang::TIntermTyped* getAsTyped() const { return 0; } virtual const glslang::TIntermOperator* getAsOperator() const { return 0; } @@ -591,6 +1017,7 @@ public: virtual const glslang::TIntermMethod* getAsMethodNode() const { return 0; } virtual const glslang::TIntermSymbol* getAsSymbolNode() const { return 0; } virtual const glslang::TIntermBranch* getAsBranchNode() const { return 0; } + virtual const glslang::TIntermLoop* getAsLoopNode() const { return 0; } virtual ~TIntermNode() { } protected: @@ -621,7 +1048,7 @@ public: virtual void setType(const TType& t) { type.shallowCopy(t); } virtual const TType& getType() const { return type; } virtual TType& getWritableType() { return type; } - + virtual TBasicType getBasicType() const { return type.getBasicType(); } virtual TQualifier& getQualifier() { return type.getQualifier(); } virtual const TQualifier& getQualifier() const { return type.getQualifier(); } @@ -634,6 +1061,8 @@ public: virtual bool isVector() const { return type.isVector(); } virtual bool isScalar() const { return type.isScalar(); } virtual bool isStruct() const { return type.isStruct(); } + virtual bool isFloatingDomain() const { return type.isFloatingDomain(); } + virtual bool isIntegerDomain() const { return type.isIntegerDomain(); } TString getCompleteString() const { return type.getCompleteString(); } protected: @@ -646,21 +1075,41 @@ protected: // class TIntermLoop : public TIntermNode { public: - TIntermLoop(TIntermNode* aBody, TIntermTyped* aTest, TIntermTyped* aTerminal, bool testFirst) : + TIntermLoop(TIntermNode* aBody, TIntermTyped* aTest, TIntermTyped* aTerminal, bool testFirst) : body(aBody), test(aTest), terminal(aTerminal), - first(testFirst) { } + first(testFirst), + unroll(false), + dontUnroll(false), + dependency(0) + { } + + virtual TIntermLoop* getAsLoopNode() { return this; } + virtual const TIntermLoop* getAsLoopNode() const { return this; } virtual void traverse(TIntermTraverser*); TIntermNode* getBody() const { return body; } TIntermTyped* getTest() const { return test; } TIntermTyped* getTerminal() const { return terminal; } bool testFirst() const { return first; } + + void setUnroll() { unroll = true; } + void setDontUnroll() { dontUnroll = true; } + bool getUnroll() const { return unroll; } + bool getDontUnroll() const { return dontUnroll; } + + static const unsigned int dependencyInfinite = 0xFFFFFFFF; + void setLoopDependency(int d) { dependency = d; } + int getLoopDependency() const { return dependency; } + protected: TIntermNode* body; // code to loop over TIntermTyped* 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 + bool dontUnroll; // true if request to not unroll + unsigned int dependency; // loop dependency hint; 0 means not set or unknown }; // @@ -708,7 +1157,11 @@ public: // per process threadPoolAllocator, then it causes increased memory usage per compile // it is essential to use "symbol = sym" to assign to symbol TIntermSymbol(int i, const TString& n, const TType& t) - : TIntermTyped(t), id(i), constSubtree(nullptr) + : TIntermTyped(t), id(i), +#ifdef ENABLE_HLSL + flattenSubset(-1), +#endif + constSubtree(nullptr) { name = n; } virtual int getId() const { return id; } virtual const TString& getName() const { return name; } @@ -719,9 +1172,20 @@ public: const TConstUnionArray& getConstArray() const { return constArray; } void setConstSubtree(TIntermTyped* subtree) { constSubtree = subtree; } TIntermTyped* getConstSubtree() const { return constSubtree; } +#ifdef ENABLE_HLSL + void setFlattenSubset(int subset) { flattenSubset = subset; } + int getFlattenSubset() const { return flattenSubset; } // -1 means full object +#endif + + // 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(int newId) { id = newId; } protected: int id; // the unique id of the symbol this node represents +#ifdef ENABLE_HLSL + int flattenSubset; // how deeply the flattened object rooted at id has been dereferenced +#endif TString name; // the name of the symbol this node represents TConstUnionArray constArray; // if the symbol is a front-end compile-time constant, this is its value TIntermTyped* constSubtree; @@ -759,6 +1223,9 @@ struct TCrackedTextureOp { bool grad; bool subpass; bool lodClamp; +#ifdef AMD_EXTENSIONS + bool fragMask; +#endif }; // @@ -769,14 +1236,30 @@ public: virtual TIntermOperator* getAsOperator() { return this; } virtual const TIntermOperator* getAsOperator() const { return this; } TOperator getOp() const { return op; } - virtual bool promote() { return true; } + void setOp(TOperator newOp) { op = newOp; } bool modifiesState() const; bool isConstructor() const; - bool isTexture() const { return op > EOpTextureGuardBegin && op < EOpTextureGuardEnd; } - bool isImage() const { return op > EOpImageGuardBegin && op < EOpImageGuardEnd; } + bool isTexture() const { return op > EOpTextureGuardBegin && op < EOpTextureGuardEnd; } + bool isSampling() const { return op > EOpSamplingGuardBegin && op < EOpSamplingGuardEnd; } + bool isImage() const { return op > EOpImageGuardBegin && op < EOpImageGuardEnd; } bool isSparseTexture() const { return op > EOpSparseTextureGuardBegin && op < EOpSparseTextureGuardEnd; } bool isSparseImage() const { return op == EOpSparseImageLoad; } + void setOperationPrecision(TPrecisionQualifier p) { operationPrecision = p; } + TPrecisionQualifier getOperationPrecision() const { return operationPrecision != EpqNone ? + operationPrecision : + type.getQualifier().precision; } + TString getCompleteString() const + { + TString cs = type.getCompleteString(); + if (getOperationPrecision() != type.getQualifier().precision) { + cs += ", operation at "; + cs += GetPrecisionQualifierString(getOperationPrecision()); + } + + return cs; + } + // Crack the op into the individual dimensions of texturing operation. void crackTexture(TSampler sampler, TCrackedTextureOp& cracked) const { @@ -790,6 +1273,9 @@ public: cracked.grad = false; cracked.subpass = false; cracked.lodClamp = false; +#ifdef AMD_EXTENSIONS + cracked.fragMask = false; +#endif switch (op) { case EOpImageQuerySize: @@ -898,6 +1384,38 @@ public: cracked.gather = true; cracked.offsets = true; break; +#ifdef AMD_EXTENSIONS + case EOpTextureGatherLod: + case EOpSparseTextureGatherLod: + cracked.gather = true; + cracked.lod = true; + break; + case EOpTextureGatherLodOffset: + case EOpSparseTextureGatherLodOffset: + cracked.gather = true; + cracked.offset = true; + cracked.lod = true; + break; + case EOpTextureGatherLodOffsets: + case EOpSparseTextureGatherLodOffsets: + cracked.gather = true; + cracked.offsets = true; + cracked.lod = true; + break; + case EOpImageLoadLod: + case EOpImageStoreLod: + case EOpSparseImageLoadLod: + cracked.lod = true; + break; + case EOpFragmentMaskFetch: + cracked.subpass = sampler.dim == EsdSubpass; + cracked.fragMask = true; + break; + case EOpFragmentFetch: + cracked.subpass = sampler.dim == EsdSubpass; + cracked.fragMask = true; + break; +#endif case EOpSubpassLoad: case EOpSubpassLoadMS: cracked.subpass = true; @@ -908,9 +1426,15 @@ public: } protected: - TIntermOperator(TOperator o) : TIntermTyped(EbtFloat), op(o) {} - TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {} + TIntermOperator(TOperator o) : TIntermTyped(EbtFloat), op(o), operationPrecision(EpqNone) {} + TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o), operationPrecision(EpqNone) {} TOperator op; + // The result precision is in the inherited TType, and is usually meant to be both + // the operation precision and the result precision. However, some more complex things, + // like built-in function calls, distinguish between the two, in which case non-EqpNone + // 'operationPrecision' overrides the result precision as far as operation precision + // is concerned. + TPrecisionQualifier operationPrecision; }; // @@ -926,7 +1450,6 @@ public: virtual TIntermTyped* getRight() const { return right; } virtual TIntermBinary* getAsBinaryNode() { return this; } virtual const TIntermBinary* getAsBinaryNode() const { return this; } - virtual bool promote(); virtual void updatePrecision(); protected: TIntermTyped* left; @@ -946,21 +1469,20 @@ public: virtual const TIntermTyped* getOperand() const { return operand; } virtual TIntermUnary* getAsUnaryNode() { return this; } virtual const TIntermUnary* getAsUnaryNode() const { return this; } - virtual bool promote(); virtual void updatePrecision(); protected: TIntermTyped* operand; }; typedef TVector TIntermSequence; -typedef TVector TQualifierList; +typedef TVector TQualifierList; // // Nodes that operate on an arbitrary sized set of children. // class TIntermAggregate : public TIntermOperator { public: - TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), pragmaTable(0) { } - TIntermAggregate(TOperator o) : TIntermOperator(o), pragmaTable(0) { } + TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), pragmaTable(nullptr) { } + TIntermAggregate(TOperator o) : TIntermOperator(o), pragmaTable(nullptr) { } ~TIntermAggregate() { delete pragmaTable; } virtual TIntermAggregate* getAsAggregate() { return this; } virtual const TIntermAggregate* getAsAggregate() const { return this; } @@ -978,7 +1500,7 @@ public: void setDebug(bool d) { debug = d; } bool getOptimize() const { return optimize; } bool getDebug() const { return debug; } - void addToPragmaTable(const TPragmaTable& pTable); + void setPragmaTable(const TPragmaTable& pTable); const TPragmaTable& getPragmaTable() const { return *pragmaTable; } protected: TIntermAggregate(const TIntermAggregate&); // disallow copy constructor @@ -998,19 +1520,35 @@ protected: class TIntermSelection : public TIntermTyped { public: TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) : - TIntermTyped(EbtVoid), condition(cond), trueBlock(trueB), falseBlock(falseB) {} + TIntermTyped(EbtVoid), condition(cond), trueBlock(trueB), falseBlock(falseB), + shortCircuit(true), + flatten(false), dontFlatten(false) {} TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) : - TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {} + TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB), + shortCircuit(true), + flatten(false), dontFlatten(false) {} virtual void traverse(TIntermTraverser*); virtual TIntermTyped* getCondition() const { return condition; } virtual TIntermNode* getTrueBlock() const { return trueBlock; } virtual TIntermNode* getFalseBlock() const { return falseBlock; } virtual TIntermSelection* getAsSelectionNode() { return this; } virtual const TIntermSelection* getAsSelectionNode() const { return this; } + + void setNoShortCircuit() { shortCircuit = false; } + bool getShortCircuit() const { return shortCircuit; } + + void setFlatten() { flatten = true; } + void setDontFlatten() { dontFlatten = true; } + bool getFlatten() const { return flatten; } + bool getDontFlatten() const { return dontFlatten; } + protected: TIntermTyped* condition; TIntermNode* trueBlock; TIntermNode* falseBlock; + bool shortCircuit; // normally all if-then-else and all GLSL ?: short-circuit, but HLSL ?: does not + bool flatten; // true if flatten requested + bool dontFlatten; // true if requested to not flatten }; // @@ -1021,15 +1559,24 @@ protected: // class TIntermSwitch : public TIntermNode { public: - TIntermSwitch(TIntermTyped* cond, TIntermAggregate* b) : condition(cond), body(b) { } + TIntermSwitch(TIntermTyped* cond, TIntermAggregate* b) : condition(cond), body(b), + flatten(false), dontFlatten(false) {} virtual void traverse(TIntermTraverser*); virtual TIntermNode* getCondition() const { return condition; } virtual TIntermAggregate* getBody() const { return body; } virtual TIntermSwitch* getAsSwitchNode() { return this; } virtual const TIntermSwitch* getAsSwitchNode() const { return this; } + + void setFlatten() { flatten = true; } + void setDontFlatten() { dontFlatten = true; } + bool getFlatten() const { return flatten; } + bool getDontFlatten() const { return dontFlatten; } + protected: TIntermTyped* condition; TIntermAggregate* body; + bool flatten; // true if flatten requested + bool dontFlatten; // true if requested to not flatten }; enum TVisit @@ -1040,7 +1587,7 @@ enum TVisit }; // -// For traversing the tree. User should derive from this, +// For traversing the tree. User should derive from this, // put their traversal specific data in it, and then pass // it to a Traverse method. // @@ -1052,10 +1599,10 @@ enum TVisit // the subtree). Similarly for inVisit for in-order visiting of nodes with // multiple children. // -// If you only want post-visits, explicitly turn off preVisit (and inVisit) +// If you only want post-visits, explicitly turn off preVisit (and inVisit) // and turn on postVisit. // -// In general, for the visit*() methods, return true from interior nodes +// In general, for the visit*() methods, return true from interior nodes // to have the traversal continue on to children. // // If you process children yourself, or don't want them processed, return false. diff --git a/Externals/glslang/glslang/Include/revision.h b/Externals/glslang/glslang/Include/revision.h index e338849d45..3d66a6679e 100644 --- a/Externals/glslang/glslang/Include/revision.h +++ b/Externals/glslang/glslang/Include/revision.h @@ -1,6 +1,3 @@ // This header is generated by the make-revision script. -// For the version, it uses the latest git tag followed by the number of commits. -// For the date, it uses the current date (when then script is run). -#define GLSLANG_REVISION "SPIRV99.947" -#define GLSLANG_DATE "15-Feb-2016" +#define GLSLANG_PATCH_LEVEL 2743 diff --git a/Externals/glslang/glslang/Include/revision.template b/Externals/glslang/glslang/Include/revision.template index 1dc3392b39..6c13630b27 100644 --- a/Externals/glslang/glslang/Include/revision.template +++ b/Externals/glslang/glslang/Include/revision.template @@ -1,4 +1,4 @@ -// The file revision.h should be updated to the latest version, somehow, on +// The file revision.h should be updated to the latest version, somehow, on // check-in, if glslang has changed. // // revision.template is the source for revision.h when using SubWCRev as the diff --git a/Externals/glslang/glslang/MachineIndependent/Constant.cpp b/Externals/glslang/glslang/MachineIndependent/Constant.cpp index 4adfd4704e..142492dc33 100644 --- a/Externals/glslang/glslang/MachineIndependent/Constant.cpp +++ b/Externals/glslang/glslang/MachineIndependent/Constant.cpp @@ -1,12 +1,13 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2012-2013 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2012-2013 LunarG, Inc. +// Copyright (C) 2017 ARM Limited. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,24 +21,25 @@ // 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. +// 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. // #include "localintermediate.h" #include #include #include +#include namespace { @@ -57,7 +59,7 @@ bool isNan(double x) u.d = x; int bitPatternL = u.i[0]; int bitPatternH = u.i[1]; - return (bitPatternH & 0x7ff80000) == 0x7ff80000 && + return (bitPatternH & 0x7ff80000) == 0x7ff80000 && ((bitPatternH & 0xFFFFF) != 0 || bitPatternL != 0); } @@ -68,7 +70,7 @@ bool isInf(double x) u.d = x; int bitPatternL = u.i[0]; int bitPatternH = u.i[1]; - return (bitPatternH & 0x7ff00000) == 0x7ff00000 && + return (bitPatternH & 0x7ff00000) == 0x7ff00000 && (bitPatternH & 0xFFFFF) == 0 && bitPatternL == 0; } @@ -131,7 +133,7 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* right TConstUnionArray smearedArray(newComps, rightNode->getConstArray()[0]); rightUnionArray = smearedArray; } else if (constComps > 1 && newComps == 1) { - // for a case like vec4 f = 1.2 + vec4(2,3,4,5); + // for a case like vec4 f = 1.2 + vec4(2,3,4,5); newComps = constComps; rightUnionArray = rightNode->getConstArray(); TConstUnionArray smearedArray(newComps, getConstArray()[0]); @@ -176,8 +178,40 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* right switch (getType().getBasicType()) { case EbtDouble: case EbtFloat: + case EbtFloat16: newConstArray[i].setDConst(leftUnionArray[i].getDConst() / rightUnionArray[i].getDConst()); break; + case EbtInt8: + if (rightUnionArray[i] == 0) + newConstArray[i].setI8Const(0x7F); + else if (rightUnionArray[i].getI8Const() == -1 && leftUnionArray[i].getI8Const() == (signed char)0x80) + newConstArray[i].setI8Const((signed char)0x80); + else + newConstArray[i].setI8Const(leftUnionArray[i].getI8Const() / rightUnionArray[i].getI8Const()); + break; + + case EbtUint8: + if (rightUnionArray[i] == 0) { + newConstArray[i].setU8Const(0xFF); + } else + newConstArray[i].setU8Const(leftUnionArray[i].getU8Const() / rightUnionArray[i].getU8Const()); + break; + + case EbtInt16: + if (rightUnionArray[i] == 0) + newConstArray[i].setI16Const(0x7FFF); + else if (rightUnionArray[i].getI16Const() == -1 && leftUnionArray[i].getI16Const() == (signed short)0x8000) + newConstArray[i].setI16Const(short(0x8000)); + else + newConstArray[i].setI16Const(leftUnionArray[i].getI16Const() / rightUnionArray[i].getI16Const()); + break; + + case EbtUint16: + if (rightUnionArray[i] == 0) { + newConstArray[i].setU16Const(0xFFFF); + } else + newConstArray[i].setU16Const(leftUnionArray[i].getU16Const() / rightUnionArray[i].getU16Const()); + break; case EbtInt: if (rightUnionArray[i] == 0) @@ -190,7 +224,7 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* right case EbtUint: if (rightUnionArray[i] == 0) { - newConstArray[i].setUConst(0xFFFFFFFF); + newConstArray[i].setUConst(0xFFFFFFFFu); } else newConstArray[i].setUConst(leftUnionArray[i].getUConst() / rightUnionArray[i].getUConst()); break; @@ -243,8 +277,31 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* right for (int i = 0; i < newComps; i++) { if (rightUnionArray[i] == 0) newConstArray[i] = leftUnionArray[i]; - else - newConstArray[i] = leftUnionArray[i] % rightUnionArray[i]; + else { + switch (getType().getBasicType()) { + case EbtInt: + if (rightUnionArray[i].getIConst() == -1 && leftUnionArray[i].getIConst() == INT_MIN) { + newConstArray[i].setIConst(0); + break; + } else goto modulo_default; + + case EbtInt64: + if (rightUnionArray[i].getI64Const() == -1 && leftUnionArray[i].getI64Const() == LLONG_MIN) { + newConstArray[i].setI64Const(0); + break; + } else goto modulo_default; +#ifdef AMD_EXTENSIONS + case EbtInt16: + if (rightUnionArray[i].getIConst() == -1 && leftUnionArray[i].getIConst() == SHRT_MIN) { + newConstArray[i].setIConst(0); + break; + } else goto modulo_default; +#endif + default: + modulo_default: + newConstArray[i] = leftUnionArray[i] % rightUnionArray[i]; + } + } } break; @@ -367,6 +424,12 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) resultSize = 2; break; + case EOpPack16: + case EOpPack32: + case EOpPack64: + case EOpUnpack32: + case EOpUnpack16: + case EOpUnpack8: case EOpNormalize: componentWise = false; resultSize = objectSize; @@ -425,6 +488,12 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) case EOpPackSnorm2x16: case EOpPackUnorm2x16: case EOpPackHalf2x16: + case EOpPack16: + case EOpPack32: + case EOpPack64: + case EOpUnpack32: + case EOpUnpack16: + case EOpUnpack8: case EOpUnpackSnorm2x16: case EOpUnpackUnorm2x16: @@ -450,11 +519,16 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) case EOpNegative: switch (getType().getBasicType()) { case EbtDouble: + case EbtFloat16: case EbtFloat: newConstArray[i].setDConst(-unionArray[i].getDConst()); break; + case EbtInt8: newConstArray[i].setI8Const(-unionArray[i].getI8Const()); break; + case EbtUint8: newConstArray[i].setU8Const(static_cast(-static_cast(unionArray[i].getU8Const()))); break; + case EbtInt16: newConstArray[i].setI16Const(-unionArray[i].getI16Const()); break; + case EbtUint16:newConstArray[i].setU16Const(static_cast(-static_cast(unionArray[i].getU16Const()))); break; case EbtInt: newConstArray[i].setIConst(-unionArray[i].getIConst()); break; case EbtUint: newConstArray[i].setUConst(static_cast(-static_cast(unionArray[i].getUConst()))); break; case EbtInt64: newConstArray[i].setI64Const(-unionArray[i].getI64Const()); break; - case EbtUint64: newConstArray[i].setU64Const(static_cast(-static_cast(unionArray[i].getU64Const()))); break; + case EbtUint64: newConstArray[i].setU64Const(static_cast(-static_cast(unionArray[i].getU64Const()))); break; default: return 0; } @@ -604,7 +678,12 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) case EOpUintBitsToFloat: case EOpDoubleBitsToInt64: case EOpDoubleBitsToUint64: - + case EOpInt64BitsToDouble: + case EOpUint64BitsToDouble: + case EOpFloat16BitsToInt16: + case EOpFloat16BitsToUint16: + case EOpInt16BitsToFloat16: + case EOpUint16BitsToFloat16: default: return 0; } @@ -620,9 +699,12 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) // // Do constant folding for an aggregate node that has all its children // as constants and an operator that requires constant folding. -// +// TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode) { + if (aggrNode == nullptr) + return aggrNode; + if (! areAllChildConst(aggrNode)) return aggrNode; @@ -685,14 +767,6 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode) for (unsigned int arg = 0; arg < children.size(); ++arg) childConstUnions.push_back(children[arg]->getAsConstantUnion()->getConstArray()); - // Second, do the actual folding - - bool isFloatingPoint = children[0]->getAsTyped()->getBasicType() == EbtFloat || - children[0]->getAsTyped()->getBasicType() == EbtDouble; - bool isSigned = children[0]->getAsTyped()->getBasicType() == EbtInt || - children[0]->getAsTyped()->getBasicType() == EbtInt64; - bool isInt64 = children[0]->getAsTyped()->getBasicType() == EbtInt64 || - children[0]->getAsTyped()->getBasicType() == EbtUint64; if (componentwise) { for (int comp = 0; comp < objectSize; comp++) { @@ -713,53 +787,114 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode) newConstArray[comp].setDConst(pow(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst())); break; case EOpMin: - if (isFloatingPoint) + switch(children[0]->getAsTyped()->getBasicType()) { + case EbtFloat16: + case EbtFloat: + case EbtDouble: newConstArray[comp].setDConst(std::min(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst())); - else if (isSigned) { - if (isInt64) - newConstArray[comp].setI64Const(std::min(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const())); - else - newConstArray[comp].setIConst(std::min(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst())); - } else { - if (isInt64) - newConstArray[comp].setU64Const(std::min(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const())); - else - newConstArray[comp].setUConst(std::min(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst())); + break; + case EbtInt8: + newConstArray[comp].setI8Const(std::min(childConstUnions[0][arg0comp].getI8Const(), childConstUnions[1][arg1comp].getI8Const())); + break; + case EbtUint8: + newConstArray[comp].setU8Const(std::min(childConstUnions[0][arg0comp].getU8Const(), childConstUnions[1][arg1comp].getU8Const())); + break; + case EbtInt16: + newConstArray[comp].setI16Const(std::min(childConstUnions[0][arg0comp].getI16Const(), childConstUnions[1][arg1comp].getI16Const())); + break; + case EbtUint16: + newConstArray[comp].setU16Const(std::min(childConstUnions[0][arg0comp].getU16Const(), childConstUnions[1][arg1comp].getU16Const())); + break; + case EbtInt: + newConstArray[comp].setIConst(std::min(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst())); + break; + case EbtUint: + newConstArray[comp].setUConst(std::min(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst())); + break; + case EbtInt64: + newConstArray[comp].setI64Const(std::min(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const())); + break; + case EbtUint64: + newConstArray[comp].setU64Const(std::min(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const())); + break; + default: assert(false && "Default missing"); } break; case EOpMax: - if (isFloatingPoint) + switch(children[0]->getAsTyped()->getBasicType()) { + case EbtFloat16: + case EbtFloat: + case EbtDouble: newConstArray[comp].setDConst(std::max(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst())); - else if (isSigned) { - if (isInt64) - newConstArray[comp].setI64Const(std::max(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const())); - else - newConstArray[comp].setIConst(std::max(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst())); - } else { - if (isInt64) - newConstArray[comp].setU64Const(std::max(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const())); - else - newConstArray[comp].setUConst(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst())); + break; + case EbtInt8: + newConstArray[comp].setI8Const(std::max(childConstUnions[0][arg0comp].getI8Const(), childConstUnions[1][arg1comp].getI8Const())); + break; + case EbtUint8: + newConstArray[comp].setU8Const(std::max(childConstUnions[0][arg0comp].getU8Const(), childConstUnions[1][arg1comp].getU8Const())); + break; + case EbtInt16: + newConstArray[comp].setI16Const(std::max(childConstUnions[0][arg0comp].getI16Const(), childConstUnions[1][arg1comp].getI16Const())); + break; + case EbtUint16: + newConstArray[comp].setU16Const(std::max(childConstUnions[0][arg0comp].getU16Const(), childConstUnions[1][arg1comp].getU16Const())); + break; + case EbtInt: + newConstArray[comp].setIConst(std::max(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst())); + break; + case EbtUint: + newConstArray[comp].setUConst(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst())); + break; + case EbtInt64: + newConstArray[comp].setI64Const(std::max(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const())); + break; + case EbtUint64: + newConstArray[comp].setU64Const(std::max(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const())); + break; + default: assert(false && "Default missing"); } break; case EOpClamp: - if (isFloatingPoint) + switch(children[0]->getAsTyped()->getBasicType()) { + case EbtFloat16: + case EbtFloat: + case EbtDouble: newConstArray[comp].setDConst(std::min(std::max(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()), childConstUnions[2][arg2comp].getDConst())); - else if (isSigned) { - if (isInt64) - newConstArray[comp].setI64Const(std::min(std::max(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const()), - childConstUnions[2][arg2comp].getI64Const())); - else - newConstArray[comp].setIConst(std::min(std::max(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()), + break; + case EbtInt8: + newConstArray[comp].setI8Const(std::min(std::max(childConstUnions[0][arg0comp].getI8Const(), childConstUnions[1][arg1comp].getI8Const()), + childConstUnions[2][arg2comp].getI8Const())); + break; + case EbtUint8: + newConstArray[comp].setU8Const(std::min(std::max(childConstUnions[0][arg0comp].getU8Const(), childConstUnions[1][arg1comp].getU8Const()), + childConstUnions[2][arg2comp].getU8Const())); + break; + case EbtInt16: + newConstArray[comp].setI16Const(std::min(std::max(childConstUnions[0][arg0comp].getI16Const(), childConstUnions[1][arg1comp].getI16Const()), + childConstUnions[2][arg2comp].getI16Const())); + break; + case EbtUint16: + newConstArray[comp].setU16Const(std::min(std::max(childConstUnions[0][arg0comp].getU16Const(), childConstUnions[1][arg1comp].getU16Const()), + childConstUnions[2][arg2comp].getU16Const())); + break; + case EbtInt: + newConstArray[comp].setIConst(std::min(std::max(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()), childConstUnions[2][arg2comp].getIConst())); - } else { - if (isInt64) - newConstArray[comp].setU64Const(std::min(std::max(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const()), - childConstUnions[2][arg2comp].getU64Const())); - else - newConstArray[comp].setUConst(std::min(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()), + break; + case EbtUint: + newConstArray[comp].setUConst(std::min(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()), childConstUnions[2][arg2comp].getUConst())); + break; + case EbtInt64: + newConstArray[comp].setI64Const(std::min(std::max(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const()), + childConstUnions[2][arg2comp].getI64Const())); + break; + case EbtUint64: + newConstArray[comp].setU64Const(std::min(std::max(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const()), + childConstUnions[2][arg2comp].getU64Const())); + break; + default: assert(false && "Default missing"); } break; case EOpLessThan: @@ -793,7 +928,7 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode) break; case EOpSmoothStep: { - double t = (childConstUnions[2][arg2comp].getDConst() - childConstUnions[0][arg0comp].getDConst()) / + double t = (childConstUnions[2][arg2comp].getDConst() - childConstUnions[0][arg0comp].getDConst()) / (childConstUnions[1][arg1comp].getDConst() - childConstUnions[0][arg0comp].getDConst()); if (t < 0.0) t = 0.0; @@ -832,7 +967,7 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode) newConstArray[2] = childConstUnions[0][0] * childConstUnions[1][1] - childConstUnions[0][1] * childConstUnions[1][0]; break; case EOpFaceForward: - // If dot(Nref, I) < 0 return N, otherwise return –N: Arguments are (N, I, Nref). + // If dot(Nref, I) < 0 return N, otherwise return -N: Arguments are (N, I, Nref). dot = childConstUnions[1].dot(childConstUnions[2]); for (int comp = 0; comp < numComps; ++comp) { if (dot < 0.0) @@ -959,23 +1094,23 @@ TIntermTyped* TIntermediate::foldDereference(TIntermTyped* node, int index, cons } // -// Make a constant vector node or constant scalar node, representing a given +// Make a constant vector node or constant scalar node, representing a given // constant vector and constant swizzle into it. // -TIntermTyped* TIntermediate::foldSwizzle(TIntermTyped* node, TVectorFields& fields, const TSourceLoc& loc) +TIntermTyped* TIntermediate::foldSwizzle(TIntermTyped* node, TSwizzleSelectors& selectors, const TSourceLoc& loc) { const TConstUnionArray& unionArray = node->getAsConstantUnion()->getConstArray(); - TConstUnionArray constArray(fields.num); + TConstUnionArray constArray(selectors.size()); - for (int i = 0; i < fields.num; i++) - constArray[i] = unionArray[fields.offsets[i]]; + for (int i = 0; i < selectors.size(); i++) + constArray[i] = unionArray[selectors[i]]; TIntermTyped* result = addConstantUnion(constArray, node->getType(), loc); if (result == 0) result = node; else - result->setType(TType(node->getBasicType(), EvqConst, fields.num)); + result->setType(TType(node->getBasicType(), EvqConst, selectors.size())); return result; } diff --git a/Externals/glslang/glslang/MachineIndependent/InfoSink.cpp b/Externals/glslang/glslang/MachineIndependent/InfoSink.cpp index 2e8888270b..d00c422566 100644 --- a/Externals/glslang/glslang/MachineIndependent/InfoSink.cpp +++ b/Externals/glslang/glslang/MachineIndependent/InfoSink.cpp @@ -1,10 +1,10 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -18,31 +18,35 @@ // 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. +// 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. // #include "../Include/InfoSink.h" -#include +#include namespace glslang { -void TInfoSinkBase::append(const char* s) +void TInfoSinkBase::append(const char* s) { if (outputStream & EString) { - checkMem(strlen(s)); - sink.append(s); + if (s == nullptr) + sink.append("(null)"); + else { + checkMem(strlen(s)); + sink.append(s); + } } //#ifdef _WIN32 @@ -54,11 +58,11 @@ void TInfoSinkBase::append(const char* s) fprintf(stdout, "%s", s); } -void TInfoSinkBase::append(int count, char c) -{ +void TInfoSinkBase::append(int count, char c) +{ if (outputStream & EString) { - checkMem(count); - sink.append(count, c); + checkMem(count); + sink.append(count, c); } //#ifdef _WIN32 @@ -74,11 +78,11 @@ void TInfoSinkBase::append(int count, char c) fprintf(stdout, "%c", c); } -void TInfoSinkBase::append(const TPersistString& t) -{ +void TInfoSinkBase::append(const TPersistString& t) +{ if (outputStream & EString) { - checkMem(t.size()); - sink.append(t); + checkMem(t.size()); + sink.append(t); } //#ifdef _WIN32 @@ -91,10 +95,10 @@ void TInfoSinkBase::append(const TPersistString& t) } void TInfoSinkBase::append(const TString& t) -{ +{ if (outputStream & EString) { - checkMem(t.size()); - sink.append(t.c_str()); + checkMem(t.size()); + sink.append(t.c_str()); } //#ifdef _WIN32 diff --git a/Externals/glslang/glslang/MachineIndependent/Initialize.cpp b/Externals/glslang/glslang/MachineIndependent/Initialize.cpp old mode 100644 new mode 100755 index 871e788470..a5ab093949 --- a/Externals/glslang/glslang/MachineIndependent/Initialize.cpp +++ b/Externals/glslang/glslang/MachineIndependent/Initialize.cpp @@ -1,13 +1,14 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2012-2016 LunarG, Inc. -//Copyright (C) 2015-2016 Google, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2012-2016 LunarG, Inc. +// Copyright (C) 2015-2017 Google, Inc. +// Copyright (C) 2017 ARM Limited. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -21,22 +22,22 @@ // 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. +// 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. // // -// Create strings that declare built-in definitions, add built-ins programmatically +// Create strings that declare built-in definitions, add built-ins programmatically // that cannot be expressed in the strings, and establish mappings between // built-in functions and operators. // @@ -83,10 +84,15 @@ TBuiltIns::TBuiltIns() // Set up textual representations for making all the permutations // of texturing/imaging functions. prefixes[EbtFloat] = ""; +#ifdef AMD_EXTENSIONS + prefixes[EbtFloat16] = "f16"; +#endif + prefixes[EbtInt8] = "i8"; + prefixes[EbtUint8] = "u8"; + prefixes[EbtInt16] = "i16"; + prefixes[EbtUint16] = "u16"; prefixes[EbtInt] = "i"; prefixes[EbtUint] = "u"; - prefixes[EbtInt64] = "i64"; - prefixes[EbtUint64] = "u64"; postfixes[2] = "2"; postfixes[3] = "3"; postfixes[4] = "4"; @@ -130,47 +136,47 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec2 radians(vec2 degrees);" "vec3 radians(vec3 degrees);" "vec4 radians(vec4 degrees);" - + "float degrees(float radians);" "vec2 degrees(vec2 radians);" "vec3 degrees(vec3 radians);" "vec4 degrees(vec4 radians);" - + "float sin(float angle);" "vec2 sin(vec2 angle);" "vec3 sin(vec3 angle);" "vec4 sin(vec4 angle);" - + "float cos(float angle);" "vec2 cos(vec2 angle);" "vec3 cos(vec3 angle);" "vec4 cos(vec4 angle);" - + "float tan(float angle);" "vec2 tan(vec2 angle);" "vec3 tan(vec3 angle);" "vec4 tan(vec4 angle);" - + "float asin(float x);" "vec2 asin(vec2 x);" "vec3 asin(vec3 x);" "vec4 asin(vec4 x);" - + "float acos(float x);" "vec2 acos(vec2 x);" "vec3 acos(vec3 x);" "vec4 acos(vec4 x);" - + "float atan(float y, float x);" "vec2 atan(vec2 y, vec2 x);" "vec3 atan(vec3 y, vec3 x);" "vec4 atan(vec4 y, vec4 x);" - + "float atan(float y_over_x);" "vec2 atan(vec2 y_over_x);" "vec3 atan(vec3 y_over_x);" "vec4 atan(vec4 y_over_x);" - + "\n"); if (version >= 130) { @@ -179,32 +185,32 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec2 sinh(vec2 angle);" "vec3 sinh(vec3 angle);" "vec4 sinh(vec4 angle);" - + "float cosh(float angle);" "vec2 cosh(vec2 angle);" "vec3 cosh(vec3 angle);" "vec4 cosh(vec4 angle);" - + "float tanh(float angle);" "vec2 tanh(vec2 angle);" "vec3 tanh(vec3 angle);" "vec4 tanh(vec4 angle);" - + "float asinh(float x);" "vec2 asinh(vec2 x);" "vec3 asinh(vec3 x);" "vec4 asinh(vec4 x);" - + "float acosh(float x);" "vec2 acosh(vec2 x);" "vec3 acosh(vec3 x);" "vec4 acosh(vec4 x);" - + "float atanh(float y_over_x);" "vec2 atanh(vec2 y_over_x);" "vec3 atanh(vec3 y_over_x);" "vec4 atanh(vec4 y_over_x);" - + "\n"); } @@ -216,37 +222,37 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec2 pow(vec2 x, vec2 y);" "vec3 pow(vec3 x, vec3 y);" "vec4 pow(vec4 x, vec4 y);" - + "float exp(float x);" "vec2 exp(vec2 x);" "vec3 exp(vec3 x);" "vec4 exp(vec4 x);" - + "float log(float x);" "vec2 log(vec2 x);" "vec3 log(vec3 x);" "vec4 log(vec4 x);" - + "float exp2(float x);" "vec2 exp2(vec2 x);" "vec3 exp2(vec3 x);" "vec4 exp2(vec4 x);" - + "float log2(float x);" "vec2 log2(vec2 x);" "vec3 log2(vec3 x);" "vec4 log2(vec4 x);" - + "float sqrt(float x);" "vec2 sqrt(vec2 x);" "vec3 sqrt(vec3 x);" "vec4 sqrt(vec4 x);" - + "float inversesqrt(float x);" "vec2 inversesqrt(vec2 x);" "vec3 inversesqrt(vec3 x);" "vec4 inversesqrt(vec4 x);" - + "\n"); // @@ -257,27 +263,27 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec2 abs(vec2 x);" "vec3 abs(vec3 x);" "vec4 abs(vec4 x);" - + "float sign(float x);" "vec2 sign(vec2 x);" "vec3 sign(vec3 x);" "vec4 sign(vec4 x);" - + "float floor(float x);" "vec2 floor(vec2 x);" "vec3 floor(vec3 x);" "vec4 floor(vec4 x);" - + "float ceil(float x);" "vec2 ceil(vec2 x);" "vec3 ceil(vec3 x);" "vec4 ceil(vec4 x);" - + "float fract(float x);" "vec2 fract(vec2 x);" "vec3 fract(vec3 x);" "vec4 fract(vec4 x);" - + "float mod(float x, float y);" "vec2 mod(vec2 x, float y);" "vec3 mod(vec3 x, float y);" @@ -285,7 +291,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec2 mod(vec2 x, vec2 y);" "vec3 mod(vec3 x, vec3 y);" "vec4 mod(vec4 x, vec4 y);" - + "float min(float x, float y);" "vec2 min(vec2 x, float y);" "vec3 min(vec3 x, float y);" @@ -293,7 +299,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec2 min(vec2 x, vec2 y);" "vec3 min(vec3 x, vec3 y);" "vec4 min(vec4 x, vec4 y);" - + "float max(float x, float y);" "vec2 max(vec2 x, float y);" "vec3 max(vec3 x, float y);" @@ -301,7 +307,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec2 max(vec2 x, vec2 y);" "vec3 max(vec3 x, vec3 y);" "vec4 max(vec4 x, vec4 y);" - + "float clamp(float x, float minVal, float maxVal);" "vec2 clamp(vec2 x, float minVal, float maxVal);" "vec3 clamp(vec3 x, float minVal, float maxVal);" @@ -309,7 +315,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec2 clamp(vec2 x, vec2 minVal, vec2 maxVal);" "vec3 clamp(vec3 x, vec3 minVal, vec3 maxVal);" "vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal);" - + "float mix(float x, float y, float a);" "vec2 mix(vec2 x, vec2 y, float a);" "vec3 mix(vec3 x, vec3 y, float a);" @@ -325,7 +331,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec2 step(float edge, vec2 x);" "vec3 step(float edge, vec3 x);" "vec4 step(float edge, vec4 x);" - + "float smoothstep(float edge0, float edge1, float x);" "vec2 smoothstep(vec2 edge0, vec2 edge1, vec2 x);" "vec3 smoothstep(vec3 edge0, vec3 edge1, vec3 x);" @@ -333,7 +339,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec2 smoothstep(float edge0, float edge1, vec2 x);" "vec3 smoothstep(float edge0, float edge1, vec3 x);" "vec4 smoothstep(float edge0, float edge1, vec4 x);" - + "\n"); if (version >= 130) { @@ -352,22 +358,22 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec2 trunc(vec2 x);" "vec3 trunc(vec3 x);" "vec4 trunc(vec4 x);" - + "float round(float x);" "vec2 round(vec2 x);" "vec3 round(vec3 x);" "vec4 round(vec4 x);" - + "float roundEven(float x);" "vec2 roundEven(vec2 x);" "vec3 roundEven(vec3 x);" "vec4 roundEven(vec4 x);" - + "float modf(float, out float);" "vec2 modf(vec2, out vec2 );" "vec3 modf(vec3, out vec3 );" "vec4 modf(vec4, out vec4 );" - + " int min(int x, int y);" "ivec2 min(ivec2 x, int y);" "ivec3 min(ivec3 x, int y);" @@ -375,7 +381,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "ivec2 min(ivec2 x, ivec2 y);" "ivec3 min(ivec3 x, ivec3 y);" "ivec4 min(ivec4 x, ivec4 y);" - + " uint min(uint x, uint y);" "uvec2 min(uvec2 x, uint y);" "uvec3 min(uvec3 x, uint y);" @@ -383,7 +389,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "uvec2 min(uvec2 x, uvec2 y);" "uvec3 min(uvec3 x, uvec3 y);" "uvec4 min(uvec4 x, uvec4 y);" - + " int max(int x, int y);" "ivec2 max(ivec2 x, int y);" "ivec3 max(ivec3 x, int y);" @@ -591,16 +597,16 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "dvec2 faceforward(dvec2, dvec2, dvec2);" "dvec3 faceforward(dvec3, dvec3, dvec3);" "dvec4 faceforward(dvec4, dvec4, dvec4);" - + "double reflect(double, double);" "dvec2 reflect(dvec2 , dvec2 );" "dvec3 reflect(dvec3 , dvec3 );" "dvec4 reflect(dvec4 , dvec4 );" - - "double refract(double, double, double);" - "dvec2 refract(dvec2 , dvec2 , double);" - "dvec3 refract(dvec3 , dvec3 , double);" - "dvec4 refract(dvec4 , dvec4 , double);" + + "double refract(double, double, float);" + "dvec2 refract(dvec2 , dvec2 , float);" + "dvec3 refract(dvec3 , dvec3 , float);" + "dvec4 refract(dvec4 , dvec4 , float);" "dmat2 matrixCompMult(dmat2, dmat2);" "dmat3 matrixCompMult(dmat3, dmat3);" @@ -801,10 +807,129 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "bvec3 notEqual(u64vec3, u64vec3);" "bvec4 notEqual(u64vec4, u64vec4);" + "int findLSB(int64_t);" + "ivec2 findLSB(i64vec2);" + "ivec3 findLSB(i64vec3);" + "ivec4 findLSB(i64vec4);" + + "int findLSB(uint64_t);" + "ivec2 findLSB(u64vec2);" + "ivec3 findLSB(u64vec3);" + "ivec4 findLSB(u64vec4);" + + "int findMSB(int64_t);" + "ivec2 findMSB(i64vec2);" + "ivec3 findMSB(i64vec3);" + "ivec4 findMSB(i64vec4);" + + "int findMSB(uint64_t);" + "ivec2 findMSB(u64vec2);" + "ivec3 findMSB(u64vec3);" + "ivec4 findMSB(u64vec4);" + "\n" ); } +#ifdef AMD_EXTENSIONS + // GL_AMD_shader_trinary_minmax + if (profile != EEsProfile && version >= 430) { + commonBuiltins.append( + "float min3(float, float, float);" + "vec2 min3(vec2, vec2, vec2);" + "vec3 min3(vec3, vec3, vec3);" + "vec4 min3(vec4, vec4, vec4);" + + "int min3(int, int, int);" + "ivec2 min3(ivec2, ivec2, ivec2);" + "ivec3 min3(ivec3, ivec3, ivec3);" + "ivec4 min3(ivec4, ivec4, ivec4);" + + "uint min3(uint, uint, uint);" + "uvec2 min3(uvec2, uvec2, uvec2);" + "uvec3 min3(uvec3, uvec3, uvec3);" + "uvec4 min3(uvec4, uvec4, uvec4);" + + "float max3(float, float, float);" + "vec2 max3(vec2, vec2, vec2);" + "vec3 max3(vec3, vec3, vec3);" + "vec4 max3(vec4, vec4, vec4);" + + "int max3(int, int, int);" + "ivec2 max3(ivec2, ivec2, ivec2);" + "ivec3 max3(ivec3, ivec3, ivec3);" + "ivec4 max3(ivec4, ivec4, ivec4);" + + "uint max3(uint, uint, uint);" + "uvec2 max3(uvec2, uvec2, uvec2);" + "uvec3 max3(uvec3, uvec3, uvec3);" + "uvec4 max3(uvec4, uvec4, uvec4);" + + "float mid3(float, float, float);" + "vec2 mid3(vec2, vec2, vec2);" + "vec3 mid3(vec3, vec3, vec3);" + "vec4 mid3(vec4, vec4, vec4);" + + "int mid3(int, int, int);" + "ivec2 mid3(ivec2, ivec2, ivec2);" + "ivec3 mid3(ivec3, ivec3, ivec3);" + "ivec4 mid3(ivec4, ivec4, ivec4);" + + "uint mid3(uint, uint, uint);" + "uvec2 mid3(uvec2, uvec2, uvec2);" + "uvec3 mid3(uvec3, uvec3, uvec3);" + "uvec4 mid3(uvec4, uvec4, uvec4);" + + "float16_t min3(float16_t, float16_t, float16_t);" + "f16vec2 min3(f16vec2, f16vec2, f16vec2);" + "f16vec3 min3(f16vec3, f16vec3, f16vec3);" + "f16vec4 min3(f16vec4, f16vec4, f16vec4);" + + "float16_t max3(float16_t, float16_t, float16_t);" + "f16vec2 max3(f16vec2, f16vec2, f16vec2);" + "f16vec3 max3(f16vec3, f16vec3, f16vec3);" + "f16vec4 max3(f16vec4, f16vec4, f16vec4);" + + "float16_t mid3(float16_t, float16_t, float16_t);" + "f16vec2 mid3(f16vec2, f16vec2, f16vec2);" + "f16vec3 mid3(f16vec3, f16vec3, f16vec3);" + "f16vec4 mid3(f16vec4, f16vec4, f16vec4);" + + "int16_t min3(int16_t, int16_t, int16_t);" + "i16vec2 min3(i16vec2, i16vec2, i16vec2);" + "i16vec3 min3(i16vec3, i16vec3, i16vec3);" + "i16vec4 min3(i16vec4, i16vec4, i16vec4);" + + "int16_t max3(int16_t, int16_t, int16_t);" + "i16vec2 max3(i16vec2, i16vec2, i16vec2);" + "i16vec3 max3(i16vec3, i16vec3, i16vec3);" + "i16vec4 max3(i16vec4, i16vec4, i16vec4);" + + "int16_t mid3(int16_t, int16_t, int16_t);" + "i16vec2 mid3(i16vec2, i16vec2, i16vec2);" + "i16vec3 mid3(i16vec3, i16vec3, i16vec3);" + "i16vec4 mid3(i16vec4, i16vec4, i16vec4);" + + "uint16_t min3(uint16_t, uint16_t, uint16_t);" + "u16vec2 min3(u16vec2, u16vec2, u16vec2);" + "u16vec3 min3(u16vec3, u16vec3, u16vec3);" + "u16vec4 min3(u16vec4, u16vec4, u16vec4);" + + "uint16_t max3(uint16_t, uint16_t, uint16_t);" + "u16vec2 max3(u16vec2, u16vec2, u16vec2);" + "u16vec3 max3(u16vec3, u16vec3, u16vec3);" + "u16vec4 max3(u16vec4, u16vec4, u16vec4);" + + "uint16_t mid3(uint16_t, uint16_t, uint16_t);" + "u16vec2 mid3(u16vec2, u16vec2, u16vec2);" + "u16vec3 mid3(u16vec3, u16vec3, u16vec3);" + "u16vec4 mid3(u16vec4, u16vec4, u16vec4);" + + "\n" + ); + } +#endif + if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 430)) { commonBuiltins.append( @@ -835,6 +960,32 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } +#ifdef NV_EXTENSIONS + if (profile != EEsProfile && version >= 440) { + commonBuiltins.append( + "uint64_t atomicMin(coherent volatile inout uint64_t, uint64_t);" + " int64_t atomicMin(coherent volatile inout int64_t, int64_t);" + + "uint64_t atomicMax(coherent volatile inout uint64_t, uint64_t);" + " int64_t atomicMax(coherent volatile inout int64_t, int64_t);" + + "uint64_t atomicAnd(coherent volatile inout uint64_t, uint64_t);" + " int64_t atomicAnd(coherent volatile inout int64_t, int64_t);" + + "uint64_t atomicOr (coherent volatile inout uint64_t, uint64_t);" + " int64_t atomicOr (coherent volatile inout int64_t, int64_t);" + + "uint64_t atomicXor(coherent volatile inout uint64_t, uint64_t);" + " int64_t atomicXor(coherent volatile inout int64_t, int64_t);" + + " int64_t atomicAdd(coherent volatile inout int64_t, int64_t);" + " int64_t atomicExchange(coherent volatile inout int64_t, int64_t);" + " int64_t atomicCompSwap(coherent volatile inout int64_t, int64_t, int64_t);" + + "\n"); + } +#endif + if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 450)) { commonBuiltins.append( @@ -859,25 +1010,25 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV if ((profile == EEsProfile && version >= 300) || (profile != EEsProfile && version >= 330)) { commonBuiltins.append( - "highp int floatBitsToInt(highp float value);" - "highp ivec2 floatBitsToInt(highp vec2 value);" - "highp ivec3 floatBitsToInt(highp vec3 value);" - "highp ivec4 floatBitsToInt(highp vec4 value);" - - "highp uint floatBitsToUint(highp float value);" - "highp uvec2 floatBitsToUint(highp vec2 value);" - "highp uvec3 floatBitsToUint(highp vec3 value);" - "highp uvec4 floatBitsToUint(highp vec4 value);" + "int floatBitsToInt(highp float value);" + "ivec2 floatBitsToInt(highp vec2 value);" + "ivec3 floatBitsToInt(highp vec3 value);" + "ivec4 floatBitsToInt(highp vec4 value);" - "highp float intBitsToFloat(highp int value);" - "highp vec2 intBitsToFloat(highp ivec2 value);" - "highp vec3 intBitsToFloat(highp ivec3 value);" - "highp vec4 intBitsToFloat(highp ivec4 value);" + "uint floatBitsToUint(highp float value);" + "uvec2 floatBitsToUint(highp vec2 value);" + "uvec3 floatBitsToUint(highp vec3 value);" + "uvec4 floatBitsToUint(highp vec4 value);" - "highp float uintBitsToFloat(highp uint value);" - "highp vec2 uintBitsToFloat(highp uvec2 value);" - "highp vec3 uintBitsToFloat(highp uvec3 value);" - "highp vec4 uintBitsToFloat(highp uvec4 value);" + "float intBitsToFloat(highp int value);" + "vec2 intBitsToFloat(highp ivec2 value);" + "vec3 intBitsToFloat(highp ivec3 value);" + "vec4 intBitsToFloat(highp ivec4 value);" + + "float uintBitsToFloat(highp uint value);" + "vec2 uintBitsToFloat(highp uvec2 value);" + "vec3 uintBitsToFloat(highp uvec3 value);" + "vec4 uintBitsToFloat(highp uvec4 value);" "\n"); } @@ -905,15 +1056,15 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 400)) { commonBuiltins.append( - "highp float frexp(highp float, out highp int);" - "highp vec2 frexp(highp vec2, out highp ivec2);" - "highp vec3 frexp(highp vec3, out highp ivec3);" - "highp vec4 frexp(highp vec4, out highp ivec4);" + "float frexp(highp float, out highp int);" + "vec2 frexp(highp vec2, out highp ivec2);" + "vec3 frexp(highp vec3, out highp ivec3);" + "vec4 frexp(highp vec4, out highp ivec4);" - "highp float ldexp(highp float, highp int);" - "highp vec2 ldexp(highp vec2, highp ivec2);" - "highp vec3 ldexp(highp vec3, highp ivec3);" - "highp vec4 ldexp(highp vec4, highp ivec4);" + "float ldexp(highp float, highp int);" + "vec2 ldexp(highp vec2, highp ivec2);" + "vec3 ldexp(highp vec3, highp ivec3);" + "vec4 ldexp(highp vec4, highp ivec4);" "\n"); } @@ -940,7 +1091,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV (profile != EEsProfile && version >= 400)) { commonBuiltins.append( "highp uint packUnorm2x16(vec2);" - "highp vec2 unpackUnorm2x16(highp uint);" + "vec2 unpackUnorm2x16(highp uint);" "\n"); } @@ -949,18 +1100,37 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV commonBuiltins.append( "highp uint packSnorm2x16(vec2);" " vec2 unpackSnorm2x16(highp uint);" - "highp uint packHalf2x16(mediump vec2);" - " vec2 unpackHalf2x16(highp uint);" + "highp uint packHalf2x16(vec2);" + "\n"); + } + + if (profile == EEsProfile && version >= 300) { + commonBuiltins.append( + "mediump vec2 unpackHalf2x16(highp uint);" + "\n"); + } else if (profile != EEsProfile && version >= 420) { + commonBuiltins.append( + " vec2 unpackHalf2x16(highp uint);" "\n"); } if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 400)) { commonBuiltins.append( - "highp uint packSnorm4x8 (mediump vec4);" - " vec4 unpackSnorm4x8(highp uint);" - "highp uint packUnorm4x8 (mediump vec4);" - " vec4 unpackUnorm4x8(highp uint);" + "highp uint packSnorm4x8(vec4);" + "highp uint packUnorm4x8(vec4);" + "\n"); + } + + if (profile == EEsProfile && version >= 310) { + commonBuiltins.append( + "mediump vec4 unpackSnorm4x8(highp uint);" + "mediump vec4 unpackUnorm4x8(highp uint);" + "\n"); + } else if (profile != EEsProfile && version >= 400) { + commonBuiltins.append( + "vec4 unpackSnorm4x8(highp uint);" + "vec4 unpackUnorm4x8(highp uint);" "\n"); } @@ -972,38 +1142,38 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "float length(vec2 x);" "float length(vec3 x);" "float length(vec4 x);" - + "float distance(float p0, float p1);" "float distance(vec2 p0, vec2 p1);" "float distance(vec3 p0, vec3 p1);" "float distance(vec4 p0, vec4 p1);" - + "float dot(float x, float y);" "float dot(vec2 x, vec2 y);" "float dot(vec3 x, vec3 y);" "float dot(vec4 x, vec4 y);" - + "vec3 cross(vec3 x, vec3 y);" "float normalize(float x);" "vec2 normalize(vec2 x);" "vec3 normalize(vec3 x);" "vec4 normalize(vec4 x);" - + "float faceforward(float N, float I, float Nref);" "vec2 faceforward(vec2 N, vec2 I, vec2 Nref);" "vec3 faceforward(vec3 N, vec3 I, vec3 Nref);" "vec4 faceforward(vec4 N, vec4 I, vec4 Nref);" - + "float reflect(float I, float N);" "vec2 reflect(vec2 I, vec2 N);" "vec3 reflect(vec3 I, vec3 N);" "vec4 reflect(vec4 I, vec4 N);" - + "float refract(float I, float N, float eta);" "vec2 refract(vec2 I, vec2 N, float eta);" "vec3 refract(vec3 I, vec3 N, float eta);" "vec4 refract(vec4 I, vec4 N, float eta);" - + "\n"); // @@ -1013,7 +1183,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "mat2 matrixCompMult(mat2 x, mat2 y);" "mat3 matrixCompMult(mat3 x, mat3 y);" "mat4 matrixCompMult(mat4 x, mat4 y);" - + "\n"); // 120 is correct for both ES and desktop @@ -1028,7 +1198,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "mat4x2 outerProduct(vec2 c, vec4 r);" "mat3x4 outerProduct(vec4 c, vec3 r);" "mat4x3 outerProduct(vec3 c, vec4 r);" - + "mat2 transpose(mat2 m);" "mat3 transpose(mat3 m);" "mat4 transpose(mat4 m);" @@ -1044,8 +1214,8 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "mat3x2 matrixCompMult(mat3x2, mat3x2);" "mat3x4 matrixCompMult(mat3x4, mat3x4);" "mat4x2 matrixCompMult(mat4x2, mat4x2);" - "mat4x3 matrixCompMult(mat4x3, mat4x3);" - + "mat4x3 matrixCompMult(mat4x3, mat4x3);" + "\n"); // 150 is correct for both ES and desktop @@ -1054,11 +1224,11 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "float determinant(mat2 m);" "float determinant(mat3 m);" "float determinant(mat4 m);" - + "mat2 inverse(mat2 m);" "mat3 inverse(mat3 m);" "mat4 inverse(mat4 m);" - + "\n"); } } @@ -1070,71 +1240,71 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "bvec2 lessThan(vec2 x, vec2 y);" "bvec3 lessThan(vec3 x, vec3 y);" "bvec4 lessThan(vec4 x, vec4 y);" - + "bvec2 lessThan(ivec2 x, ivec2 y);" "bvec3 lessThan(ivec3 x, ivec3 y);" "bvec4 lessThan(ivec4 x, ivec4 y);" - + "bvec2 lessThanEqual(vec2 x, vec2 y);" "bvec3 lessThanEqual(vec3 x, vec3 y);" "bvec4 lessThanEqual(vec4 x, vec4 y);" - + "bvec2 lessThanEqual(ivec2 x, ivec2 y);" "bvec3 lessThanEqual(ivec3 x, ivec3 y);" "bvec4 lessThanEqual(ivec4 x, ivec4 y);" - + "bvec2 greaterThan(vec2 x, vec2 y);" "bvec3 greaterThan(vec3 x, vec3 y);" "bvec4 greaterThan(vec4 x, vec4 y);" - + "bvec2 greaterThan(ivec2 x, ivec2 y);" "bvec3 greaterThan(ivec3 x, ivec3 y);" "bvec4 greaterThan(ivec4 x, ivec4 y);" - + "bvec2 greaterThanEqual(vec2 x, vec2 y);" "bvec3 greaterThanEqual(vec3 x, vec3 y);" "bvec4 greaterThanEqual(vec4 x, vec4 y);" - + "bvec2 greaterThanEqual(ivec2 x, ivec2 y);" "bvec3 greaterThanEqual(ivec3 x, ivec3 y);" "bvec4 greaterThanEqual(ivec4 x, ivec4 y);" - + "bvec2 equal(vec2 x, vec2 y);" "bvec3 equal(vec3 x, vec3 y);" "bvec4 equal(vec4 x, vec4 y);" - + "bvec2 equal(ivec2 x, ivec2 y);" "bvec3 equal(ivec3 x, ivec3 y);" "bvec4 equal(ivec4 x, ivec4 y);" - + "bvec2 equal(bvec2 x, bvec2 y);" "bvec3 equal(bvec3 x, bvec3 y);" "bvec4 equal(bvec4 x, bvec4 y);" - + "bvec2 notEqual(vec2 x, vec2 y);" "bvec3 notEqual(vec3 x, vec3 y);" "bvec4 notEqual(vec4 x, vec4 y);" - + "bvec2 notEqual(ivec2 x, ivec2 y);" "bvec3 notEqual(ivec3 x, ivec3 y);" "bvec4 notEqual(ivec4 x, ivec4 y);" - + "bvec2 notEqual(bvec2 x, bvec2 y);" "bvec3 notEqual(bvec3 x, bvec3 y);" "bvec4 notEqual(bvec4 x, bvec4 y);" - + "bool any(bvec2 x);" "bool any(bvec3 x);" "bool any(bvec4 x);" - + "bool all(bvec2 x);" "bool all(bvec3 x);" "bool all(bvec4 x);" - + "bvec2 not(bvec2 x);" "bvec3 not(bvec3 x);" "bvec4 not(bvec4 x);" - + "\n"); if (version >= 130) { @@ -1142,27 +1312,27 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "bvec2 lessThan(uvec2 x, uvec2 y);" "bvec3 lessThan(uvec3 x, uvec3 y);" "bvec4 lessThan(uvec4 x, uvec4 y);" - + "bvec2 lessThanEqual(uvec2 x, uvec2 y);" "bvec3 lessThanEqual(uvec3 x, uvec3 y);" "bvec4 lessThanEqual(uvec4 x, uvec4 y);" - + "bvec2 greaterThan(uvec2 x, uvec2 y);" "bvec3 greaterThan(uvec3 x, uvec3 y);" "bvec4 greaterThan(uvec4 x, uvec4 y);" - + "bvec2 greaterThanEqual(uvec2 x, uvec2 y);" "bvec3 greaterThanEqual(uvec3 x, uvec3 y);" "bvec4 greaterThanEqual(uvec4 x, uvec4 y);" - + "bvec2 equal(uvec2 x, uvec2 y);" "bvec3 equal(uvec3 x, uvec3 y);" "bvec4 equal(uvec4 x, uvec4 y);" "bvec2 notEqual(uvec2 x, uvec2 y);" "bvec3 notEqual(uvec3 x, uvec3 y);" - "bvec4 notEqual(uvec4 x, uvec4 y);" - + "bvec4 notEqual(uvec4 x, uvec4 y);" + "\n"); } @@ -1185,7 +1355,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec4 texture3DProj(sampler3D, vec4);" // OES_texture_3D, but caught by keyword check "vec4 textureCube(samplerCube, vec3);" - + "\n"); } } @@ -1199,7 +1369,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec4 texture1DProj(sampler1D, vec2);" "vec4 texture1DProj(sampler1D, vec4);" - + "vec4 shadow1D(sampler1DShadow, vec3);" "vec4 shadow2D(sampler2DShadow, vec3);" "vec4 shadow1DProj(sampler1DShadow, vec4);" @@ -1217,15 +1387,33 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV if (profile == EEsProfile) { if (spvVersion.spv == 0) { + if (version < 300) { + commonBuiltins.append( + "vec4 texture2D(samplerExternalOES, vec2 coord);" // GL_OES_EGL_image_external + "vec4 texture2DProj(samplerExternalOES, vec3);" // GL_OES_EGL_image_external + "vec4 texture2DProj(samplerExternalOES, vec4);" // GL_OES_EGL_image_external + "\n"); + } else { + commonBuiltins.append( + "highp ivec2 textureSize(samplerExternalOES, int lod);" // GL_OES_EGL_image_external_essl3 + "vec4 texture(samplerExternalOES, vec2);" // GL_OES_EGL_image_external_essl3 + "vec4 texture(samplerExternalOES, vec2, float bias);" // GL_OES_EGL_image_external_essl3 + "vec4 textureProj(samplerExternalOES, vec3);" // GL_OES_EGL_image_external_essl3 + "vec4 textureProj(samplerExternalOES, vec3, float bias);" // GL_OES_EGL_image_external_essl3 + "vec4 textureProj(samplerExternalOES, vec4);" // GL_OES_EGL_image_external_essl3 + "vec4 textureProj(samplerExternalOES, vec4, float bias);" // GL_OES_EGL_image_external_essl3 + "vec4 texelFetch(samplerExternalOES, ivec2, int lod);" // GL_OES_EGL_image_external_essl3 + "\n"); + } commonBuiltins.append( - "vec4 texture2D(samplerExternalOES, vec2 coord);" // GL_OES_EGL_image_external, caught by keyword check - "vec4 texture2DProj(samplerExternalOES, vec3);" // GL_OES_EGL_image_external, caught by keyword check - "vec4 texture2DProj(samplerExternalOES, vec4);" // GL_OES_EGL_image_external, caught by keyword check "vec4 texture2DGradEXT(sampler2D, vec2, vec2, vec2);" // GL_EXT_shader_texture_lod "vec4 texture2DProjGradEXT(sampler2D, vec3, vec2, vec2);" // GL_EXT_shader_texture_lod "vec4 texture2DProjGradEXT(sampler2D, vec4, vec2, vec2);" // GL_EXT_shader_texture_lod "vec4 textureCubeGradEXT(samplerCube, vec3, vec3, vec3);" // GL_EXT_shader_texture_lod + "float shadow2DEXT(sampler2DShadow, vec3);" // GL_EXT_shadow_samplers + "float shadow2DProjEXT(sampler2DShadow, vec4);" // GL_EXT_shadow_samplers + "\n"); } } @@ -1233,28 +1421,28 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV // // Noise functions. // - if (profile != EEsProfile) { + if (spvVersion.spv == 0 && profile != EEsProfile) { commonBuiltins.append( "float noise1(float x);" "float noise1(vec2 x);" "float noise1(vec3 x);" "float noise1(vec4 x);" - + "vec2 noise2(float x);" "vec2 noise2(vec2 x);" "vec2 noise2(vec3 x);" "vec2 noise2(vec4 x);" - + "vec3 noise3(float x);" "vec3 noise3(vec2 x);" "vec3 noise3(vec3 x);" "vec3 noise3(vec4 x);" - + "vec4 noise4(float x);" "vec4 noise4(vec2 x);" "vec4 noise4(vec3 x);" "vec4 noise4(vec4 x);" - + "\n"); } @@ -1265,9 +1453,23 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV if ((profile != EEsProfile && version >= 300) || (profile == EEsProfile && version >= 310)) { commonBuiltins.append( - "uint atomicCounterIncrement(atomic_uint x);" - "uint atomicCounterDecrement(atomic_uint x);" - "uint atomicCounter(atomic_uint x);" + "uint atomicCounterIncrement(atomic_uint);" + "uint atomicCounterDecrement(atomic_uint);" + "uint atomicCounter(atomic_uint);" + + "\n"); + } + if (profile != EEsProfile && version >= 460) { + commonBuiltins.append( + "uint atomicCounterAdd(atomic_uint, uint);" + "uint atomicCounterSubtract(atomic_uint, uint);" + "uint atomicCounterMin(atomic_uint, uint);" + "uint atomicCounterMax(atomic_uint, uint);" + "uint atomicCounterAnd(atomic_uint, uint);" + "uint atomicCounterOr(atomic_uint, uint);" + "uint atomicCounterXor(atomic_uint, uint);" + "uint atomicCounterExchange(atomic_uint, uint);" + "uint atomicCounterCompSwap(atomic_uint, uint, uint);" "\n"); } @@ -1297,6 +1499,11 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "uvec3 bitfieldInsert(uvec3 base, uvec3, int, int);" "uvec4 bitfieldInsert(uvec4 base, uvec4, int, int);" + "\n"); + } + + if (profile != EEsProfile && version >= 400) { + commonBuiltins.append( " int findLSB( int);" "ivec2 findLSB(ivec2);" "ivec3 findLSB(ivec3);" @@ -1308,95 +1515,23 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "ivec4 findLSB(uvec4);" "\n"); - } - - if (profile != EEsProfile && version >= 400) { + } else if (profile == EEsProfile && version >= 310) { commonBuiltins.append( - " uint uaddCarry( uint, uint, out uint carry);" - "uvec2 uaddCarry(uvec2, uvec2, out uvec2 carry);" - "uvec3 uaddCarry(uvec3, uvec3, out uvec3 carry);" - "uvec4 uaddCarry(uvec4, uvec4, out uvec4 carry);" + "lowp int findLSB( int);" + "lowp ivec2 findLSB(ivec2);" + "lowp ivec3 findLSB(ivec3);" + "lowp ivec4 findLSB(ivec4);" - " uint usubBorrow( uint, uint, out uint borrow);" - "uvec2 usubBorrow(uvec2, uvec2, out uvec2 borrow);" - "uvec3 usubBorrow(uvec3, uvec3, out uvec3 borrow);" - "uvec4 usubBorrow(uvec4, uvec4, out uvec4 borrow);" - - "void umulExtended( uint, uint, out uint, out uint lsb);" - "void umulExtended(uvec2, uvec2, out uvec2, out uvec2 lsb);" - "void umulExtended(uvec3, uvec3, out uvec3, out uvec3 lsb);" - "void umulExtended(uvec4, uvec4, out uvec4, out uvec4 lsb);" - - "void imulExtended( int, int, out int, out int lsb);" - "void imulExtended(ivec2, ivec2, out ivec2, out ivec2 lsb);" - "void imulExtended(ivec3, ivec3, out ivec3, out ivec3 lsb);" - "void imulExtended(ivec4, ivec4, out ivec4, out ivec4 lsb);" - - " int bitfieldReverse( int);" - "ivec2 bitfieldReverse(ivec2);" - "ivec3 bitfieldReverse(ivec3);" - "ivec4 bitfieldReverse(ivec4);" - - " uint bitfieldReverse( uint);" - "uvec2 bitfieldReverse(uvec2);" - "uvec3 bitfieldReverse(uvec3);" - "uvec4 bitfieldReverse(uvec4);" - - " int bitCount( int);" - "ivec2 bitCount(ivec2);" - "ivec3 bitCount(ivec3);" - "ivec4 bitCount(ivec4);" - - " int bitCount( uint);" - "ivec2 bitCount(uvec2);" - "ivec3 bitCount(uvec3);" - "ivec4 bitCount(uvec4);" - - " int findMSB( int);" - "ivec2 findMSB(ivec2);" - "ivec3 findMSB(ivec3);" - "ivec4 findMSB(ivec4);" - - " int findMSB( uint);" - "ivec2 findMSB(uvec2);" - "ivec3 findMSB(uvec3);" - "ivec4 findMSB(uvec4);" + "lowp int findLSB( uint);" + "lowp ivec2 findLSB(uvec2);" + "lowp ivec3 findLSB(uvec3);" + "lowp ivec4 findLSB(uvec4);" "\n"); } - if (profile == EEsProfile && version >= 310) { + if (profile != EEsProfile && version >= 400) { commonBuiltins.append( - "highp uint uaddCarry(highp uint, highp uint, out lowp uint carry);" - "highp uvec2 uaddCarry(highp uvec2, highp uvec2, out lowp uvec2 carry);" - "highp uvec3 uaddCarry(highp uvec3, highp uvec3, out lowp uvec3 carry);" - "highp uvec4 uaddCarry(highp uvec4, highp uvec4, out lowp uvec4 carry);" - - "highp uint usubBorrow(highp uint, highp uint, out lowp uint borrow);" - "highp uvec2 usubBorrow(highp uvec2, highp uvec2, out lowp uvec2 borrow);" - "highp uvec3 usubBorrow(highp uvec3, highp uvec3, out lowp uvec3 borrow);" - "highp uvec4 usubBorrow(highp uvec4, highp uvec4, out lowp uvec4 borrow);" - - "void umulExtended(highp uint, highp uint, highp out uint, out highp uint lsb);" - "void umulExtended(highp uvec2, highp uvec2, highp out uvec2, out highp uvec2 lsb);" - "void umulExtended(highp uvec3, highp uvec3, highp out uvec3, out highp uvec3 lsb);" - "void umulExtended(highp uvec4, highp uvec4, highp out uvec4, out highp uvec4 lsb);" - - "void imulExtended(highp int, highp int, highp out int, out highp int lsb);" - "void imulExtended(highp ivec2, highp ivec2, highp out ivec2, out highp ivec2 lsb);" - "void imulExtended(highp ivec3, highp ivec3, highp out ivec3, out highp ivec3 lsb);" - "void imulExtended(highp ivec4, highp ivec4, highp out ivec4, out highp ivec4 lsb);" - - "highp int bitfieldReverse(highp int);" - "highp ivec2 bitfieldReverse(highp ivec2);" - "highp ivec3 bitfieldReverse(highp ivec3);" - "highp ivec4 bitfieldReverse(highp ivec4);" - - "highp uint bitfieldReverse(highp uint);" - "highp uvec2 bitfieldReverse(highp uvec2);" - "highp uvec3 bitfieldReverse(highp uvec3);" - "highp uvec4 bitfieldReverse(highp uvec4);" - " int bitCount( int);" "ivec2 bitCount(ivec2);" "ivec3 bitCount(ivec3);" @@ -1416,7 +1551,68 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "ivec2 findMSB(highp uvec2);" "ivec3 findMSB(highp uvec3);" "ivec4 findMSB(highp uvec4);" - + + "\n"); + } + + if ((profile == EEsProfile && version >= 310) || + (profile != EEsProfile && version >= 400)) { + commonBuiltins.append( + " uint uaddCarry(highp uint, highp uint, out lowp uint carry);" + "uvec2 uaddCarry(highp uvec2, highp uvec2, out lowp uvec2 carry);" + "uvec3 uaddCarry(highp uvec3, highp uvec3, out lowp uvec3 carry);" + "uvec4 uaddCarry(highp uvec4, highp uvec4, out lowp uvec4 carry);" + + " uint usubBorrow(highp uint, highp uint, out lowp uint borrow);" + "uvec2 usubBorrow(highp uvec2, highp uvec2, out lowp uvec2 borrow);" + "uvec3 usubBorrow(highp uvec3, highp uvec3, out lowp uvec3 borrow);" + "uvec4 usubBorrow(highp uvec4, highp uvec4, out lowp uvec4 borrow);" + + "void umulExtended(highp uint, highp uint, out highp uint, out highp uint lsb);" + "void umulExtended(highp uvec2, highp uvec2, out highp uvec2, out highp uvec2 lsb);" + "void umulExtended(highp uvec3, highp uvec3, out highp uvec3, out highp uvec3 lsb);" + "void umulExtended(highp uvec4, highp uvec4, out highp uvec4, out highp uvec4 lsb);" + + "void imulExtended(highp int, highp int, out highp int, out highp int lsb);" + "void imulExtended(highp ivec2, highp ivec2, out highp ivec2, out highp ivec2 lsb);" + "void imulExtended(highp ivec3, highp ivec3, out highp ivec3, out highp ivec3 lsb);" + "void imulExtended(highp ivec4, highp ivec4, out highp ivec4, out highp ivec4 lsb);" + + " int bitfieldReverse(highp int);" + "ivec2 bitfieldReverse(highp ivec2);" + "ivec3 bitfieldReverse(highp ivec3);" + "ivec4 bitfieldReverse(highp ivec4);" + + " uint bitfieldReverse(highp uint);" + "uvec2 bitfieldReverse(highp uvec2);" + "uvec3 bitfieldReverse(highp uvec3);" + "uvec4 bitfieldReverse(highp uvec4);" + + "\n"); + } + + if (profile == EEsProfile && version >= 310) { + commonBuiltins.append( + "lowp int bitCount( int);" + "lowp ivec2 bitCount(ivec2);" + "lowp ivec3 bitCount(ivec3);" + "lowp ivec4 bitCount(ivec4);" + + "lowp int bitCount( uint);" + "lowp ivec2 bitCount(uvec2);" + "lowp ivec3 bitCount(uvec3);" + "lowp ivec4 bitCount(uvec4);" + + "lowp int findMSB(highp int);" + "lowp ivec2 findMSB(highp ivec2);" + "lowp ivec3 findMSB(highp ivec3);" + "lowp ivec4 findMSB(highp ivec4);" + + "lowp int findMSB(highp uint);" + "lowp ivec2 findMSB(highp uvec2);" + "lowp ivec3 findMSB(highp uvec3);" + "lowp ivec4 findMSB(highp uvec4);" + "\n"); } @@ -1458,7 +1654,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } - // GL_ARB_shader_group_vote + // GL_ARB_shader_group_vote if (profile != EEsProfile && version >= 430) { commonBuiltins.append( "bool anyInvocationARB(bool);" @@ -1468,6 +1664,2911 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } + // GL_KHR_shader_subgroup + if (spvVersion.vulkan > 0) { + commonBuiltins.append( + "void subgroupBarrier();" + "void subgroupMemoryBarrier();" + "void subgroupMemoryBarrierBuffer();" + "void subgroupMemoryBarrierImage();" + "bool subgroupElect();" + + "bool subgroupAll(bool);\n" + "bool subgroupAny(bool);\n" + + "bool subgroupAllEqual(float);\n" + "bool subgroupAllEqual(vec2);\n" + "bool subgroupAllEqual(vec3);\n" + "bool subgroupAllEqual(vec4);\n" + "bool subgroupAllEqual(int);\n" + "bool subgroupAllEqual(ivec2);\n" + "bool subgroupAllEqual(ivec3);\n" + "bool subgroupAllEqual(ivec4);\n" + "bool subgroupAllEqual(uint);\n" + "bool subgroupAllEqual(uvec2);\n" + "bool subgroupAllEqual(uvec3);\n" + "bool subgroupAllEqual(uvec4);\n" + "bool subgroupAllEqual(bool);\n" + "bool subgroupAllEqual(bvec2);\n" + "bool subgroupAllEqual(bvec3);\n" + "bool subgroupAllEqual(bvec4);\n" + + "float subgroupBroadcast(float, uint);\n" + "vec2 subgroupBroadcast(vec2, uint);\n" + "vec3 subgroupBroadcast(vec3, uint);\n" + "vec4 subgroupBroadcast(vec4, uint);\n" + "int subgroupBroadcast(int, uint);\n" + "ivec2 subgroupBroadcast(ivec2, uint);\n" + "ivec3 subgroupBroadcast(ivec3, uint);\n" + "ivec4 subgroupBroadcast(ivec4, uint);\n" + "uint subgroupBroadcast(uint, uint);\n" + "uvec2 subgroupBroadcast(uvec2, uint);\n" + "uvec3 subgroupBroadcast(uvec3, uint);\n" + "uvec4 subgroupBroadcast(uvec4, uint);\n" + "bool subgroupBroadcast(bool, uint);\n" + "bvec2 subgroupBroadcast(bvec2, uint);\n" + "bvec3 subgroupBroadcast(bvec3, uint);\n" + "bvec4 subgroupBroadcast(bvec4, uint);\n" + + "float subgroupBroadcastFirst(float);\n" + "vec2 subgroupBroadcastFirst(vec2);\n" + "vec3 subgroupBroadcastFirst(vec3);\n" + "vec4 subgroupBroadcastFirst(vec4);\n" + "int subgroupBroadcastFirst(int);\n" + "ivec2 subgroupBroadcastFirst(ivec2);\n" + "ivec3 subgroupBroadcastFirst(ivec3);\n" + "ivec4 subgroupBroadcastFirst(ivec4);\n" + "uint subgroupBroadcastFirst(uint);\n" + "uvec2 subgroupBroadcastFirst(uvec2);\n" + "uvec3 subgroupBroadcastFirst(uvec3);\n" + "uvec4 subgroupBroadcastFirst(uvec4);\n" + "bool subgroupBroadcastFirst(bool);\n" + "bvec2 subgroupBroadcastFirst(bvec2);\n" + "bvec3 subgroupBroadcastFirst(bvec3);\n" + "bvec4 subgroupBroadcastFirst(bvec4);\n" + + "uvec4 subgroupBallot(bool);\n" + "bool subgroupInverseBallot(uvec4);\n" + "bool subgroupBallotBitExtract(uvec4, uint);\n" + "uint subgroupBallotBitCount(uvec4);\n" + "uint subgroupBallotInclusiveBitCount(uvec4);\n" + "uint subgroupBallotExclusiveBitCount(uvec4);\n" + "uint subgroupBallotFindLSB(uvec4);\n" + "uint subgroupBallotFindMSB(uvec4);\n" + + "float subgroupShuffle(float, uint);\n" + "vec2 subgroupShuffle(vec2, uint);\n" + "vec3 subgroupShuffle(vec3, uint);\n" + "vec4 subgroupShuffle(vec4, uint);\n" + "int subgroupShuffle(int, uint);\n" + "ivec2 subgroupShuffle(ivec2, uint);\n" + "ivec3 subgroupShuffle(ivec3, uint);\n" + "ivec4 subgroupShuffle(ivec4, uint);\n" + "uint subgroupShuffle(uint, uint);\n" + "uvec2 subgroupShuffle(uvec2, uint);\n" + "uvec3 subgroupShuffle(uvec3, uint);\n" + "uvec4 subgroupShuffle(uvec4, uint);\n" + "bool subgroupShuffle(bool, uint);\n" + "bvec2 subgroupShuffle(bvec2, uint);\n" + "bvec3 subgroupShuffle(bvec3, uint);\n" + "bvec4 subgroupShuffle(bvec4, uint);\n" + + "float subgroupShuffleXor(float, uint);\n" + "vec2 subgroupShuffleXor(vec2, uint);\n" + "vec3 subgroupShuffleXor(vec3, uint);\n" + "vec4 subgroupShuffleXor(vec4, uint);\n" + "int subgroupShuffleXor(int, uint);\n" + "ivec2 subgroupShuffleXor(ivec2, uint);\n" + "ivec3 subgroupShuffleXor(ivec3, uint);\n" + "ivec4 subgroupShuffleXor(ivec4, uint);\n" + "uint subgroupShuffleXor(uint, uint);\n" + "uvec2 subgroupShuffleXor(uvec2, uint);\n" + "uvec3 subgroupShuffleXor(uvec3, uint);\n" + "uvec4 subgroupShuffleXor(uvec4, uint);\n" + "bool subgroupShuffleXor(bool, uint);\n" + "bvec2 subgroupShuffleXor(bvec2, uint);\n" + "bvec3 subgroupShuffleXor(bvec3, uint);\n" + "bvec4 subgroupShuffleXor(bvec4, uint);\n" + + "float subgroupShuffleUp(float, uint delta);\n" + "vec2 subgroupShuffleUp(vec2, uint delta);\n" + "vec3 subgroupShuffleUp(vec3, uint delta);\n" + "vec4 subgroupShuffleUp(vec4, uint delta);\n" + "int subgroupShuffleUp(int, uint delta);\n" + "ivec2 subgroupShuffleUp(ivec2, uint delta);\n" + "ivec3 subgroupShuffleUp(ivec3, uint delta);\n" + "ivec4 subgroupShuffleUp(ivec4, uint delta);\n" + "uint subgroupShuffleUp(uint, uint delta);\n" + "uvec2 subgroupShuffleUp(uvec2, uint delta);\n" + "uvec3 subgroupShuffleUp(uvec3, uint delta);\n" + "uvec4 subgroupShuffleUp(uvec4, uint delta);\n" + "bool subgroupShuffleUp(bool, uint delta);\n" + "bvec2 subgroupShuffleUp(bvec2, uint delta);\n" + "bvec3 subgroupShuffleUp(bvec3, uint delta);\n" + "bvec4 subgroupShuffleUp(bvec4, uint delta);\n" + + "float subgroupShuffleDown(float, uint delta);\n" + "vec2 subgroupShuffleDown(vec2, uint delta);\n" + "vec3 subgroupShuffleDown(vec3, uint delta);\n" + "vec4 subgroupShuffleDown(vec4, uint delta);\n" + "int subgroupShuffleDown(int, uint delta);\n" + "ivec2 subgroupShuffleDown(ivec2, uint delta);\n" + "ivec3 subgroupShuffleDown(ivec3, uint delta);\n" + "ivec4 subgroupShuffleDown(ivec4, uint delta);\n" + "uint subgroupShuffleDown(uint, uint delta);\n" + "uvec2 subgroupShuffleDown(uvec2, uint delta);\n" + "uvec3 subgroupShuffleDown(uvec3, uint delta);\n" + "uvec4 subgroupShuffleDown(uvec4, uint delta);\n" + "bool subgroupShuffleDown(bool, uint delta);\n" + "bvec2 subgroupShuffleDown(bvec2, uint delta);\n" + "bvec3 subgroupShuffleDown(bvec3, uint delta);\n" + "bvec4 subgroupShuffleDown(bvec4, uint delta);\n" + + "float subgroupAdd(float);\n" + "vec2 subgroupAdd(vec2);\n" + "vec3 subgroupAdd(vec3);\n" + "vec4 subgroupAdd(vec4);\n" + "int subgroupAdd(int);\n" + "ivec2 subgroupAdd(ivec2);\n" + "ivec3 subgroupAdd(ivec3);\n" + "ivec4 subgroupAdd(ivec4);\n" + "uint subgroupAdd(uint);\n" + "uvec2 subgroupAdd(uvec2);\n" + "uvec3 subgroupAdd(uvec3);\n" + "uvec4 subgroupAdd(uvec4);\n" + + "float subgroupMul(float);\n" + "vec2 subgroupMul(vec2);\n" + "vec3 subgroupMul(vec3);\n" + "vec4 subgroupMul(vec4);\n" + "int subgroupMul(int);\n" + "ivec2 subgroupMul(ivec2);\n" + "ivec3 subgroupMul(ivec3);\n" + "ivec4 subgroupMul(ivec4);\n" + "uint subgroupMul(uint);\n" + "uvec2 subgroupMul(uvec2);\n" + "uvec3 subgroupMul(uvec3);\n" + "uvec4 subgroupMul(uvec4);\n" + + "float subgroupMin(float);\n" + "vec2 subgroupMin(vec2);\n" + "vec3 subgroupMin(vec3);\n" + "vec4 subgroupMin(vec4);\n" + "int subgroupMin(int);\n" + "ivec2 subgroupMin(ivec2);\n" + "ivec3 subgroupMin(ivec3);\n" + "ivec4 subgroupMin(ivec4);\n" + "uint subgroupMin(uint);\n" + "uvec2 subgroupMin(uvec2);\n" + "uvec3 subgroupMin(uvec3);\n" + "uvec4 subgroupMin(uvec4);\n" + + "float subgroupMax(float);\n" + "vec2 subgroupMax(vec2);\n" + "vec3 subgroupMax(vec3);\n" + "vec4 subgroupMax(vec4);\n" + "int subgroupMax(int);\n" + "ivec2 subgroupMax(ivec2);\n" + "ivec3 subgroupMax(ivec3);\n" + "ivec4 subgroupMax(ivec4);\n" + "uint subgroupMax(uint);\n" + "uvec2 subgroupMax(uvec2);\n" + "uvec3 subgroupMax(uvec3);\n" + "uvec4 subgroupMax(uvec4);\n" + + "int subgroupAnd(int);\n" + "ivec2 subgroupAnd(ivec2);\n" + "ivec3 subgroupAnd(ivec3);\n" + "ivec4 subgroupAnd(ivec4);\n" + "uint subgroupAnd(uint);\n" + "uvec2 subgroupAnd(uvec2);\n" + "uvec3 subgroupAnd(uvec3);\n" + "uvec4 subgroupAnd(uvec4);\n" + "bool subgroupAnd(bool);\n" + "bvec2 subgroupAnd(bvec2);\n" + "bvec3 subgroupAnd(bvec3);\n" + "bvec4 subgroupAnd(bvec4);\n" + + "int subgroupOr(int);\n" + "ivec2 subgroupOr(ivec2);\n" + "ivec3 subgroupOr(ivec3);\n" + "ivec4 subgroupOr(ivec4);\n" + "uint subgroupOr(uint);\n" + "uvec2 subgroupOr(uvec2);\n" + "uvec3 subgroupOr(uvec3);\n" + "uvec4 subgroupOr(uvec4);\n" + "bool subgroupOr(bool);\n" + "bvec2 subgroupOr(bvec2);\n" + "bvec3 subgroupOr(bvec3);\n" + "bvec4 subgroupOr(bvec4);\n" + + "int subgroupXor(int);\n" + "ivec2 subgroupXor(ivec2);\n" + "ivec3 subgroupXor(ivec3);\n" + "ivec4 subgroupXor(ivec4);\n" + "uint subgroupXor(uint);\n" + "uvec2 subgroupXor(uvec2);\n" + "uvec3 subgroupXor(uvec3);\n" + "uvec4 subgroupXor(uvec4);\n" + "bool subgroupXor(bool);\n" + "bvec2 subgroupXor(bvec2);\n" + "bvec3 subgroupXor(bvec3);\n" + "bvec4 subgroupXor(bvec4);\n" + + "float subgroupInclusiveAdd(float);\n" + "vec2 subgroupInclusiveAdd(vec2);\n" + "vec3 subgroupInclusiveAdd(vec3);\n" + "vec4 subgroupInclusiveAdd(vec4);\n" + "int subgroupInclusiveAdd(int);\n" + "ivec2 subgroupInclusiveAdd(ivec2);\n" + "ivec3 subgroupInclusiveAdd(ivec3);\n" + "ivec4 subgroupInclusiveAdd(ivec4);\n" + "uint subgroupInclusiveAdd(uint);\n" + "uvec2 subgroupInclusiveAdd(uvec2);\n" + "uvec3 subgroupInclusiveAdd(uvec3);\n" + "uvec4 subgroupInclusiveAdd(uvec4);\n" + + "float subgroupInclusiveMul(float);\n" + "vec2 subgroupInclusiveMul(vec2);\n" + "vec3 subgroupInclusiveMul(vec3);\n" + "vec4 subgroupInclusiveMul(vec4);\n" + "int subgroupInclusiveMul(int);\n" + "ivec2 subgroupInclusiveMul(ivec2);\n" + "ivec3 subgroupInclusiveMul(ivec3);\n" + "ivec4 subgroupInclusiveMul(ivec4);\n" + "uint subgroupInclusiveMul(uint);\n" + "uvec2 subgroupInclusiveMul(uvec2);\n" + "uvec3 subgroupInclusiveMul(uvec3);\n" + "uvec4 subgroupInclusiveMul(uvec4);\n" + + "float subgroupInclusiveMin(float);\n" + "vec2 subgroupInclusiveMin(vec2);\n" + "vec3 subgroupInclusiveMin(vec3);\n" + "vec4 subgroupInclusiveMin(vec4);\n" + "int subgroupInclusiveMin(int);\n" + "ivec2 subgroupInclusiveMin(ivec2);\n" + "ivec3 subgroupInclusiveMin(ivec3);\n" + "ivec4 subgroupInclusiveMin(ivec4);\n" + "uint subgroupInclusiveMin(uint);\n" + "uvec2 subgroupInclusiveMin(uvec2);\n" + "uvec3 subgroupInclusiveMin(uvec3);\n" + "uvec4 subgroupInclusiveMin(uvec4);\n" + + "float subgroupInclusiveMax(float);\n" + "vec2 subgroupInclusiveMax(vec2);\n" + "vec3 subgroupInclusiveMax(vec3);\n" + "vec4 subgroupInclusiveMax(vec4);\n" + "int subgroupInclusiveMax(int);\n" + "ivec2 subgroupInclusiveMax(ivec2);\n" + "ivec3 subgroupInclusiveMax(ivec3);\n" + "ivec4 subgroupInclusiveMax(ivec4);\n" + "uint subgroupInclusiveMax(uint);\n" + "uvec2 subgroupInclusiveMax(uvec2);\n" + "uvec3 subgroupInclusiveMax(uvec3);\n" + "uvec4 subgroupInclusiveMax(uvec4);\n" + + "int subgroupInclusiveAnd(int);\n" + "ivec2 subgroupInclusiveAnd(ivec2);\n" + "ivec3 subgroupInclusiveAnd(ivec3);\n" + "ivec4 subgroupInclusiveAnd(ivec4);\n" + "uint subgroupInclusiveAnd(uint);\n" + "uvec2 subgroupInclusiveAnd(uvec2);\n" + "uvec3 subgroupInclusiveAnd(uvec3);\n" + "uvec4 subgroupInclusiveAnd(uvec4);\n" + "bool subgroupInclusiveAnd(bool);\n" + "bvec2 subgroupInclusiveAnd(bvec2);\n" + "bvec3 subgroupInclusiveAnd(bvec3);\n" + "bvec4 subgroupInclusiveAnd(bvec4);\n" + + "int subgroupInclusiveOr(int);\n" + "ivec2 subgroupInclusiveOr(ivec2);\n" + "ivec3 subgroupInclusiveOr(ivec3);\n" + "ivec4 subgroupInclusiveOr(ivec4);\n" + "uint subgroupInclusiveOr(uint);\n" + "uvec2 subgroupInclusiveOr(uvec2);\n" + "uvec3 subgroupInclusiveOr(uvec3);\n" + "uvec4 subgroupInclusiveOr(uvec4);\n" + "bool subgroupInclusiveOr(bool);\n" + "bvec2 subgroupInclusiveOr(bvec2);\n" + "bvec3 subgroupInclusiveOr(bvec3);\n" + "bvec4 subgroupInclusiveOr(bvec4);\n" + + "int subgroupInclusiveXor(int);\n" + "ivec2 subgroupInclusiveXor(ivec2);\n" + "ivec3 subgroupInclusiveXor(ivec3);\n" + "ivec4 subgroupInclusiveXor(ivec4);\n" + "uint subgroupInclusiveXor(uint);\n" + "uvec2 subgroupInclusiveXor(uvec2);\n" + "uvec3 subgroupInclusiveXor(uvec3);\n" + "uvec4 subgroupInclusiveXor(uvec4);\n" + "bool subgroupInclusiveXor(bool);\n" + "bvec2 subgroupInclusiveXor(bvec2);\n" + "bvec3 subgroupInclusiveXor(bvec3);\n" + "bvec4 subgroupInclusiveXor(bvec4);\n" + + "float subgroupExclusiveAdd(float);\n" + "vec2 subgroupExclusiveAdd(vec2);\n" + "vec3 subgroupExclusiveAdd(vec3);\n" + "vec4 subgroupExclusiveAdd(vec4);\n" + "int subgroupExclusiveAdd(int);\n" + "ivec2 subgroupExclusiveAdd(ivec2);\n" + "ivec3 subgroupExclusiveAdd(ivec3);\n" + "ivec4 subgroupExclusiveAdd(ivec4);\n" + "uint subgroupExclusiveAdd(uint);\n" + "uvec2 subgroupExclusiveAdd(uvec2);\n" + "uvec3 subgroupExclusiveAdd(uvec3);\n" + "uvec4 subgroupExclusiveAdd(uvec4);\n" + + "float subgroupExclusiveMul(float);\n" + "vec2 subgroupExclusiveMul(vec2);\n" + "vec3 subgroupExclusiveMul(vec3);\n" + "vec4 subgroupExclusiveMul(vec4);\n" + "int subgroupExclusiveMul(int);\n" + "ivec2 subgroupExclusiveMul(ivec2);\n" + "ivec3 subgroupExclusiveMul(ivec3);\n" + "ivec4 subgroupExclusiveMul(ivec4);\n" + "uint subgroupExclusiveMul(uint);\n" + "uvec2 subgroupExclusiveMul(uvec2);\n" + "uvec3 subgroupExclusiveMul(uvec3);\n" + "uvec4 subgroupExclusiveMul(uvec4);\n" + + "float subgroupExclusiveMin(float);\n" + "vec2 subgroupExclusiveMin(vec2);\n" + "vec3 subgroupExclusiveMin(vec3);\n" + "vec4 subgroupExclusiveMin(vec4);\n" + "int subgroupExclusiveMin(int);\n" + "ivec2 subgroupExclusiveMin(ivec2);\n" + "ivec3 subgroupExclusiveMin(ivec3);\n" + "ivec4 subgroupExclusiveMin(ivec4);\n" + "uint subgroupExclusiveMin(uint);\n" + "uvec2 subgroupExclusiveMin(uvec2);\n" + "uvec3 subgroupExclusiveMin(uvec3);\n" + "uvec4 subgroupExclusiveMin(uvec4);\n" + + "float subgroupExclusiveMax(float);\n" + "vec2 subgroupExclusiveMax(vec2);\n" + "vec3 subgroupExclusiveMax(vec3);\n" + "vec4 subgroupExclusiveMax(vec4);\n" + "int subgroupExclusiveMax(int);\n" + "ivec2 subgroupExclusiveMax(ivec2);\n" + "ivec3 subgroupExclusiveMax(ivec3);\n" + "ivec4 subgroupExclusiveMax(ivec4);\n" + "uint subgroupExclusiveMax(uint);\n" + "uvec2 subgroupExclusiveMax(uvec2);\n" + "uvec3 subgroupExclusiveMax(uvec3);\n" + "uvec4 subgroupExclusiveMax(uvec4);\n" + + "int subgroupExclusiveAnd(int);\n" + "ivec2 subgroupExclusiveAnd(ivec2);\n" + "ivec3 subgroupExclusiveAnd(ivec3);\n" + "ivec4 subgroupExclusiveAnd(ivec4);\n" + "uint subgroupExclusiveAnd(uint);\n" + "uvec2 subgroupExclusiveAnd(uvec2);\n" + "uvec3 subgroupExclusiveAnd(uvec3);\n" + "uvec4 subgroupExclusiveAnd(uvec4);\n" + "bool subgroupExclusiveAnd(bool);\n" + "bvec2 subgroupExclusiveAnd(bvec2);\n" + "bvec3 subgroupExclusiveAnd(bvec3);\n" + "bvec4 subgroupExclusiveAnd(bvec4);\n" + + "int subgroupExclusiveOr(int);\n" + "ivec2 subgroupExclusiveOr(ivec2);\n" + "ivec3 subgroupExclusiveOr(ivec3);\n" + "ivec4 subgroupExclusiveOr(ivec4);\n" + "uint subgroupExclusiveOr(uint);\n" + "uvec2 subgroupExclusiveOr(uvec2);\n" + "uvec3 subgroupExclusiveOr(uvec3);\n" + "uvec4 subgroupExclusiveOr(uvec4);\n" + "bool subgroupExclusiveOr(bool);\n" + "bvec2 subgroupExclusiveOr(bvec2);\n" + "bvec3 subgroupExclusiveOr(bvec3);\n" + "bvec4 subgroupExclusiveOr(bvec4);\n" + + "int subgroupExclusiveXor(int);\n" + "ivec2 subgroupExclusiveXor(ivec2);\n" + "ivec3 subgroupExclusiveXor(ivec3);\n" + "ivec4 subgroupExclusiveXor(ivec4);\n" + "uint subgroupExclusiveXor(uint);\n" + "uvec2 subgroupExclusiveXor(uvec2);\n" + "uvec3 subgroupExclusiveXor(uvec3);\n" + "uvec4 subgroupExclusiveXor(uvec4);\n" + "bool subgroupExclusiveXor(bool);\n" + "bvec2 subgroupExclusiveXor(bvec2);\n" + "bvec3 subgroupExclusiveXor(bvec3);\n" + "bvec4 subgroupExclusiveXor(bvec4);\n" + + "float subgroupClusteredAdd(float, uint);\n" + "vec2 subgroupClusteredAdd(vec2, uint);\n" + "vec3 subgroupClusteredAdd(vec3, uint);\n" + "vec4 subgroupClusteredAdd(vec4, uint);\n" + "int subgroupClusteredAdd(int, uint);\n" + "ivec2 subgroupClusteredAdd(ivec2, uint);\n" + "ivec3 subgroupClusteredAdd(ivec3, uint);\n" + "ivec4 subgroupClusteredAdd(ivec4, uint);\n" + "uint subgroupClusteredAdd(uint, uint);\n" + "uvec2 subgroupClusteredAdd(uvec2, uint);\n" + "uvec3 subgroupClusteredAdd(uvec3, uint);\n" + "uvec4 subgroupClusteredAdd(uvec4, uint);\n" + + "float subgroupClusteredMul(float, uint);\n" + "vec2 subgroupClusteredMul(vec2, uint);\n" + "vec3 subgroupClusteredMul(vec3, uint);\n" + "vec4 subgroupClusteredMul(vec4, uint);\n" + "int subgroupClusteredMul(int, uint);\n" + "ivec2 subgroupClusteredMul(ivec2, uint);\n" + "ivec3 subgroupClusteredMul(ivec3, uint);\n" + "ivec4 subgroupClusteredMul(ivec4, uint);\n" + "uint subgroupClusteredMul(uint, uint);\n" + "uvec2 subgroupClusteredMul(uvec2, uint);\n" + "uvec3 subgroupClusteredMul(uvec3, uint);\n" + "uvec4 subgroupClusteredMul(uvec4, uint);\n" + + "float subgroupClusteredMin(float, uint);\n" + "vec2 subgroupClusteredMin(vec2, uint);\n" + "vec3 subgroupClusteredMin(vec3, uint);\n" + "vec4 subgroupClusteredMin(vec4, uint);\n" + "int subgroupClusteredMin(int, uint);\n" + "ivec2 subgroupClusteredMin(ivec2, uint);\n" + "ivec3 subgroupClusteredMin(ivec3, uint);\n" + "ivec4 subgroupClusteredMin(ivec4, uint);\n" + "uint subgroupClusteredMin(uint, uint);\n" + "uvec2 subgroupClusteredMin(uvec2, uint);\n" + "uvec3 subgroupClusteredMin(uvec3, uint);\n" + "uvec4 subgroupClusteredMin(uvec4, uint);\n" + + "float subgroupClusteredMax(float, uint);\n" + "vec2 subgroupClusteredMax(vec2, uint);\n" + "vec3 subgroupClusteredMax(vec3, uint);\n" + "vec4 subgroupClusteredMax(vec4, uint);\n" + "int subgroupClusteredMax(int, uint);\n" + "ivec2 subgroupClusteredMax(ivec2, uint);\n" + "ivec3 subgroupClusteredMax(ivec3, uint);\n" + "ivec4 subgroupClusteredMax(ivec4, uint);\n" + "uint subgroupClusteredMax(uint, uint);\n" + "uvec2 subgroupClusteredMax(uvec2, uint);\n" + "uvec3 subgroupClusteredMax(uvec3, uint);\n" + "uvec4 subgroupClusteredMax(uvec4, uint);\n" + + "int subgroupClusteredAnd(int, uint);\n" + "ivec2 subgroupClusteredAnd(ivec2, uint);\n" + "ivec3 subgroupClusteredAnd(ivec3, uint);\n" + "ivec4 subgroupClusteredAnd(ivec4, uint);\n" + "uint subgroupClusteredAnd(uint, uint);\n" + "uvec2 subgroupClusteredAnd(uvec2, uint);\n" + "uvec3 subgroupClusteredAnd(uvec3, uint);\n" + "uvec4 subgroupClusteredAnd(uvec4, uint);\n" + "bool subgroupClusteredAnd(bool, uint);\n" + "bvec2 subgroupClusteredAnd(bvec2, uint);\n" + "bvec3 subgroupClusteredAnd(bvec3, uint);\n" + "bvec4 subgroupClusteredAnd(bvec4, uint);\n" + + "int subgroupClusteredOr(int, uint);\n" + "ivec2 subgroupClusteredOr(ivec2, uint);\n" + "ivec3 subgroupClusteredOr(ivec3, uint);\n" + "ivec4 subgroupClusteredOr(ivec4, uint);\n" + "uint subgroupClusteredOr(uint, uint);\n" + "uvec2 subgroupClusteredOr(uvec2, uint);\n" + "uvec3 subgroupClusteredOr(uvec3, uint);\n" + "uvec4 subgroupClusteredOr(uvec4, uint);\n" + "bool subgroupClusteredOr(bool, uint);\n" + "bvec2 subgroupClusteredOr(bvec2, uint);\n" + "bvec3 subgroupClusteredOr(bvec3, uint);\n" + "bvec4 subgroupClusteredOr(bvec4, uint);\n" + + "int subgroupClusteredXor(int, uint);\n" + "ivec2 subgroupClusteredXor(ivec2, uint);\n" + "ivec3 subgroupClusteredXor(ivec3, uint);\n" + "ivec4 subgroupClusteredXor(ivec4, uint);\n" + "uint subgroupClusteredXor(uint, uint);\n" + "uvec2 subgroupClusteredXor(uvec2, uint);\n" + "uvec3 subgroupClusteredXor(uvec3, uint);\n" + "uvec4 subgroupClusteredXor(uvec4, uint);\n" + "bool subgroupClusteredXor(bool, uint);\n" + "bvec2 subgroupClusteredXor(bvec2, uint);\n" + "bvec3 subgroupClusteredXor(bvec3, uint);\n" + "bvec4 subgroupClusteredXor(bvec4, uint);\n" + + "float subgroupQuadBroadcast(float, uint);\n" + "vec2 subgroupQuadBroadcast(vec2, uint);\n" + "vec3 subgroupQuadBroadcast(vec3, uint);\n" + "vec4 subgroupQuadBroadcast(vec4, uint);\n" + "int subgroupQuadBroadcast(int, uint);\n" + "ivec2 subgroupQuadBroadcast(ivec2, uint);\n" + "ivec3 subgroupQuadBroadcast(ivec3, uint);\n" + "ivec4 subgroupQuadBroadcast(ivec4, uint);\n" + "uint subgroupQuadBroadcast(uint, uint);\n" + "uvec2 subgroupQuadBroadcast(uvec2, uint);\n" + "uvec3 subgroupQuadBroadcast(uvec3, uint);\n" + "uvec4 subgroupQuadBroadcast(uvec4, uint);\n" + "bool subgroupQuadBroadcast(bool, uint);\n" + "bvec2 subgroupQuadBroadcast(bvec2, uint);\n" + "bvec3 subgroupQuadBroadcast(bvec3, uint);\n" + "bvec4 subgroupQuadBroadcast(bvec4, uint);\n" + + "float subgroupQuadSwapHorizontal(float);\n" + "vec2 subgroupQuadSwapHorizontal(vec2);\n" + "vec3 subgroupQuadSwapHorizontal(vec3);\n" + "vec4 subgroupQuadSwapHorizontal(vec4);\n" + "int subgroupQuadSwapHorizontal(int);\n" + "ivec2 subgroupQuadSwapHorizontal(ivec2);\n" + "ivec3 subgroupQuadSwapHorizontal(ivec3);\n" + "ivec4 subgroupQuadSwapHorizontal(ivec4);\n" + "uint subgroupQuadSwapHorizontal(uint);\n" + "uvec2 subgroupQuadSwapHorizontal(uvec2);\n" + "uvec3 subgroupQuadSwapHorizontal(uvec3);\n" + "uvec4 subgroupQuadSwapHorizontal(uvec4);\n" + "bool subgroupQuadSwapHorizontal(bool);\n" + "bvec2 subgroupQuadSwapHorizontal(bvec2);\n" + "bvec3 subgroupQuadSwapHorizontal(bvec3);\n" + "bvec4 subgroupQuadSwapHorizontal(bvec4);\n" + + "float subgroupQuadSwapVertical(float);\n" + "vec2 subgroupQuadSwapVertical(vec2);\n" + "vec3 subgroupQuadSwapVertical(vec3);\n" + "vec4 subgroupQuadSwapVertical(vec4);\n" + "int subgroupQuadSwapVertical(int);\n" + "ivec2 subgroupQuadSwapVertical(ivec2);\n" + "ivec3 subgroupQuadSwapVertical(ivec3);\n" + "ivec4 subgroupQuadSwapVertical(ivec4);\n" + "uint subgroupQuadSwapVertical(uint);\n" + "uvec2 subgroupQuadSwapVertical(uvec2);\n" + "uvec3 subgroupQuadSwapVertical(uvec3);\n" + "uvec4 subgroupQuadSwapVertical(uvec4);\n" + "bool subgroupQuadSwapVertical(bool);\n" + "bvec2 subgroupQuadSwapVertical(bvec2);\n" + "bvec3 subgroupQuadSwapVertical(bvec3);\n" + "bvec4 subgroupQuadSwapVertical(bvec4);\n" + + "float subgroupQuadSwapDiagonal(float);\n" + "vec2 subgroupQuadSwapDiagonal(vec2);\n" + "vec3 subgroupQuadSwapDiagonal(vec3);\n" + "vec4 subgroupQuadSwapDiagonal(vec4);\n" + "int subgroupQuadSwapDiagonal(int);\n" + "ivec2 subgroupQuadSwapDiagonal(ivec2);\n" + "ivec3 subgroupQuadSwapDiagonal(ivec3);\n" + "ivec4 subgroupQuadSwapDiagonal(ivec4);\n" + "uint subgroupQuadSwapDiagonal(uint);\n" + "uvec2 subgroupQuadSwapDiagonal(uvec2);\n" + "uvec3 subgroupQuadSwapDiagonal(uvec3);\n" + "uvec4 subgroupQuadSwapDiagonal(uvec4);\n" + "bool subgroupQuadSwapDiagonal(bool);\n" + "bvec2 subgroupQuadSwapDiagonal(bvec2);\n" + "bvec3 subgroupQuadSwapDiagonal(bvec3);\n" + "bvec4 subgroupQuadSwapDiagonal(bvec4);\n" + +#ifdef NV_EXTENSIONS + "uvec4 subgroupPartitionNV(float);\n" + "uvec4 subgroupPartitionNV(vec2);\n" + "uvec4 subgroupPartitionNV(vec3);\n" + "uvec4 subgroupPartitionNV(vec4);\n" + "uvec4 subgroupPartitionNV(int);\n" + "uvec4 subgroupPartitionNV(ivec2);\n" + "uvec4 subgroupPartitionNV(ivec3);\n" + "uvec4 subgroupPartitionNV(ivec4);\n" + "uvec4 subgroupPartitionNV(uint);\n" + "uvec4 subgroupPartitionNV(uvec2);\n" + "uvec4 subgroupPartitionNV(uvec3);\n" + "uvec4 subgroupPartitionNV(uvec4);\n" + "uvec4 subgroupPartitionNV(bool);\n" + "uvec4 subgroupPartitionNV(bvec2);\n" + "uvec4 subgroupPartitionNV(bvec3);\n" + "uvec4 subgroupPartitionNV(bvec4);\n" + + "float subgroupPartitionedAddNV(float, uvec4 ballot);\n" + "vec2 subgroupPartitionedAddNV(vec2, uvec4 ballot);\n" + "vec3 subgroupPartitionedAddNV(vec3, uvec4 ballot);\n" + "vec4 subgroupPartitionedAddNV(vec4, uvec4 ballot);\n" + "int subgroupPartitionedAddNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedAddNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedAddNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedAddNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedAddNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedAddNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedAddNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedAddNV(uvec4, uvec4 ballot);\n" + + "float subgroupPartitionedMulNV(float, uvec4 ballot);\n" + "vec2 subgroupPartitionedMulNV(vec2, uvec4 ballot);\n" + "vec3 subgroupPartitionedMulNV(vec3, uvec4 ballot);\n" + "vec4 subgroupPartitionedMulNV(vec4, uvec4 ballot);\n" + "int subgroupPartitionedMulNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedMulNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedMulNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedMulNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedMulNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedMulNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedMulNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedMulNV(uvec4, uvec4 ballot);\n" + + "float subgroupPartitionedMinNV(float, uvec4 ballot);\n" + "vec2 subgroupPartitionedMinNV(vec2, uvec4 ballot);\n" + "vec3 subgroupPartitionedMinNV(vec3, uvec4 ballot);\n" + "vec4 subgroupPartitionedMinNV(vec4, uvec4 ballot);\n" + "int subgroupPartitionedMinNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedMinNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedMinNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedMinNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedMinNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedMinNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedMinNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedMinNV(uvec4, uvec4 ballot);\n" + + "float subgroupPartitionedMaxNV(float, uvec4 ballot);\n" + "vec2 subgroupPartitionedMaxNV(vec2, uvec4 ballot);\n" + "vec3 subgroupPartitionedMaxNV(vec3, uvec4 ballot);\n" + "vec4 subgroupPartitionedMaxNV(vec4, uvec4 ballot);\n" + "int subgroupPartitionedMaxNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedMaxNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedMaxNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedMaxNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedMaxNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedMaxNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedMaxNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedMaxNV(uvec4, uvec4 ballot);\n" + + "int subgroupPartitionedAndNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedAndNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedAndNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedAndNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedAndNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedAndNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedAndNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedAndNV(uvec4, uvec4 ballot);\n" + "bool subgroupPartitionedAndNV(bool, uvec4 ballot);\n" + "bvec2 subgroupPartitionedAndNV(bvec2, uvec4 ballot);\n" + "bvec3 subgroupPartitionedAndNV(bvec3, uvec4 ballot);\n" + "bvec4 subgroupPartitionedAndNV(bvec4, uvec4 ballot);\n" + + "int subgroupPartitionedOrNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedOrNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedOrNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedOrNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedOrNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedOrNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedOrNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedOrNV(uvec4, uvec4 ballot);\n" + "bool subgroupPartitionedOrNV(bool, uvec4 ballot);\n" + "bvec2 subgroupPartitionedOrNV(bvec2, uvec4 ballot);\n" + "bvec3 subgroupPartitionedOrNV(bvec3, uvec4 ballot);\n" + "bvec4 subgroupPartitionedOrNV(bvec4, uvec4 ballot);\n" + + "int subgroupPartitionedXorNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedXorNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedXorNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedXorNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedXorNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedXorNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedXorNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedXorNV(uvec4, uvec4 ballot);\n" + "bool subgroupPartitionedXorNV(bool, uvec4 ballot);\n" + "bvec2 subgroupPartitionedXorNV(bvec2, uvec4 ballot);\n" + "bvec3 subgroupPartitionedXorNV(bvec3, uvec4 ballot);\n" + "bvec4 subgroupPartitionedXorNV(bvec4, uvec4 ballot);\n" + + "float subgroupPartitionedInclusiveAddNV(float, uvec4 ballot);\n" + "vec2 subgroupPartitionedInclusiveAddNV(vec2, uvec4 ballot);\n" + "vec3 subgroupPartitionedInclusiveAddNV(vec3, uvec4 ballot);\n" + "vec4 subgroupPartitionedInclusiveAddNV(vec4, uvec4 ballot);\n" + "int subgroupPartitionedInclusiveAddNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedInclusiveAddNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedInclusiveAddNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedInclusiveAddNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedInclusiveAddNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedInclusiveAddNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedInclusiveAddNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedInclusiveAddNV(uvec4, uvec4 ballot);\n" + + "float subgroupPartitionedInclusiveMulNV(float, uvec4 ballot);\n" + "vec2 subgroupPartitionedInclusiveMulNV(vec2, uvec4 ballot);\n" + "vec3 subgroupPartitionedInclusiveMulNV(vec3, uvec4 ballot);\n" + "vec4 subgroupPartitionedInclusiveMulNV(vec4, uvec4 ballot);\n" + "int subgroupPartitionedInclusiveMulNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedInclusiveMulNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedInclusiveMulNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedInclusiveMulNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedInclusiveMulNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedInclusiveMulNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedInclusiveMulNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedInclusiveMulNV(uvec4, uvec4 ballot);\n" + + "float subgroupPartitionedInclusiveMinNV(float, uvec4 ballot);\n" + "vec2 subgroupPartitionedInclusiveMinNV(vec2, uvec4 ballot);\n" + "vec3 subgroupPartitionedInclusiveMinNV(vec3, uvec4 ballot);\n" + "vec4 subgroupPartitionedInclusiveMinNV(vec4, uvec4 ballot);\n" + "int subgroupPartitionedInclusiveMinNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedInclusiveMinNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedInclusiveMinNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedInclusiveMinNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedInclusiveMinNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedInclusiveMinNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedInclusiveMinNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedInclusiveMinNV(uvec4, uvec4 ballot);\n" + + "float subgroupPartitionedInclusiveMaxNV(float, uvec4 ballot);\n" + "vec2 subgroupPartitionedInclusiveMaxNV(vec2, uvec4 ballot);\n" + "vec3 subgroupPartitionedInclusiveMaxNV(vec3, uvec4 ballot);\n" + "vec4 subgroupPartitionedInclusiveMaxNV(vec4, uvec4 ballot);\n" + "int subgroupPartitionedInclusiveMaxNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedInclusiveMaxNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedInclusiveMaxNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedInclusiveMaxNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedInclusiveMaxNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedInclusiveMaxNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedInclusiveMaxNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedInclusiveMaxNV(uvec4, uvec4 ballot);\n" + + "int subgroupPartitionedInclusiveAndNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedInclusiveAndNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedInclusiveAndNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedInclusiveAndNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedInclusiveAndNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedInclusiveAndNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedInclusiveAndNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedInclusiveAndNV(uvec4, uvec4 ballot);\n" + "bool subgroupPartitionedInclusiveAndNV(bool, uvec4 ballot);\n" + "bvec2 subgroupPartitionedInclusiveAndNV(bvec2, uvec4 ballot);\n" + "bvec3 subgroupPartitionedInclusiveAndNV(bvec3, uvec4 ballot);\n" + "bvec4 subgroupPartitionedInclusiveAndNV(bvec4, uvec4 ballot);\n" + + "int subgroupPartitionedInclusiveOrNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedInclusiveOrNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedInclusiveOrNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedInclusiveOrNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedInclusiveOrNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedInclusiveOrNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedInclusiveOrNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedInclusiveOrNV(uvec4, uvec4 ballot);\n" + "bool subgroupPartitionedInclusiveOrNV(bool, uvec4 ballot);\n" + "bvec2 subgroupPartitionedInclusiveOrNV(bvec2, uvec4 ballot);\n" + "bvec3 subgroupPartitionedInclusiveOrNV(bvec3, uvec4 ballot);\n" + "bvec4 subgroupPartitionedInclusiveOrNV(bvec4, uvec4 ballot);\n" + + "int subgroupPartitionedInclusiveXorNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedInclusiveXorNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedInclusiveXorNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedInclusiveXorNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedInclusiveXorNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedInclusiveXorNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedInclusiveXorNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedInclusiveXorNV(uvec4, uvec4 ballot);\n" + "bool subgroupPartitionedInclusiveXorNV(bool, uvec4 ballot);\n" + "bvec2 subgroupPartitionedInclusiveXorNV(bvec2, uvec4 ballot);\n" + "bvec3 subgroupPartitionedInclusiveXorNV(bvec3, uvec4 ballot);\n" + "bvec4 subgroupPartitionedInclusiveXorNV(bvec4, uvec4 ballot);\n" + + "float subgroupPartitionedExclusiveAddNV(float, uvec4 ballot);\n" + "vec2 subgroupPartitionedExclusiveAddNV(vec2, uvec4 ballot);\n" + "vec3 subgroupPartitionedExclusiveAddNV(vec3, uvec4 ballot);\n" + "vec4 subgroupPartitionedExclusiveAddNV(vec4, uvec4 ballot);\n" + "int subgroupPartitionedExclusiveAddNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedExclusiveAddNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedExclusiveAddNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedExclusiveAddNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedExclusiveAddNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedExclusiveAddNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedExclusiveAddNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedExclusiveAddNV(uvec4, uvec4 ballot);\n" + + "float subgroupPartitionedExclusiveMulNV(float, uvec4 ballot);\n" + "vec2 subgroupPartitionedExclusiveMulNV(vec2, uvec4 ballot);\n" + "vec3 subgroupPartitionedExclusiveMulNV(vec3, uvec4 ballot);\n" + "vec4 subgroupPartitionedExclusiveMulNV(vec4, uvec4 ballot);\n" + "int subgroupPartitionedExclusiveMulNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedExclusiveMulNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedExclusiveMulNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedExclusiveMulNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedExclusiveMulNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedExclusiveMulNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedExclusiveMulNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedExclusiveMulNV(uvec4, uvec4 ballot);\n" + + "float subgroupPartitionedExclusiveMinNV(float, uvec4 ballot);\n" + "vec2 subgroupPartitionedExclusiveMinNV(vec2, uvec4 ballot);\n" + "vec3 subgroupPartitionedExclusiveMinNV(vec3, uvec4 ballot);\n" + "vec4 subgroupPartitionedExclusiveMinNV(vec4, uvec4 ballot);\n" + "int subgroupPartitionedExclusiveMinNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedExclusiveMinNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedExclusiveMinNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedExclusiveMinNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedExclusiveMinNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedExclusiveMinNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedExclusiveMinNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedExclusiveMinNV(uvec4, uvec4 ballot);\n" + + "float subgroupPartitionedExclusiveMaxNV(float, uvec4 ballot);\n" + "vec2 subgroupPartitionedExclusiveMaxNV(vec2, uvec4 ballot);\n" + "vec3 subgroupPartitionedExclusiveMaxNV(vec3, uvec4 ballot);\n" + "vec4 subgroupPartitionedExclusiveMaxNV(vec4, uvec4 ballot);\n" + "int subgroupPartitionedExclusiveMaxNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedExclusiveMaxNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedExclusiveMaxNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedExclusiveMaxNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedExclusiveMaxNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedExclusiveMaxNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedExclusiveMaxNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedExclusiveMaxNV(uvec4, uvec4 ballot);\n" + + "int subgroupPartitionedExclusiveAndNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedExclusiveAndNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedExclusiveAndNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedExclusiveAndNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedExclusiveAndNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedExclusiveAndNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedExclusiveAndNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedExclusiveAndNV(uvec4, uvec4 ballot);\n" + "bool subgroupPartitionedExclusiveAndNV(bool, uvec4 ballot);\n" + "bvec2 subgroupPartitionedExclusiveAndNV(bvec2, uvec4 ballot);\n" + "bvec3 subgroupPartitionedExclusiveAndNV(bvec3, uvec4 ballot);\n" + "bvec4 subgroupPartitionedExclusiveAndNV(bvec4, uvec4 ballot);\n" + + "int subgroupPartitionedExclusiveOrNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedExclusiveOrNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedExclusiveOrNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedExclusiveOrNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedExclusiveOrNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedExclusiveOrNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedExclusiveOrNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedExclusiveOrNV(uvec4, uvec4 ballot);\n" + "bool subgroupPartitionedExclusiveOrNV(bool, uvec4 ballot);\n" + "bvec2 subgroupPartitionedExclusiveOrNV(bvec2, uvec4 ballot);\n" + "bvec3 subgroupPartitionedExclusiveOrNV(bvec3, uvec4 ballot);\n" + "bvec4 subgroupPartitionedExclusiveOrNV(bvec4, uvec4 ballot);\n" + + "int subgroupPartitionedExclusiveXorNV(int, uvec4 ballot);\n" + "ivec2 subgroupPartitionedExclusiveXorNV(ivec2, uvec4 ballot);\n" + "ivec3 subgroupPartitionedExclusiveXorNV(ivec3, uvec4 ballot);\n" + "ivec4 subgroupPartitionedExclusiveXorNV(ivec4, uvec4 ballot);\n" + "uint subgroupPartitionedExclusiveXorNV(uint, uvec4 ballot);\n" + "uvec2 subgroupPartitionedExclusiveXorNV(uvec2, uvec4 ballot);\n" + "uvec3 subgroupPartitionedExclusiveXorNV(uvec3, uvec4 ballot);\n" + "uvec4 subgroupPartitionedExclusiveXorNV(uvec4, uvec4 ballot);\n" + "bool subgroupPartitionedExclusiveXorNV(bool, uvec4 ballot);\n" + "bvec2 subgroupPartitionedExclusiveXorNV(bvec2, uvec4 ballot);\n" + "bvec3 subgroupPartitionedExclusiveXorNV(bvec3, uvec4 ballot);\n" + "bvec4 subgroupPartitionedExclusiveXorNV(bvec4, uvec4 ballot);\n" +#endif + + "\n"); + + if (profile != EEsProfile && version >= 400) { + commonBuiltins.append( + "bool subgroupAllEqual(double);\n" + "bool subgroupAllEqual(dvec2);\n" + "bool subgroupAllEqual(dvec3);\n" + "bool subgroupAllEqual(dvec4);\n" + + "double subgroupBroadcast(double, uint);\n" + "dvec2 subgroupBroadcast(dvec2, uint);\n" + "dvec3 subgroupBroadcast(dvec3, uint);\n" + "dvec4 subgroupBroadcast(dvec4, uint);\n" + + "double subgroupBroadcastFirst(double);\n" + "dvec2 subgroupBroadcastFirst(dvec2);\n" + "dvec3 subgroupBroadcastFirst(dvec3);\n" + "dvec4 subgroupBroadcastFirst(dvec4);\n" + + "double subgroupShuffle(double, uint);\n" + "dvec2 subgroupShuffle(dvec2, uint);\n" + "dvec3 subgroupShuffle(dvec3, uint);\n" + "dvec4 subgroupShuffle(dvec4, uint);\n" + + "double subgroupShuffleXor(double, uint);\n" + "dvec2 subgroupShuffleXor(dvec2, uint);\n" + "dvec3 subgroupShuffleXor(dvec3, uint);\n" + "dvec4 subgroupShuffleXor(dvec4, uint);\n" + + "double subgroupShuffleUp(double, uint delta);\n" + "dvec2 subgroupShuffleUp(dvec2, uint delta);\n" + "dvec3 subgroupShuffleUp(dvec3, uint delta);\n" + "dvec4 subgroupShuffleUp(dvec4, uint delta);\n" + + "double subgroupShuffleDown(double, uint delta);\n" + "dvec2 subgroupShuffleDown(dvec2, uint delta);\n" + "dvec3 subgroupShuffleDown(dvec3, uint delta);\n" + "dvec4 subgroupShuffleDown(dvec4, uint delta);\n" + + "double subgroupAdd(double);\n" + "dvec2 subgroupAdd(dvec2);\n" + "dvec3 subgroupAdd(dvec3);\n" + "dvec4 subgroupAdd(dvec4);\n" + + "double subgroupMul(double);\n" + "dvec2 subgroupMul(dvec2);\n" + "dvec3 subgroupMul(dvec3);\n" + "dvec4 subgroupMul(dvec4);\n" + + "double subgroupMin(double);\n" + "dvec2 subgroupMin(dvec2);\n" + "dvec3 subgroupMin(dvec3);\n" + "dvec4 subgroupMin(dvec4);\n" + + "double subgroupMax(double);\n" + "dvec2 subgroupMax(dvec2);\n" + "dvec3 subgroupMax(dvec3);\n" + "dvec4 subgroupMax(dvec4);\n" + + "double subgroupInclusiveAdd(double);\n" + "dvec2 subgroupInclusiveAdd(dvec2);\n" + "dvec3 subgroupInclusiveAdd(dvec3);\n" + "dvec4 subgroupInclusiveAdd(dvec4);\n" + + "double subgroupInclusiveMul(double);\n" + "dvec2 subgroupInclusiveMul(dvec2);\n" + "dvec3 subgroupInclusiveMul(dvec3);\n" + "dvec4 subgroupInclusiveMul(dvec4);\n" + + "double subgroupInclusiveMin(double);\n" + "dvec2 subgroupInclusiveMin(dvec2);\n" + "dvec3 subgroupInclusiveMin(dvec3);\n" + "dvec4 subgroupInclusiveMin(dvec4);\n" + + "double subgroupInclusiveMax(double);\n" + "dvec2 subgroupInclusiveMax(dvec2);\n" + "dvec3 subgroupInclusiveMax(dvec3);\n" + "dvec4 subgroupInclusiveMax(dvec4);\n" + + "double subgroupExclusiveAdd(double);\n" + "dvec2 subgroupExclusiveAdd(dvec2);\n" + "dvec3 subgroupExclusiveAdd(dvec3);\n" + "dvec4 subgroupExclusiveAdd(dvec4);\n" + + "double subgroupExclusiveMul(double);\n" + "dvec2 subgroupExclusiveMul(dvec2);\n" + "dvec3 subgroupExclusiveMul(dvec3);\n" + "dvec4 subgroupExclusiveMul(dvec4);\n" + + "double subgroupExclusiveMin(double);\n" + "dvec2 subgroupExclusiveMin(dvec2);\n" + "dvec3 subgroupExclusiveMin(dvec3);\n" + "dvec4 subgroupExclusiveMin(dvec4);\n" + + "double subgroupExclusiveMax(double);\n" + "dvec2 subgroupExclusiveMax(dvec2);\n" + "dvec3 subgroupExclusiveMax(dvec3);\n" + "dvec4 subgroupExclusiveMax(dvec4);\n" + + "double subgroupClusteredAdd(double, uint);\n" + "dvec2 subgroupClusteredAdd(dvec2, uint);\n" + "dvec3 subgroupClusteredAdd(dvec3, uint);\n" + "dvec4 subgroupClusteredAdd(dvec4, uint);\n" + + "double subgroupClusteredMul(double, uint);\n" + "dvec2 subgroupClusteredMul(dvec2, uint);\n" + "dvec3 subgroupClusteredMul(dvec3, uint);\n" + "dvec4 subgroupClusteredMul(dvec4, uint);\n" + + "double subgroupClusteredMin(double, uint);\n" + "dvec2 subgroupClusteredMin(dvec2, uint);\n" + "dvec3 subgroupClusteredMin(dvec3, uint);\n" + "dvec4 subgroupClusteredMin(dvec4, uint);\n" + + "double subgroupClusteredMax(double, uint);\n" + "dvec2 subgroupClusteredMax(dvec2, uint);\n" + "dvec3 subgroupClusteredMax(dvec3, uint);\n" + "dvec4 subgroupClusteredMax(dvec4, uint);\n" + + "double subgroupQuadBroadcast(double, uint);\n" + "dvec2 subgroupQuadBroadcast(dvec2, uint);\n" + "dvec3 subgroupQuadBroadcast(dvec3, uint);\n" + "dvec4 subgroupQuadBroadcast(dvec4, uint);\n" + + "double subgroupQuadSwapHorizontal(double);\n" + "dvec2 subgroupQuadSwapHorizontal(dvec2);\n" + "dvec3 subgroupQuadSwapHorizontal(dvec3);\n" + "dvec4 subgroupQuadSwapHorizontal(dvec4);\n" + + "double subgroupQuadSwapVertical(double);\n" + "dvec2 subgroupQuadSwapVertical(dvec2);\n" + "dvec3 subgroupQuadSwapVertical(dvec3);\n" + "dvec4 subgroupQuadSwapVertical(dvec4);\n" + + "double subgroupQuadSwapDiagonal(double);\n" + "dvec2 subgroupQuadSwapDiagonal(dvec2);\n" + "dvec3 subgroupQuadSwapDiagonal(dvec3);\n" + "dvec4 subgroupQuadSwapDiagonal(dvec4);\n" + + +#ifdef NV_EXTENSIONS + "uvec4 subgroupPartitionNV(double);\n" + "uvec4 subgroupPartitionNV(dvec2);\n" + "uvec4 subgroupPartitionNV(dvec3);\n" + "uvec4 subgroupPartitionNV(dvec4);\n" + + "double subgroupPartitionedAddNV(double, uvec4 ballot);\n" + "dvec2 subgroupPartitionedAddNV(dvec2, uvec4 ballot);\n" + "dvec3 subgroupPartitionedAddNV(dvec3, uvec4 ballot);\n" + "dvec4 subgroupPartitionedAddNV(dvec4, uvec4 ballot);\n" + + "double subgroupPartitionedMulNV(double, uvec4 ballot);\n" + "dvec2 subgroupPartitionedMulNV(dvec2, uvec4 ballot);\n" + "dvec3 subgroupPartitionedMulNV(dvec3, uvec4 ballot);\n" + "dvec4 subgroupPartitionedMulNV(dvec4, uvec4 ballot);\n" + + "double subgroupPartitionedMinNV(double, uvec4 ballot);\n" + "dvec2 subgroupPartitionedMinNV(dvec2, uvec4 ballot);\n" + "dvec3 subgroupPartitionedMinNV(dvec3, uvec4 ballot);\n" + "dvec4 subgroupPartitionedMinNV(dvec4, uvec4 ballot);\n" + + "double subgroupPartitionedMaxNV(double, uvec4 ballot);\n" + "dvec2 subgroupPartitionedMaxNV(dvec2, uvec4 ballot);\n" + "dvec3 subgroupPartitionedMaxNV(dvec3, uvec4 ballot);\n" + "dvec4 subgroupPartitionedMaxNV(dvec4, uvec4 ballot);\n" + + "double subgroupPartitionedInclusiveAddNV(double, uvec4 ballot);\n" + "dvec2 subgroupPartitionedInclusiveAddNV(dvec2, uvec4 ballot);\n" + "dvec3 subgroupPartitionedInclusiveAddNV(dvec3, uvec4 ballot);\n" + "dvec4 subgroupPartitionedInclusiveAddNV(dvec4, uvec4 ballot);\n" + + "double subgroupPartitionedInclusiveMulNV(double, uvec4 ballot);\n" + "dvec2 subgroupPartitionedInclusiveMulNV(dvec2, uvec4 ballot);\n" + "dvec3 subgroupPartitionedInclusiveMulNV(dvec3, uvec4 ballot);\n" + "dvec4 subgroupPartitionedInclusiveMulNV(dvec4, uvec4 ballot);\n" + + "double subgroupPartitionedInclusiveMinNV(double, uvec4 ballot);\n" + "dvec2 subgroupPartitionedInclusiveMinNV(dvec2, uvec4 ballot);\n" + "dvec3 subgroupPartitionedInclusiveMinNV(dvec3, uvec4 ballot);\n" + "dvec4 subgroupPartitionedInclusiveMinNV(dvec4, uvec4 ballot);\n" + + "double subgroupPartitionedInclusiveMaxNV(double, uvec4 ballot);\n" + "dvec2 subgroupPartitionedInclusiveMaxNV(dvec2, uvec4 ballot);\n" + "dvec3 subgroupPartitionedInclusiveMaxNV(dvec3, uvec4 ballot);\n" + "dvec4 subgroupPartitionedInclusiveMaxNV(dvec4, uvec4 ballot);\n" + + "double subgroupPartitionedExclusiveAddNV(double, uvec4 ballot);\n" + "dvec2 subgroupPartitionedExclusiveAddNV(dvec2, uvec4 ballot);\n" + "dvec3 subgroupPartitionedExclusiveAddNV(dvec3, uvec4 ballot);\n" + "dvec4 subgroupPartitionedExclusiveAddNV(dvec4, uvec4 ballot);\n" + + "double subgroupPartitionedExclusiveMulNV(double, uvec4 ballot);\n" + "dvec2 subgroupPartitionedExclusiveMulNV(dvec2, uvec4 ballot);\n" + "dvec3 subgroupPartitionedExclusiveMulNV(dvec3, uvec4 ballot);\n" + "dvec4 subgroupPartitionedExclusiveMulNV(dvec4, uvec4 ballot);\n" + + "double subgroupPartitionedExclusiveMinNV(double, uvec4 ballot);\n" + "dvec2 subgroupPartitionedExclusiveMinNV(dvec2, uvec4 ballot);\n" + "dvec3 subgroupPartitionedExclusiveMinNV(dvec3, uvec4 ballot);\n" + "dvec4 subgroupPartitionedExclusiveMinNV(dvec4, uvec4 ballot);\n" + + "double subgroupPartitionedExclusiveMaxNV(double, uvec4 ballot);\n" + "dvec2 subgroupPartitionedExclusiveMaxNV(dvec2, uvec4 ballot);\n" + "dvec3 subgroupPartitionedExclusiveMaxNV(dvec3, uvec4 ballot);\n" + "dvec4 subgroupPartitionedExclusiveMaxNV(dvec4, uvec4 ballot);\n" +#endif + + "\n"); + } + + stageBuiltins[EShLangCompute].append( + "void subgroupMemoryBarrierShared();" + + "\n" + ); + } + + if (profile != EEsProfile && version >= 460) { + commonBuiltins.append( + "bool anyInvocation(bool);" + "bool allInvocations(bool);" + "bool allInvocationsEqual(bool);" + + "\n"); + } + +#ifdef AMD_EXTENSIONS + // GL_AMD_shader_ballot + if (profile != EEsProfile && version >= 450) { + commonBuiltins.append( + "float minInvocationsAMD(float);" + "vec2 minInvocationsAMD(vec2);" + "vec3 minInvocationsAMD(vec3);" + "vec4 minInvocationsAMD(vec4);" + + "int minInvocationsAMD(int);" + "ivec2 minInvocationsAMD(ivec2);" + "ivec3 minInvocationsAMD(ivec3);" + "ivec4 minInvocationsAMD(ivec4);" + + "uint minInvocationsAMD(uint);" + "uvec2 minInvocationsAMD(uvec2);" + "uvec3 minInvocationsAMD(uvec3);" + "uvec4 minInvocationsAMD(uvec4);" + + "double minInvocationsAMD(double);" + "dvec2 minInvocationsAMD(dvec2);" + "dvec3 minInvocationsAMD(dvec3);" + "dvec4 minInvocationsAMD(dvec4);" + + "int64_t minInvocationsAMD(int64_t);" + "i64vec2 minInvocationsAMD(i64vec2);" + "i64vec3 minInvocationsAMD(i64vec3);" + "i64vec4 minInvocationsAMD(i64vec4);" + + "uint64_t minInvocationsAMD(uint64_t);" + "u64vec2 minInvocationsAMD(u64vec2);" + "u64vec3 minInvocationsAMD(u64vec3);" + "u64vec4 minInvocationsAMD(u64vec4);" + + "float16_t minInvocationsAMD(float16_t);" + "f16vec2 minInvocationsAMD(f16vec2);" + "f16vec3 minInvocationsAMD(f16vec3);" + "f16vec4 minInvocationsAMD(f16vec4);" + + "int16_t minInvocationsAMD(int16_t);" + "i16vec2 minInvocationsAMD(i16vec2);" + "i16vec3 minInvocationsAMD(i16vec3);" + "i16vec4 minInvocationsAMD(i16vec4);" + + "uint16_t minInvocationsAMD(uint16_t);" + "u16vec2 minInvocationsAMD(u16vec2);" + "u16vec3 minInvocationsAMD(u16vec3);" + "u16vec4 minInvocationsAMD(u16vec4);" + + "float minInvocationsInclusiveScanAMD(float);" + "vec2 minInvocationsInclusiveScanAMD(vec2);" + "vec3 minInvocationsInclusiveScanAMD(vec3);" + "vec4 minInvocationsInclusiveScanAMD(vec4);" + + "int minInvocationsInclusiveScanAMD(int);" + "ivec2 minInvocationsInclusiveScanAMD(ivec2);" + "ivec3 minInvocationsInclusiveScanAMD(ivec3);" + "ivec4 minInvocationsInclusiveScanAMD(ivec4);" + + "uint minInvocationsInclusiveScanAMD(uint);" + "uvec2 minInvocationsInclusiveScanAMD(uvec2);" + "uvec3 minInvocationsInclusiveScanAMD(uvec3);" + "uvec4 minInvocationsInclusiveScanAMD(uvec4);" + + "double minInvocationsInclusiveScanAMD(double);" + "dvec2 minInvocationsInclusiveScanAMD(dvec2);" + "dvec3 minInvocationsInclusiveScanAMD(dvec3);" + "dvec4 minInvocationsInclusiveScanAMD(dvec4);" + + "int64_t minInvocationsInclusiveScanAMD(int64_t);" + "i64vec2 minInvocationsInclusiveScanAMD(i64vec2);" + "i64vec3 minInvocationsInclusiveScanAMD(i64vec3);" + "i64vec4 minInvocationsInclusiveScanAMD(i64vec4);" + + "uint64_t minInvocationsInclusiveScanAMD(uint64_t);" + "u64vec2 minInvocationsInclusiveScanAMD(u64vec2);" + "u64vec3 minInvocationsInclusiveScanAMD(u64vec3);" + "u64vec4 minInvocationsInclusiveScanAMD(u64vec4);" + + "float16_t minInvocationsInclusiveScanAMD(float16_t);" + "f16vec2 minInvocationsInclusiveScanAMD(f16vec2);" + "f16vec3 minInvocationsInclusiveScanAMD(f16vec3);" + "f16vec4 minInvocationsInclusiveScanAMD(f16vec4);" + + "int16_t minInvocationsInclusiveScanAMD(int16_t);" + "i16vec2 minInvocationsInclusiveScanAMD(i16vec2);" + "i16vec3 minInvocationsInclusiveScanAMD(i16vec3);" + "i16vec4 minInvocationsInclusiveScanAMD(i16vec4);" + + "uint16_t minInvocationsInclusiveScanAMD(uint16_t);" + "u16vec2 minInvocationsInclusiveScanAMD(u16vec2);" + "u16vec3 minInvocationsInclusiveScanAMD(u16vec3);" + "u16vec4 minInvocationsInclusiveScanAMD(u16vec4);" + + "float minInvocationsExclusiveScanAMD(float);" + "vec2 minInvocationsExclusiveScanAMD(vec2);" + "vec3 minInvocationsExclusiveScanAMD(vec3);" + "vec4 minInvocationsExclusiveScanAMD(vec4);" + + "int minInvocationsExclusiveScanAMD(int);" + "ivec2 minInvocationsExclusiveScanAMD(ivec2);" + "ivec3 minInvocationsExclusiveScanAMD(ivec3);" + "ivec4 minInvocationsExclusiveScanAMD(ivec4);" + + "uint minInvocationsExclusiveScanAMD(uint);" + "uvec2 minInvocationsExclusiveScanAMD(uvec2);" + "uvec3 minInvocationsExclusiveScanAMD(uvec3);" + "uvec4 minInvocationsExclusiveScanAMD(uvec4);" + + "double minInvocationsExclusiveScanAMD(double);" + "dvec2 minInvocationsExclusiveScanAMD(dvec2);" + "dvec3 minInvocationsExclusiveScanAMD(dvec3);" + "dvec4 minInvocationsExclusiveScanAMD(dvec4);" + + "int64_t minInvocationsExclusiveScanAMD(int64_t);" + "i64vec2 minInvocationsExclusiveScanAMD(i64vec2);" + "i64vec3 minInvocationsExclusiveScanAMD(i64vec3);" + "i64vec4 minInvocationsExclusiveScanAMD(i64vec4);" + + "uint64_t minInvocationsExclusiveScanAMD(uint64_t);" + "u64vec2 minInvocationsExclusiveScanAMD(u64vec2);" + "u64vec3 minInvocationsExclusiveScanAMD(u64vec3);" + "u64vec4 minInvocationsExclusiveScanAMD(u64vec4);" + + "float16_t minInvocationsExclusiveScanAMD(float16_t);" + "f16vec2 minInvocationsExclusiveScanAMD(f16vec2);" + "f16vec3 minInvocationsExclusiveScanAMD(f16vec3);" + "f16vec4 minInvocationsExclusiveScanAMD(f16vec4);" + + "int16_t minInvocationsExclusiveScanAMD(int16_t);" + "i16vec2 minInvocationsExclusiveScanAMD(i16vec2);" + "i16vec3 minInvocationsExclusiveScanAMD(i16vec3);" + "i16vec4 minInvocationsExclusiveScanAMD(i16vec4);" + + "uint16_t minInvocationsExclusiveScanAMD(uint16_t);" + "u16vec2 minInvocationsExclusiveScanAMD(u16vec2);" + "u16vec3 minInvocationsExclusiveScanAMD(u16vec3);" + "u16vec4 minInvocationsExclusiveScanAMD(u16vec4);" + + "float maxInvocationsAMD(float);" + "vec2 maxInvocationsAMD(vec2);" + "vec3 maxInvocationsAMD(vec3);" + "vec4 maxInvocationsAMD(vec4);" + + "int maxInvocationsAMD(int);" + "ivec2 maxInvocationsAMD(ivec2);" + "ivec3 maxInvocationsAMD(ivec3);" + "ivec4 maxInvocationsAMD(ivec4);" + + "uint maxInvocationsAMD(uint);" + "uvec2 maxInvocationsAMD(uvec2);" + "uvec3 maxInvocationsAMD(uvec3);" + "uvec4 maxInvocationsAMD(uvec4);" + + "double maxInvocationsAMD(double);" + "dvec2 maxInvocationsAMD(dvec2);" + "dvec3 maxInvocationsAMD(dvec3);" + "dvec4 maxInvocationsAMD(dvec4);" + + "int64_t maxInvocationsAMD(int64_t);" + "i64vec2 maxInvocationsAMD(i64vec2);" + "i64vec3 maxInvocationsAMD(i64vec3);" + "i64vec4 maxInvocationsAMD(i64vec4);" + + "uint64_t maxInvocationsAMD(uint64_t);" + "u64vec2 maxInvocationsAMD(u64vec2);" + "u64vec3 maxInvocationsAMD(u64vec3);" + "u64vec4 maxInvocationsAMD(u64vec4);" + + "float16_t maxInvocationsAMD(float16_t);" + "f16vec2 maxInvocationsAMD(f16vec2);" + "f16vec3 maxInvocationsAMD(f16vec3);" + "f16vec4 maxInvocationsAMD(f16vec4);" + + "int16_t maxInvocationsAMD(int16_t);" + "i16vec2 maxInvocationsAMD(i16vec2);" + "i16vec3 maxInvocationsAMD(i16vec3);" + "i16vec4 maxInvocationsAMD(i16vec4);" + + "uint16_t maxInvocationsAMD(uint16_t);" + "u16vec2 maxInvocationsAMD(u16vec2);" + "u16vec3 maxInvocationsAMD(u16vec3);" + "u16vec4 maxInvocationsAMD(u16vec4);" + + "float maxInvocationsInclusiveScanAMD(float);" + "vec2 maxInvocationsInclusiveScanAMD(vec2);" + "vec3 maxInvocationsInclusiveScanAMD(vec3);" + "vec4 maxInvocationsInclusiveScanAMD(vec4);" + + "int maxInvocationsInclusiveScanAMD(int);" + "ivec2 maxInvocationsInclusiveScanAMD(ivec2);" + "ivec3 maxInvocationsInclusiveScanAMD(ivec3);" + "ivec4 maxInvocationsInclusiveScanAMD(ivec4);" + + "uint maxInvocationsInclusiveScanAMD(uint);" + "uvec2 maxInvocationsInclusiveScanAMD(uvec2);" + "uvec3 maxInvocationsInclusiveScanAMD(uvec3);" + "uvec4 maxInvocationsInclusiveScanAMD(uvec4);" + + "double maxInvocationsInclusiveScanAMD(double);" + "dvec2 maxInvocationsInclusiveScanAMD(dvec2);" + "dvec3 maxInvocationsInclusiveScanAMD(dvec3);" + "dvec4 maxInvocationsInclusiveScanAMD(dvec4);" + + "int64_t maxInvocationsInclusiveScanAMD(int64_t);" + "i64vec2 maxInvocationsInclusiveScanAMD(i64vec2);" + "i64vec3 maxInvocationsInclusiveScanAMD(i64vec3);" + "i64vec4 maxInvocationsInclusiveScanAMD(i64vec4);" + + "uint64_t maxInvocationsInclusiveScanAMD(uint64_t);" + "u64vec2 maxInvocationsInclusiveScanAMD(u64vec2);" + "u64vec3 maxInvocationsInclusiveScanAMD(u64vec3);" + "u64vec4 maxInvocationsInclusiveScanAMD(u64vec4);" + + "float16_t maxInvocationsInclusiveScanAMD(float16_t);" + "f16vec2 maxInvocationsInclusiveScanAMD(f16vec2);" + "f16vec3 maxInvocationsInclusiveScanAMD(f16vec3);" + "f16vec4 maxInvocationsInclusiveScanAMD(f16vec4);" + + "int16_t maxInvocationsInclusiveScanAMD(int16_t);" + "i16vec2 maxInvocationsInclusiveScanAMD(i16vec2);" + "i16vec3 maxInvocationsInclusiveScanAMD(i16vec3);" + "i16vec4 maxInvocationsInclusiveScanAMD(i16vec4);" + + "uint16_t maxInvocationsInclusiveScanAMD(uint16_t);" + "u16vec2 maxInvocationsInclusiveScanAMD(u16vec2);" + "u16vec3 maxInvocationsInclusiveScanAMD(u16vec3);" + "u16vec4 maxInvocationsInclusiveScanAMD(u16vec4);" + + "float maxInvocationsExclusiveScanAMD(float);" + "vec2 maxInvocationsExclusiveScanAMD(vec2);" + "vec3 maxInvocationsExclusiveScanAMD(vec3);" + "vec4 maxInvocationsExclusiveScanAMD(vec4);" + + "int maxInvocationsExclusiveScanAMD(int);" + "ivec2 maxInvocationsExclusiveScanAMD(ivec2);" + "ivec3 maxInvocationsExclusiveScanAMD(ivec3);" + "ivec4 maxInvocationsExclusiveScanAMD(ivec4);" + + "uint maxInvocationsExclusiveScanAMD(uint);" + "uvec2 maxInvocationsExclusiveScanAMD(uvec2);" + "uvec3 maxInvocationsExclusiveScanAMD(uvec3);" + "uvec4 maxInvocationsExclusiveScanAMD(uvec4);" + + "double maxInvocationsExclusiveScanAMD(double);" + "dvec2 maxInvocationsExclusiveScanAMD(dvec2);" + "dvec3 maxInvocationsExclusiveScanAMD(dvec3);" + "dvec4 maxInvocationsExclusiveScanAMD(dvec4);" + + "int64_t maxInvocationsExclusiveScanAMD(int64_t);" + "i64vec2 maxInvocationsExclusiveScanAMD(i64vec2);" + "i64vec3 maxInvocationsExclusiveScanAMD(i64vec3);" + "i64vec4 maxInvocationsExclusiveScanAMD(i64vec4);" + + "uint64_t maxInvocationsExclusiveScanAMD(uint64_t);" + "u64vec2 maxInvocationsExclusiveScanAMD(u64vec2);" + "u64vec3 maxInvocationsExclusiveScanAMD(u64vec3);" + "u64vec4 maxInvocationsExclusiveScanAMD(u64vec4);" + + "float16_t maxInvocationsExclusiveScanAMD(float16_t);" + "f16vec2 maxInvocationsExclusiveScanAMD(f16vec2);" + "f16vec3 maxInvocationsExclusiveScanAMD(f16vec3);" + "f16vec4 maxInvocationsExclusiveScanAMD(f16vec4);" + + "int16_t maxInvocationsExclusiveScanAMD(int16_t);" + "i16vec2 maxInvocationsExclusiveScanAMD(i16vec2);" + "i16vec3 maxInvocationsExclusiveScanAMD(i16vec3);" + "i16vec4 maxInvocationsExclusiveScanAMD(i16vec4);" + + "uint16_t maxInvocationsExclusiveScanAMD(uint16_t);" + "u16vec2 maxInvocationsExclusiveScanAMD(u16vec2);" + "u16vec3 maxInvocationsExclusiveScanAMD(u16vec3);" + "u16vec4 maxInvocationsExclusiveScanAMD(u16vec4);" + + "float addInvocationsAMD(float);" + "vec2 addInvocationsAMD(vec2);" + "vec3 addInvocationsAMD(vec3);" + "vec4 addInvocationsAMD(vec4);" + + "int addInvocationsAMD(int);" + "ivec2 addInvocationsAMD(ivec2);" + "ivec3 addInvocationsAMD(ivec3);" + "ivec4 addInvocationsAMD(ivec4);" + + "uint addInvocationsAMD(uint);" + "uvec2 addInvocationsAMD(uvec2);" + "uvec3 addInvocationsAMD(uvec3);" + "uvec4 addInvocationsAMD(uvec4);" + + "double addInvocationsAMD(double);" + "dvec2 addInvocationsAMD(dvec2);" + "dvec3 addInvocationsAMD(dvec3);" + "dvec4 addInvocationsAMD(dvec4);" + + "int64_t addInvocationsAMD(int64_t);" + "i64vec2 addInvocationsAMD(i64vec2);" + "i64vec3 addInvocationsAMD(i64vec3);" + "i64vec4 addInvocationsAMD(i64vec4);" + + "uint64_t addInvocationsAMD(uint64_t);" + "u64vec2 addInvocationsAMD(u64vec2);" + "u64vec3 addInvocationsAMD(u64vec3);" + "u64vec4 addInvocationsAMD(u64vec4);" + + "float16_t addInvocationsAMD(float16_t);" + "f16vec2 addInvocationsAMD(f16vec2);" + "f16vec3 addInvocationsAMD(f16vec3);" + "f16vec4 addInvocationsAMD(f16vec4);" + + "int16_t addInvocationsAMD(int16_t);" + "i16vec2 addInvocationsAMD(i16vec2);" + "i16vec3 addInvocationsAMD(i16vec3);" + "i16vec4 addInvocationsAMD(i16vec4);" + + "uint16_t addInvocationsAMD(uint16_t);" + "u16vec2 addInvocationsAMD(u16vec2);" + "u16vec3 addInvocationsAMD(u16vec3);" + "u16vec4 addInvocationsAMD(u16vec4);" + + "float addInvocationsInclusiveScanAMD(float);" + "vec2 addInvocationsInclusiveScanAMD(vec2);" + "vec3 addInvocationsInclusiveScanAMD(vec3);" + "vec4 addInvocationsInclusiveScanAMD(vec4);" + + "int addInvocationsInclusiveScanAMD(int);" + "ivec2 addInvocationsInclusiveScanAMD(ivec2);" + "ivec3 addInvocationsInclusiveScanAMD(ivec3);" + "ivec4 addInvocationsInclusiveScanAMD(ivec4);" + + "uint addInvocationsInclusiveScanAMD(uint);" + "uvec2 addInvocationsInclusiveScanAMD(uvec2);" + "uvec3 addInvocationsInclusiveScanAMD(uvec3);" + "uvec4 addInvocationsInclusiveScanAMD(uvec4);" + + "double addInvocationsInclusiveScanAMD(double);" + "dvec2 addInvocationsInclusiveScanAMD(dvec2);" + "dvec3 addInvocationsInclusiveScanAMD(dvec3);" + "dvec4 addInvocationsInclusiveScanAMD(dvec4);" + + "int64_t addInvocationsInclusiveScanAMD(int64_t);" + "i64vec2 addInvocationsInclusiveScanAMD(i64vec2);" + "i64vec3 addInvocationsInclusiveScanAMD(i64vec3);" + "i64vec4 addInvocationsInclusiveScanAMD(i64vec4);" + + "uint64_t addInvocationsInclusiveScanAMD(uint64_t);" + "u64vec2 addInvocationsInclusiveScanAMD(u64vec2);" + "u64vec3 addInvocationsInclusiveScanAMD(u64vec3);" + "u64vec4 addInvocationsInclusiveScanAMD(u64vec4);" + + "float16_t addInvocationsInclusiveScanAMD(float16_t);" + "f16vec2 addInvocationsInclusiveScanAMD(f16vec2);" + "f16vec3 addInvocationsInclusiveScanAMD(f16vec3);" + "f16vec4 addInvocationsInclusiveScanAMD(f16vec4);" + + "int16_t addInvocationsInclusiveScanAMD(int16_t);" + "i16vec2 addInvocationsInclusiveScanAMD(i16vec2);" + "i16vec3 addInvocationsInclusiveScanAMD(i16vec3);" + "i16vec4 addInvocationsInclusiveScanAMD(i16vec4);" + + "uint16_t addInvocationsInclusiveScanAMD(uint16_t);" + "u16vec2 addInvocationsInclusiveScanAMD(u16vec2);" + "u16vec3 addInvocationsInclusiveScanAMD(u16vec3);" + "u16vec4 addInvocationsInclusiveScanAMD(u16vec4);" + + "float addInvocationsExclusiveScanAMD(float);" + "vec2 addInvocationsExclusiveScanAMD(vec2);" + "vec3 addInvocationsExclusiveScanAMD(vec3);" + "vec4 addInvocationsExclusiveScanAMD(vec4);" + + "int addInvocationsExclusiveScanAMD(int);" + "ivec2 addInvocationsExclusiveScanAMD(ivec2);" + "ivec3 addInvocationsExclusiveScanAMD(ivec3);" + "ivec4 addInvocationsExclusiveScanAMD(ivec4);" + + "uint addInvocationsExclusiveScanAMD(uint);" + "uvec2 addInvocationsExclusiveScanAMD(uvec2);" + "uvec3 addInvocationsExclusiveScanAMD(uvec3);" + "uvec4 addInvocationsExclusiveScanAMD(uvec4);" + + "double addInvocationsExclusiveScanAMD(double);" + "dvec2 addInvocationsExclusiveScanAMD(dvec2);" + "dvec3 addInvocationsExclusiveScanAMD(dvec3);" + "dvec4 addInvocationsExclusiveScanAMD(dvec4);" + + "int64_t addInvocationsExclusiveScanAMD(int64_t);" + "i64vec2 addInvocationsExclusiveScanAMD(i64vec2);" + "i64vec3 addInvocationsExclusiveScanAMD(i64vec3);" + "i64vec4 addInvocationsExclusiveScanAMD(i64vec4);" + + "uint64_t addInvocationsExclusiveScanAMD(uint64_t);" + "u64vec2 addInvocationsExclusiveScanAMD(u64vec2);" + "u64vec3 addInvocationsExclusiveScanAMD(u64vec3);" + "u64vec4 addInvocationsExclusiveScanAMD(u64vec4);" + + "float16_t addInvocationsExclusiveScanAMD(float16_t);" + "f16vec2 addInvocationsExclusiveScanAMD(f16vec2);" + "f16vec3 addInvocationsExclusiveScanAMD(f16vec3);" + "f16vec4 addInvocationsExclusiveScanAMD(f16vec4);" + + "int16_t addInvocationsExclusiveScanAMD(int16_t);" + "i16vec2 addInvocationsExclusiveScanAMD(i16vec2);" + "i16vec3 addInvocationsExclusiveScanAMD(i16vec3);" + "i16vec4 addInvocationsExclusiveScanAMD(i16vec4);" + + "uint16_t addInvocationsExclusiveScanAMD(uint16_t);" + "u16vec2 addInvocationsExclusiveScanAMD(u16vec2);" + "u16vec3 addInvocationsExclusiveScanAMD(u16vec3);" + "u16vec4 addInvocationsExclusiveScanAMD(u16vec4);" + + "float minInvocationsNonUniformAMD(float);" + "vec2 minInvocationsNonUniformAMD(vec2);" + "vec3 minInvocationsNonUniformAMD(vec3);" + "vec4 minInvocationsNonUniformAMD(vec4);" + + "int minInvocationsNonUniformAMD(int);" + "ivec2 minInvocationsNonUniformAMD(ivec2);" + "ivec3 minInvocationsNonUniformAMD(ivec3);" + "ivec4 minInvocationsNonUniformAMD(ivec4);" + + "uint minInvocationsNonUniformAMD(uint);" + "uvec2 minInvocationsNonUniformAMD(uvec2);" + "uvec3 minInvocationsNonUniformAMD(uvec3);" + "uvec4 minInvocationsNonUniformAMD(uvec4);" + + "double minInvocationsNonUniformAMD(double);" + "dvec2 minInvocationsNonUniformAMD(dvec2);" + "dvec3 minInvocationsNonUniformAMD(dvec3);" + "dvec4 minInvocationsNonUniformAMD(dvec4);" + + "int64_t minInvocationsNonUniformAMD(int64_t);" + "i64vec2 minInvocationsNonUniformAMD(i64vec2);" + "i64vec3 minInvocationsNonUniformAMD(i64vec3);" + "i64vec4 minInvocationsNonUniformAMD(i64vec4);" + + "uint64_t minInvocationsNonUniformAMD(uint64_t);" + "u64vec2 minInvocationsNonUniformAMD(u64vec2);" + "u64vec3 minInvocationsNonUniformAMD(u64vec3);" + "u64vec4 minInvocationsNonUniformAMD(u64vec4);" + + "float16_t minInvocationsNonUniformAMD(float16_t);" + "f16vec2 minInvocationsNonUniformAMD(f16vec2);" + "f16vec3 minInvocationsNonUniformAMD(f16vec3);" + "f16vec4 minInvocationsNonUniformAMD(f16vec4);" + + "int16_t minInvocationsNonUniformAMD(int16_t);" + "i16vec2 minInvocationsNonUniformAMD(i16vec2);" + "i16vec3 minInvocationsNonUniformAMD(i16vec3);" + "i16vec4 minInvocationsNonUniformAMD(i16vec4);" + + "uint16_t minInvocationsNonUniformAMD(uint16_t);" + "u16vec2 minInvocationsNonUniformAMD(u16vec2);" + "u16vec3 minInvocationsNonUniformAMD(u16vec3);" + "u16vec4 minInvocationsNonUniformAMD(u16vec4);" + + "float minInvocationsInclusiveScanNonUniformAMD(float);" + "vec2 minInvocationsInclusiveScanNonUniformAMD(vec2);" + "vec3 minInvocationsInclusiveScanNonUniformAMD(vec3);" + "vec4 minInvocationsInclusiveScanNonUniformAMD(vec4);" + + "int minInvocationsInclusiveScanNonUniformAMD(int);" + "ivec2 minInvocationsInclusiveScanNonUniformAMD(ivec2);" + "ivec3 minInvocationsInclusiveScanNonUniformAMD(ivec3);" + "ivec4 minInvocationsInclusiveScanNonUniformAMD(ivec4);" + + "uint minInvocationsInclusiveScanNonUniformAMD(uint);" + "uvec2 minInvocationsInclusiveScanNonUniformAMD(uvec2);" + "uvec3 minInvocationsInclusiveScanNonUniformAMD(uvec3);" + "uvec4 minInvocationsInclusiveScanNonUniformAMD(uvec4);" + + "double minInvocationsInclusiveScanNonUniformAMD(double);" + "dvec2 minInvocationsInclusiveScanNonUniformAMD(dvec2);" + "dvec3 minInvocationsInclusiveScanNonUniformAMD(dvec3);" + "dvec4 minInvocationsInclusiveScanNonUniformAMD(dvec4);" + + "int64_t minInvocationsInclusiveScanNonUniformAMD(int64_t);" + "i64vec2 minInvocationsInclusiveScanNonUniformAMD(i64vec2);" + "i64vec3 minInvocationsInclusiveScanNonUniformAMD(i64vec3);" + "i64vec4 minInvocationsInclusiveScanNonUniformAMD(i64vec4);" + + "uint64_t minInvocationsInclusiveScanNonUniformAMD(uint64_t);" + "u64vec2 minInvocationsInclusiveScanNonUniformAMD(u64vec2);" + "u64vec3 minInvocationsInclusiveScanNonUniformAMD(u64vec3);" + "u64vec4 minInvocationsInclusiveScanNonUniformAMD(u64vec4);" + + "float16_t minInvocationsInclusiveScanNonUniformAMD(float16_t);" + "f16vec2 minInvocationsInclusiveScanNonUniformAMD(f16vec2);" + "f16vec3 minInvocationsInclusiveScanNonUniformAMD(f16vec3);" + "f16vec4 minInvocationsInclusiveScanNonUniformAMD(f16vec4);" + + "int16_t minInvocationsInclusiveScanNonUniformAMD(int16_t);" + "i16vec2 minInvocationsInclusiveScanNonUniformAMD(i16vec2);" + "i16vec3 minInvocationsInclusiveScanNonUniformAMD(i16vec3);" + "i16vec4 minInvocationsInclusiveScanNonUniformAMD(i16vec4);" + + "uint16_t minInvocationsInclusiveScanNonUniformAMD(uint16_t);" + "u16vec2 minInvocationsInclusiveScanNonUniformAMD(u16vec2);" + "u16vec3 minInvocationsInclusiveScanNonUniformAMD(u16vec3);" + "u16vec4 minInvocationsInclusiveScanNonUniformAMD(u16vec4);" + + "float minInvocationsExclusiveScanNonUniformAMD(float);" + "vec2 minInvocationsExclusiveScanNonUniformAMD(vec2);" + "vec3 minInvocationsExclusiveScanNonUniformAMD(vec3);" + "vec4 minInvocationsExclusiveScanNonUniformAMD(vec4);" + + "int minInvocationsExclusiveScanNonUniformAMD(int);" + "ivec2 minInvocationsExclusiveScanNonUniformAMD(ivec2);" + "ivec3 minInvocationsExclusiveScanNonUniformAMD(ivec3);" + "ivec4 minInvocationsExclusiveScanNonUniformAMD(ivec4);" + + "uint minInvocationsExclusiveScanNonUniformAMD(uint);" + "uvec2 minInvocationsExclusiveScanNonUniformAMD(uvec2);" + "uvec3 minInvocationsExclusiveScanNonUniformAMD(uvec3);" + "uvec4 minInvocationsExclusiveScanNonUniformAMD(uvec4);" + + "double minInvocationsExclusiveScanNonUniformAMD(double);" + "dvec2 minInvocationsExclusiveScanNonUniformAMD(dvec2);" + "dvec3 minInvocationsExclusiveScanNonUniformAMD(dvec3);" + "dvec4 minInvocationsExclusiveScanNonUniformAMD(dvec4);" + + "int64_t minInvocationsExclusiveScanNonUniformAMD(int64_t);" + "i64vec2 minInvocationsExclusiveScanNonUniformAMD(i64vec2);" + "i64vec3 minInvocationsExclusiveScanNonUniformAMD(i64vec3);" + "i64vec4 minInvocationsExclusiveScanNonUniformAMD(i64vec4);" + + "uint64_t minInvocationsExclusiveScanNonUniformAMD(uint64_t);" + "u64vec2 minInvocationsExclusiveScanNonUniformAMD(u64vec2);" + "u64vec3 minInvocationsExclusiveScanNonUniformAMD(u64vec3);" + "u64vec4 minInvocationsExclusiveScanNonUniformAMD(u64vec4);" + + "float16_t minInvocationsExclusiveScanNonUniformAMD(float16_t);" + "f16vec2 minInvocationsExclusiveScanNonUniformAMD(f16vec2);" + "f16vec3 minInvocationsExclusiveScanNonUniformAMD(f16vec3);" + "f16vec4 minInvocationsExclusiveScanNonUniformAMD(f16vec4);" + + "int16_t minInvocationsExclusiveScanNonUniformAMD(int16_t);" + "i16vec2 minInvocationsExclusiveScanNonUniformAMD(i16vec2);" + "i16vec3 minInvocationsExclusiveScanNonUniformAMD(i16vec3);" + "i16vec4 minInvocationsExclusiveScanNonUniformAMD(i16vec4);" + + "uint16_t minInvocationsExclusiveScanNonUniformAMD(uint16_t);" + "u16vec2 minInvocationsExclusiveScanNonUniformAMD(u16vec2);" + "u16vec3 minInvocationsExclusiveScanNonUniformAMD(u16vec3);" + "u16vec4 minInvocationsExclusiveScanNonUniformAMD(u16vec4);" + + "float maxInvocationsNonUniformAMD(float);" + "vec2 maxInvocationsNonUniformAMD(vec2);" + "vec3 maxInvocationsNonUniformAMD(vec3);" + "vec4 maxInvocationsNonUniformAMD(vec4);" + + "int maxInvocationsNonUniformAMD(int);" + "ivec2 maxInvocationsNonUniformAMD(ivec2);" + "ivec3 maxInvocationsNonUniformAMD(ivec3);" + "ivec4 maxInvocationsNonUniformAMD(ivec4);" + + "uint maxInvocationsNonUniformAMD(uint);" + "uvec2 maxInvocationsNonUniformAMD(uvec2);" + "uvec3 maxInvocationsNonUniformAMD(uvec3);" + "uvec4 maxInvocationsNonUniformAMD(uvec4);" + + "double maxInvocationsNonUniformAMD(double);" + "dvec2 maxInvocationsNonUniformAMD(dvec2);" + "dvec3 maxInvocationsNonUniformAMD(dvec3);" + "dvec4 maxInvocationsNonUniformAMD(dvec4);" + + "int64_t maxInvocationsNonUniformAMD(int64_t);" + "i64vec2 maxInvocationsNonUniformAMD(i64vec2);" + "i64vec3 maxInvocationsNonUniformAMD(i64vec3);" + "i64vec4 maxInvocationsNonUniformAMD(i64vec4);" + + "uint64_t maxInvocationsNonUniformAMD(uint64_t);" + "u64vec2 maxInvocationsNonUniformAMD(u64vec2);" + "u64vec3 maxInvocationsNonUniformAMD(u64vec3);" + "u64vec4 maxInvocationsNonUniformAMD(u64vec4);" + + "float16_t maxInvocationsNonUniformAMD(float16_t);" + "f16vec2 maxInvocationsNonUniformAMD(f16vec2);" + "f16vec3 maxInvocationsNonUniformAMD(f16vec3);" + "f16vec4 maxInvocationsNonUniformAMD(f16vec4);" + + "int16_t maxInvocationsNonUniformAMD(int16_t);" + "i16vec2 maxInvocationsNonUniformAMD(i16vec2);" + "i16vec3 maxInvocationsNonUniformAMD(i16vec3);" + "i16vec4 maxInvocationsNonUniformAMD(i16vec4);" + + "uint16_t maxInvocationsNonUniformAMD(uint16_t);" + "u16vec2 maxInvocationsNonUniformAMD(u16vec2);" + "u16vec3 maxInvocationsNonUniformAMD(u16vec3);" + "u16vec4 maxInvocationsNonUniformAMD(u16vec4);" + + "float maxInvocationsInclusiveScanNonUniformAMD(float);" + "vec2 maxInvocationsInclusiveScanNonUniformAMD(vec2);" + "vec3 maxInvocationsInclusiveScanNonUniformAMD(vec3);" + "vec4 maxInvocationsInclusiveScanNonUniformAMD(vec4);" + + "int maxInvocationsInclusiveScanNonUniformAMD(int);" + "ivec2 maxInvocationsInclusiveScanNonUniformAMD(ivec2);" + "ivec3 maxInvocationsInclusiveScanNonUniformAMD(ivec3);" + "ivec4 maxInvocationsInclusiveScanNonUniformAMD(ivec4);" + + "uint maxInvocationsInclusiveScanNonUniformAMD(uint);" + "uvec2 maxInvocationsInclusiveScanNonUniformAMD(uvec2);" + "uvec3 maxInvocationsInclusiveScanNonUniformAMD(uvec3);" + "uvec4 maxInvocationsInclusiveScanNonUniformAMD(uvec4);" + + "double maxInvocationsInclusiveScanNonUniformAMD(double);" + "dvec2 maxInvocationsInclusiveScanNonUniformAMD(dvec2);" + "dvec3 maxInvocationsInclusiveScanNonUniformAMD(dvec3);" + "dvec4 maxInvocationsInclusiveScanNonUniformAMD(dvec4);" + + "int64_t maxInvocationsInclusiveScanNonUniformAMD(int64_t);" + "i64vec2 maxInvocationsInclusiveScanNonUniformAMD(i64vec2);" + "i64vec3 maxInvocationsInclusiveScanNonUniformAMD(i64vec3);" + "i64vec4 maxInvocationsInclusiveScanNonUniformAMD(i64vec4);" + + "uint64_t maxInvocationsInclusiveScanNonUniformAMD(uint64_t);" + "u64vec2 maxInvocationsInclusiveScanNonUniformAMD(u64vec2);" + "u64vec3 maxInvocationsInclusiveScanNonUniformAMD(u64vec3);" + "u64vec4 maxInvocationsInclusiveScanNonUniformAMD(u64vec4);" + + "float16_t maxInvocationsInclusiveScanNonUniformAMD(float16_t);" + "f16vec2 maxInvocationsInclusiveScanNonUniformAMD(f16vec2);" + "f16vec3 maxInvocationsInclusiveScanNonUniformAMD(f16vec3);" + "f16vec4 maxInvocationsInclusiveScanNonUniformAMD(f16vec4);" + + "int16_t maxInvocationsInclusiveScanNonUniformAMD(int16_t);" + "i16vec2 maxInvocationsInclusiveScanNonUniformAMD(i16vec2);" + "i16vec3 maxInvocationsInclusiveScanNonUniformAMD(i16vec3);" + "i16vec4 maxInvocationsInclusiveScanNonUniformAMD(i16vec4);" + + "uint16_t maxInvocationsInclusiveScanNonUniformAMD(uint16_t);" + "u16vec2 maxInvocationsInclusiveScanNonUniformAMD(u16vec2);" + "u16vec3 maxInvocationsInclusiveScanNonUniformAMD(u16vec3);" + "u16vec4 maxInvocationsInclusiveScanNonUniformAMD(u16vec4);" + + "float maxInvocationsExclusiveScanNonUniformAMD(float);" + "vec2 maxInvocationsExclusiveScanNonUniformAMD(vec2);" + "vec3 maxInvocationsExclusiveScanNonUniformAMD(vec3);" + "vec4 maxInvocationsExclusiveScanNonUniformAMD(vec4);" + + "int maxInvocationsExclusiveScanNonUniformAMD(int);" + "ivec2 maxInvocationsExclusiveScanNonUniformAMD(ivec2);" + "ivec3 maxInvocationsExclusiveScanNonUniformAMD(ivec3);" + "ivec4 maxInvocationsExclusiveScanNonUniformAMD(ivec4);" + + "uint maxInvocationsExclusiveScanNonUniformAMD(uint);" + "uvec2 maxInvocationsExclusiveScanNonUniformAMD(uvec2);" + "uvec3 maxInvocationsExclusiveScanNonUniformAMD(uvec3);" + "uvec4 maxInvocationsExclusiveScanNonUniformAMD(uvec4);" + + "double maxInvocationsExclusiveScanNonUniformAMD(double);" + "dvec2 maxInvocationsExclusiveScanNonUniformAMD(dvec2);" + "dvec3 maxInvocationsExclusiveScanNonUniformAMD(dvec3);" + "dvec4 maxInvocationsExclusiveScanNonUniformAMD(dvec4);" + + "int64_t maxInvocationsExclusiveScanNonUniformAMD(int64_t);" + "i64vec2 maxInvocationsExclusiveScanNonUniformAMD(i64vec2);" + "i64vec3 maxInvocationsExclusiveScanNonUniformAMD(i64vec3);" + "i64vec4 maxInvocationsExclusiveScanNonUniformAMD(i64vec4);" + + "uint64_t maxInvocationsExclusiveScanNonUniformAMD(uint64_t);" + "u64vec2 maxInvocationsExclusiveScanNonUniformAMD(u64vec2);" + "u64vec3 maxInvocationsExclusiveScanNonUniformAMD(u64vec3);" + "u64vec4 maxInvocationsExclusiveScanNonUniformAMD(u64vec4);" + + "float16_t maxInvocationsExclusiveScanNonUniformAMD(float16_t);" + "f16vec2 maxInvocationsExclusiveScanNonUniformAMD(f16vec2);" + "f16vec3 maxInvocationsExclusiveScanNonUniformAMD(f16vec3);" + "f16vec4 maxInvocationsExclusiveScanNonUniformAMD(f16vec4);" + + "int16_t maxInvocationsExclusiveScanNonUniformAMD(int16_t);" + "i16vec2 maxInvocationsExclusiveScanNonUniformAMD(i16vec2);" + "i16vec3 maxInvocationsExclusiveScanNonUniformAMD(i16vec3);" + "i16vec4 maxInvocationsExclusiveScanNonUniformAMD(i16vec4);" + + "uint16_t maxInvocationsExclusiveScanNonUniformAMD(uint16_t);" + "u16vec2 maxInvocationsExclusiveScanNonUniformAMD(u16vec2);" + "u16vec3 maxInvocationsExclusiveScanNonUniformAMD(u16vec3);" + "u16vec4 maxInvocationsExclusiveScanNonUniformAMD(u16vec4);" + + "float addInvocationsNonUniformAMD(float);" + "vec2 addInvocationsNonUniformAMD(vec2);" + "vec3 addInvocationsNonUniformAMD(vec3);" + "vec4 addInvocationsNonUniformAMD(vec4);" + + "int addInvocationsNonUniformAMD(int);" + "ivec2 addInvocationsNonUniformAMD(ivec2);" + "ivec3 addInvocationsNonUniformAMD(ivec3);" + "ivec4 addInvocationsNonUniformAMD(ivec4);" + + "uint addInvocationsNonUniformAMD(uint);" + "uvec2 addInvocationsNonUniformAMD(uvec2);" + "uvec3 addInvocationsNonUniformAMD(uvec3);" + "uvec4 addInvocationsNonUniformAMD(uvec4);" + + "double addInvocationsNonUniformAMD(double);" + "dvec2 addInvocationsNonUniformAMD(dvec2);" + "dvec3 addInvocationsNonUniformAMD(dvec3);" + "dvec4 addInvocationsNonUniformAMD(dvec4);" + + "int64_t addInvocationsNonUniformAMD(int64_t);" + "i64vec2 addInvocationsNonUniformAMD(i64vec2);" + "i64vec3 addInvocationsNonUniformAMD(i64vec3);" + "i64vec4 addInvocationsNonUniformAMD(i64vec4);" + + "uint64_t addInvocationsNonUniformAMD(uint64_t);" + "u64vec2 addInvocationsNonUniformAMD(u64vec2);" + "u64vec3 addInvocationsNonUniformAMD(u64vec3);" + "u64vec4 addInvocationsNonUniformAMD(u64vec4);" + + "float16_t addInvocationsNonUniformAMD(float16_t);" + "f16vec2 addInvocationsNonUniformAMD(f16vec2);" + "f16vec3 addInvocationsNonUniformAMD(f16vec3);" + "f16vec4 addInvocationsNonUniformAMD(f16vec4);" + + "int16_t addInvocationsNonUniformAMD(int16_t);" + "i16vec2 addInvocationsNonUniformAMD(i16vec2);" + "i16vec3 addInvocationsNonUniformAMD(i16vec3);" + "i16vec4 addInvocationsNonUniformAMD(i16vec4);" + + "uint16_t addInvocationsNonUniformAMD(uint16_t);" + "u16vec2 addInvocationsNonUniformAMD(u16vec2);" + "u16vec3 addInvocationsNonUniformAMD(u16vec3);" + "u16vec4 addInvocationsNonUniformAMD(u16vec4);" + + "float addInvocationsInclusiveScanNonUniformAMD(float);" + "vec2 addInvocationsInclusiveScanNonUniformAMD(vec2);" + "vec3 addInvocationsInclusiveScanNonUniformAMD(vec3);" + "vec4 addInvocationsInclusiveScanNonUniformAMD(vec4);" + + "int addInvocationsInclusiveScanNonUniformAMD(int);" + "ivec2 addInvocationsInclusiveScanNonUniformAMD(ivec2);" + "ivec3 addInvocationsInclusiveScanNonUniformAMD(ivec3);" + "ivec4 addInvocationsInclusiveScanNonUniformAMD(ivec4);" + + "uint addInvocationsInclusiveScanNonUniformAMD(uint);" + "uvec2 addInvocationsInclusiveScanNonUniformAMD(uvec2);" + "uvec3 addInvocationsInclusiveScanNonUniformAMD(uvec3);" + "uvec4 addInvocationsInclusiveScanNonUniformAMD(uvec4);" + + "double addInvocationsInclusiveScanNonUniformAMD(double);" + "dvec2 addInvocationsInclusiveScanNonUniformAMD(dvec2);" + "dvec3 addInvocationsInclusiveScanNonUniformAMD(dvec3);" + "dvec4 addInvocationsInclusiveScanNonUniformAMD(dvec4);" + + "int64_t addInvocationsInclusiveScanNonUniformAMD(int64_t);" + "i64vec2 addInvocationsInclusiveScanNonUniformAMD(i64vec2);" + "i64vec3 addInvocationsInclusiveScanNonUniformAMD(i64vec3);" + "i64vec4 addInvocationsInclusiveScanNonUniformAMD(i64vec4);" + + "uint64_t addInvocationsInclusiveScanNonUniformAMD(uint64_t);" + "u64vec2 addInvocationsInclusiveScanNonUniformAMD(u64vec2);" + "u64vec3 addInvocationsInclusiveScanNonUniformAMD(u64vec3);" + "u64vec4 addInvocationsInclusiveScanNonUniformAMD(u64vec4);" + + "float16_t addInvocationsInclusiveScanNonUniformAMD(float16_t);" + "f16vec2 addInvocationsInclusiveScanNonUniformAMD(f16vec2);" + "f16vec3 addInvocationsInclusiveScanNonUniformAMD(f16vec3);" + "f16vec4 addInvocationsInclusiveScanNonUniformAMD(f16vec4);" + + "int16_t addInvocationsInclusiveScanNonUniformAMD(int16_t);" + "i16vec2 addInvocationsInclusiveScanNonUniformAMD(i16vec2);" + "i16vec3 addInvocationsInclusiveScanNonUniformAMD(i16vec3);" + "i16vec4 addInvocationsInclusiveScanNonUniformAMD(i16vec4);" + + "uint16_t addInvocationsInclusiveScanNonUniformAMD(uint16_t);" + "u16vec2 addInvocationsInclusiveScanNonUniformAMD(u16vec2);" + "u16vec3 addInvocationsInclusiveScanNonUniformAMD(u16vec3);" + "u16vec4 addInvocationsInclusiveScanNonUniformAMD(u16vec4);" + + "float addInvocationsExclusiveScanNonUniformAMD(float);" + "vec2 addInvocationsExclusiveScanNonUniformAMD(vec2);" + "vec3 addInvocationsExclusiveScanNonUniformAMD(vec3);" + "vec4 addInvocationsExclusiveScanNonUniformAMD(vec4);" + + "int addInvocationsExclusiveScanNonUniformAMD(int);" + "ivec2 addInvocationsExclusiveScanNonUniformAMD(ivec2);" + "ivec3 addInvocationsExclusiveScanNonUniformAMD(ivec3);" + "ivec4 addInvocationsExclusiveScanNonUniformAMD(ivec4);" + + "uint addInvocationsExclusiveScanNonUniformAMD(uint);" + "uvec2 addInvocationsExclusiveScanNonUniformAMD(uvec2);" + "uvec3 addInvocationsExclusiveScanNonUniformAMD(uvec3);" + "uvec4 addInvocationsExclusiveScanNonUniformAMD(uvec4);" + + "double addInvocationsExclusiveScanNonUniformAMD(double);" + "dvec2 addInvocationsExclusiveScanNonUniformAMD(dvec2);" + "dvec3 addInvocationsExclusiveScanNonUniformAMD(dvec3);" + "dvec4 addInvocationsExclusiveScanNonUniformAMD(dvec4);" + + "int64_t addInvocationsExclusiveScanNonUniformAMD(int64_t);" + "i64vec2 addInvocationsExclusiveScanNonUniformAMD(i64vec2);" + "i64vec3 addInvocationsExclusiveScanNonUniformAMD(i64vec3);" + "i64vec4 addInvocationsExclusiveScanNonUniformAMD(i64vec4);" + + "uint64_t addInvocationsExclusiveScanNonUniformAMD(uint64_t);" + "u64vec2 addInvocationsExclusiveScanNonUniformAMD(u64vec2);" + "u64vec3 addInvocationsExclusiveScanNonUniformAMD(u64vec3);" + "u64vec4 addInvocationsExclusiveScanNonUniformAMD(u64vec4);" + + "float16_t addInvocationsExclusiveScanNonUniformAMD(float16_t);" + "f16vec2 addInvocationsExclusiveScanNonUniformAMD(f16vec2);" + "f16vec3 addInvocationsExclusiveScanNonUniformAMD(f16vec3);" + "f16vec4 addInvocationsExclusiveScanNonUniformAMD(f16vec4);" + + "int16_t addInvocationsExclusiveScanNonUniformAMD(int16_t);" + "i16vec2 addInvocationsExclusiveScanNonUniformAMD(i16vec2);" + "i16vec3 addInvocationsExclusiveScanNonUniformAMD(i16vec3);" + "i16vec4 addInvocationsExclusiveScanNonUniformAMD(i16vec4);" + + "uint16_t addInvocationsExclusiveScanNonUniformAMD(uint16_t);" + "u16vec2 addInvocationsExclusiveScanNonUniformAMD(u16vec2);" + "u16vec3 addInvocationsExclusiveScanNonUniformAMD(u16vec3);" + "u16vec4 addInvocationsExclusiveScanNonUniformAMD(u16vec4);" + + "float swizzleInvocationsAMD(float, uvec4);" + "vec2 swizzleInvocationsAMD(vec2, uvec4);" + "vec3 swizzleInvocationsAMD(vec3, uvec4);" + "vec4 swizzleInvocationsAMD(vec4, uvec4);" + + "int swizzleInvocationsAMD(int, uvec4);" + "ivec2 swizzleInvocationsAMD(ivec2, uvec4);" + "ivec3 swizzleInvocationsAMD(ivec3, uvec4);" + "ivec4 swizzleInvocationsAMD(ivec4, uvec4);" + + "uint swizzleInvocationsAMD(uint, uvec4);" + "uvec2 swizzleInvocationsAMD(uvec2, uvec4);" + "uvec3 swizzleInvocationsAMD(uvec3, uvec4);" + "uvec4 swizzleInvocationsAMD(uvec4, uvec4);" + + "float swizzleInvocationsMaskedAMD(float, uvec3);" + "vec2 swizzleInvocationsMaskedAMD(vec2, uvec3);" + "vec3 swizzleInvocationsMaskedAMD(vec3, uvec3);" + "vec4 swizzleInvocationsMaskedAMD(vec4, uvec3);" + + "int swizzleInvocationsMaskedAMD(int, uvec3);" + "ivec2 swizzleInvocationsMaskedAMD(ivec2, uvec3);" + "ivec3 swizzleInvocationsMaskedAMD(ivec3, uvec3);" + "ivec4 swizzleInvocationsMaskedAMD(ivec4, uvec3);" + + "uint swizzleInvocationsMaskedAMD(uint, uvec3);" + "uvec2 swizzleInvocationsMaskedAMD(uvec2, uvec3);" + "uvec3 swizzleInvocationsMaskedAMD(uvec3, uvec3);" + "uvec4 swizzleInvocationsMaskedAMD(uvec4, uvec3);" + + "float writeInvocationAMD(float, float, uint);" + "vec2 writeInvocationAMD(vec2, vec2, uint);" + "vec3 writeInvocationAMD(vec3, vec3, uint);" + "vec4 writeInvocationAMD(vec4, vec4, uint);" + + "int writeInvocationAMD(int, int, uint);" + "ivec2 writeInvocationAMD(ivec2, ivec2, uint);" + "ivec3 writeInvocationAMD(ivec3, ivec3, uint);" + "ivec4 writeInvocationAMD(ivec4, ivec4, uint);" + + "uint writeInvocationAMD(uint, uint, uint);" + "uvec2 writeInvocationAMD(uvec2, uvec2, uint);" + "uvec3 writeInvocationAMD(uvec3, uvec3, uint);" + "uvec4 writeInvocationAMD(uvec4, uvec4, uint);" + + "uint mbcntAMD(uint64_t);" + + "\n"); + } + + // GL_AMD_gcn_shader + if (profile != EEsProfile && version >= 450) { + commonBuiltins.append( + "float cubeFaceIndexAMD(vec3);" + "vec2 cubeFaceCoordAMD(vec3);" + "uint64_t timeAMD();" + + "\n"); + } + + // GL_AMD_shader_fragment_mask + if (profile != EEsProfile && version >= 450) { + commonBuiltins.append( + "uint fragmentMaskFetchAMD(sampler2DMS, ivec2);" + "uint fragmentMaskFetchAMD(isampler2DMS, ivec2);" + "uint fragmentMaskFetchAMD(usampler2DMS, ivec2);" + + "uint fragmentMaskFetchAMD(sampler2DMSArray, ivec3);" + "uint fragmentMaskFetchAMD(isampler2DMSArray, ivec3);" + "uint fragmentMaskFetchAMD(usampler2DMSArray, ivec3);" + + "vec4 fragmentFetchAMD(sampler2DMS, ivec2, uint);" + "ivec4 fragmentFetchAMD(isampler2DMS, ivec2, uint);" + "uvec4 fragmentFetchAMD(usampler2DMS, ivec2, uint);" + + "vec4 fragmentFetchAMD(sampler2DMSArray, ivec3, uint);" + "ivec4 fragmentFetchAMD(isampler2DMSArray, ivec3, uint);" + "uvec4 fragmentFetchAMD(usampler2DMSArray, ivec3, uint);" + + "\n"); + } + +#endif // AMD_EXTENSIONS + + // GL_AMD_gpu_shader_half_float/Explicit types + if (profile != EEsProfile && version >= 450) { + commonBuiltins.append( + "float16_t radians(float16_t);" + "f16vec2 radians(f16vec2);" + "f16vec3 radians(f16vec3);" + "f16vec4 radians(f16vec4);" + + "float16_t degrees(float16_t);" + "f16vec2 degrees(f16vec2);" + "f16vec3 degrees(f16vec3);" + "f16vec4 degrees(f16vec4);" + + "float16_t sin(float16_t);" + "f16vec2 sin(f16vec2);" + "f16vec3 sin(f16vec3);" + "f16vec4 sin(f16vec4);" + + "float16_t cos(float16_t);" + "f16vec2 cos(f16vec2);" + "f16vec3 cos(f16vec3);" + "f16vec4 cos(f16vec4);" + + "float16_t tan(float16_t);" + "f16vec2 tan(f16vec2);" + "f16vec3 tan(f16vec3);" + "f16vec4 tan(f16vec4);" + + "float16_t asin(float16_t);" + "f16vec2 asin(f16vec2);" + "f16vec3 asin(f16vec3);" + "f16vec4 asin(f16vec4);" + + "float16_t acos(float16_t);" + "f16vec2 acos(f16vec2);" + "f16vec3 acos(f16vec3);" + "f16vec4 acos(f16vec4);" + + "float16_t atan(float16_t, float16_t);" + "f16vec2 atan(f16vec2, f16vec2);" + "f16vec3 atan(f16vec3, f16vec3);" + "f16vec4 atan(f16vec4, f16vec4);" + + "float16_t atan(float16_t);" + "f16vec2 atan(f16vec2);" + "f16vec3 atan(f16vec3);" + "f16vec4 atan(f16vec4);" + + "float16_t sinh(float16_t);" + "f16vec2 sinh(f16vec2);" + "f16vec3 sinh(f16vec3);" + "f16vec4 sinh(f16vec4);" + + "float16_t cosh(float16_t);" + "f16vec2 cosh(f16vec2);" + "f16vec3 cosh(f16vec3);" + "f16vec4 cosh(f16vec4);" + + "float16_t tanh(float16_t);" + "f16vec2 tanh(f16vec2);" + "f16vec3 tanh(f16vec3);" + "f16vec4 tanh(f16vec4);" + + "float16_t asinh(float16_t);" + "f16vec2 asinh(f16vec2);" + "f16vec3 asinh(f16vec3);" + "f16vec4 asinh(f16vec4);" + + "float16_t acosh(float16_t);" + "f16vec2 acosh(f16vec2);" + "f16vec3 acosh(f16vec3);" + "f16vec4 acosh(f16vec4);" + + "float16_t atanh(float16_t);" + "f16vec2 atanh(f16vec2);" + "f16vec3 atanh(f16vec3);" + "f16vec4 atanh(f16vec4);" + + "float16_t pow(float16_t, float16_t);" + "f16vec2 pow(f16vec2, f16vec2);" + "f16vec3 pow(f16vec3, f16vec3);" + "f16vec4 pow(f16vec4, f16vec4);" + + "float16_t exp(float16_t);" + "f16vec2 exp(f16vec2);" + "f16vec3 exp(f16vec3);" + "f16vec4 exp(f16vec4);" + + "float16_t log(float16_t);" + "f16vec2 log(f16vec2);" + "f16vec3 log(f16vec3);" + "f16vec4 log(f16vec4);" + + "float16_t exp2(float16_t);" + "f16vec2 exp2(f16vec2);" + "f16vec3 exp2(f16vec3);" + "f16vec4 exp2(f16vec4);" + + "float16_t log2(float16_t);" + "f16vec2 log2(f16vec2);" + "f16vec3 log2(f16vec3);" + "f16vec4 log2(f16vec4);" + + "float16_t sqrt(float16_t);" + "f16vec2 sqrt(f16vec2);" + "f16vec3 sqrt(f16vec3);" + "f16vec4 sqrt(f16vec4);" + + "float16_t inversesqrt(float16_t);" + "f16vec2 inversesqrt(f16vec2);" + "f16vec3 inversesqrt(f16vec3);" + "f16vec4 inversesqrt(f16vec4);" + + "float16_t abs(float16_t);" + "f16vec2 abs(f16vec2);" + "f16vec3 abs(f16vec3);" + "f16vec4 abs(f16vec4);" + + "float16_t sign(float16_t);" + "f16vec2 sign(f16vec2);" + "f16vec3 sign(f16vec3);" + "f16vec4 sign(f16vec4);" + + "float16_t floor(float16_t);" + "f16vec2 floor(f16vec2);" + "f16vec3 floor(f16vec3);" + "f16vec4 floor(f16vec4);" + + "float16_t trunc(float16_t);" + "f16vec2 trunc(f16vec2);" + "f16vec3 trunc(f16vec3);" + "f16vec4 trunc(f16vec4);" + + "float16_t round(float16_t);" + "f16vec2 round(f16vec2);" + "f16vec3 round(f16vec3);" + "f16vec4 round(f16vec4);" + + "float16_t roundEven(float16_t);" + "f16vec2 roundEven(f16vec2);" + "f16vec3 roundEven(f16vec3);" + "f16vec4 roundEven(f16vec4);" + + "float16_t ceil(float16_t);" + "f16vec2 ceil(f16vec2);" + "f16vec3 ceil(f16vec3);" + "f16vec4 ceil(f16vec4);" + + "float16_t fract(float16_t);" + "f16vec2 fract(f16vec2);" + "f16vec3 fract(f16vec3);" + "f16vec4 fract(f16vec4);" + + "float16_t mod(float16_t, float16_t);" + "f16vec2 mod(f16vec2, float16_t);" + "f16vec3 mod(f16vec3, float16_t);" + "f16vec4 mod(f16vec4, float16_t);" + "f16vec2 mod(f16vec2, f16vec2);" + "f16vec3 mod(f16vec3, f16vec3);" + "f16vec4 mod(f16vec4, f16vec4);" + + "float16_t modf(float16_t, out float16_t);" + "f16vec2 modf(f16vec2, out f16vec2);" + "f16vec3 modf(f16vec3, out f16vec3);" + "f16vec4 modf(f16vec4, out f16vec4);" + + "float16_t min(float16_t, float16_t);" + "f16vec2 min(f16vec2, float16_t);" + "f16vec3 min(f16vec3, float16_t);" + "f16vec4 min(f16vec4, float16_t);" + "f16vec2 min(f16vec2, f16vec2);" + "f16vec3 min(f16vec3, f16vec3);" + "f16vec4 min(f16vec4, f16vec4);" + + "float16_t max(float16_t, float16_t);" + "f16vec2 max(f16vec2, float16_t);" + "f16vec3 max(f16vec3, float16_t);" + "f16vec4 max(f16vec4, float16_t);" + "f16vec2 max(f16vec2, f16vec2);" + "f16vec3 max(f16vec3, f16vec3);" + "f16vec4 max(f16vec4, f16vec4);" + + "float16_t clamp(float16_t, float16_t, float16_t);" + "f16vec2 clamp(f16vec2, float16_t, float16_t);" + "f16vec3 clamp(f16vec3, float16_t, float16_t);" + "f16vec4 clamp(f16vec4, float16_t, float16_t);" + "f16vec2 clamp(f16vec2, f16vec2, f16vec2);" + "f16vec3 clamp(f16vec3, f16vec3, f16vec3);" + "f16vec4 clamp(f16vec4, f16vec4, f16vec4);" + + "float16_t mix(float16_t, float16_t, float16_t);" + "f16vec2 mix(f16vec2, f16vec2, float16_t);" + "f16vec3 mix(f16vec3, f16vec3, float16_t);" + "f16vec4 mix(f16vec4, f16vec4, float16_t);" + "f16vec2 mix(f16vec2, f16vec2, f16vec2);" + "f16vec3 mix(f16vec3, f16vec3, f16vec3);" + "f16vec4 mix(f16vec4, f16vec4, f16vec4);" + "float16_t mix(float16_t, float16_t, bool);" + "f16vec2 mix(f16vec2, f16vec2, bvec2);" + "f16vec3 mix(f16vec3, f16vec3, bvec3);" + "f16vec4 mix(f16vec4, f16vec4, bvec4);" + + "float16_t step(float16_t, float16_t);" + "f16vec2 step(f16vec2, f16vec2);" + "f16vec3 step(f16vec3, f16vec3);" + "f16vec4 step(f16vec4, f16vec4);" + "f16vec2 step(float16_t, f16vec2);" + "f16vec3 step(float16_t, f16vec3);" + "f16vec4 step(float16_t, f16vec4);" + + "float16_t smoothstep(float16_t, float16_t, float16_t);" + "f16vec2 smoothstep(f16vec2, f16vec2, f16vec2);" + "f16vec3 smoothstep(f16vec3, f16vec3, f16vec3);" + "f16vec4 smoothstep(f16vec4, f16vec4, f16vec4);" + "f16vec2 smoothstep(float16_t, float16_t, f16vec2);" + "f16vec3 smoothstep(float16_t, float16_t, f16vec3);" + "f16vec4 smoothstep(float16_t, float16_t, f16vec4);" + + "bool isnan(float16_t);" + "bvec2 isnan(f16vec2);" + "bvec3 isnan(f16vec3);" + "bvec4 isnan(f16vec4);" + + "bool isinf(float16_t);" + "bvec2 isinf(f16vec2);" + "bvec3 isinf(f16vec3);" + "bvec4 isinf(f16vec4);" + + "float16_t fma(float16_t, float16_t, float16_t);" + "f16vec2 fma(f16vec2, f16vec2, f16vec2);" + "f16vec3 fma(f16vec3, f16vec3, f16vec3);" + "f16vec4 fma(f16vec4, f16vec4, f16vec4);" + + "float16_t frexp(float16_t, out int);" + "f16vec2 frexp(f16vec2, out ivec2);" + "f16vec3 frexp(f16vec3, out ivec3);" + "f16vec4 frexp(f16vec4, out ivec4);" + + "float16_t ldexp(float16_t, in int);" + "f16vec2 ldexp(f16vec2, in ivec2);" + "f16vec3 ldexp(f16vec3, in ivec3);" + "f16vec4 ldexp(f16vec4, in ivec4);" + + "uint packFloat2x16(f16vec2);" + "f16vec2 unpackFloat2x16(uint);" + + "float16_t length(float16_t);" + "float16_t length(f16vec2);" + "float16_t length(f16vec3);" + "float16_t length(f16vec4);" + + "float16_t distance(float16_t, float16_t);" + "float16_t distance(f16vec2, f16vec2);" + "float16_t distance(f16vec3, f16vec3);" + "float16_t distance(f16vec4, f16vec4);" + + "float16_t dot(float16_t, float16_t);" + "float16_t dot(f16vec2, f16vec2);" + "float16_t dot(f16vec3, f16vec3);" + "float16_t dot(f16vec4, f16vec4);" + + "f16vec3 cross(f16vec3, f16vec3);" + + "float16_t normalize(float16_t);" + "f16vec2 normalize(f16vec2);" + "f16vec3 normalize(f16vec3);" + "f16vec4 normalize(f16vec4);" + + "float16_t faceforward(float16_t, float16_t, float16_t);" + "f16vec2 faceforward(f16vec2, f16vec2, f16vec2);" + "f16vec3 faceforward(f16vec3, f16vec3, f16vec3);" + "f16vec4 faceforward(f16vec4, f16vec4, f16vec4);" + + "float16_t reflect(float16_t, float16_t);" + "f16vec2 reflect(f16vec2, f16vec2);" + "f16vec3 reflect(f16vec3, f16vec3);" + "f16vec4 reflect(f16vec4, f16vec4);" + + "float16_t refract(float16_t, float16_t, float16_t);" + "f16vec2 refract(f16vec2, f16vec2, float16_t);" + "f16vec3 refract(f16vec3, f16vec3, float16_t);" + "f16vec4 refract(f16vec4, f16vec4, float16_t);" + + "f16mat2 matrixCompMult(f16mat2, f16mat2);" + "f16mat3 matrixCompMult(f16mat3, f16mat3);" + "f16mat4 matrixCompMult(f16mat4, f16mat4);" + "f16mat2x3 matrixCompMult(f16mat2x3, f16mat2x3);" + "f16mat2x4 matrixCompMult(f16mat2x4, f16mat2x4);" + "f16mat3x2 matrixCompMult(f16mat3x2, f16mat3x2);" + "f16mat3x4 matrixCompMult(f16mat3x4, f16mat3x4);" + "f16mat4x2 matrixCompMult(f16mat4x2, f16mat4x2);" + "f16mat4x3 matrixCompMult(f16mat4x3, f16mat4x3);" + + "f16mat2 outerProduct(f16vec2, f16vec2);" + "f16mat3 outerProduct(f16vec3, f16vec3);" + "f16mat4 outerProduct(f16vec4, f16vec4);" + "f16mat2x3 outerProduct(f16vec3, f16vec2);" + "f16mat3x2 outerProduct(f16vec2, f16vec3);" + "f16mat2x4 outerProduct(f16vec4, f16vec2);" + "f16mat4x2 outerProduct(f16vec2, f16vec4);" + "f16mat3x4 outerProduct(f16vec4, f16vec3);" + "f16mat4x3 outerProduct(f16vec3, f16vec4);" + + "f16mat2 transpose(f16mat2);" + "f16mat3 transpose(f16mat3);" + "f16mat4 transpose(f16mat4);" + "f16mat2x3 transpose(f16mat3x2);" + "f16mat3x2 transpose(f16mat2x3);" + "f16mat2x4 transpose(f16mat4x2);" + "f16mat4x2 transpose(f16mat2x4);" + "f16mat3x4 transpose(f16mat4x3);" + "f16mat4x3 transpose(f16mat3x4);" + + "float16_t determinant(f16mat2);" + "float16_t determinant(f16mat3);" + "float16_t determinant(f16mat4);" + + "f16mat2 inverse(f16mat2);" + "f16mat3 inverse(f16mat3);" + "f16mat4 inverse(f16mat4);" + + "bvec2 lessThan(f16vec2, f16vec2);" + "bvec3 lessThan(f16vec3, f16vec3);" + "bvec4 lessThan(f16vec4, f16vec4);" + + "bvec2 lessThanEqual(f16vec2, f16vec2);" + "bvec3 lessThanEqual(f16vec3, f16vec3);" + "bvec4 lessThanEqual(f16vec4, f16vec4);" + + "bvec2 greaterThan(f16vec2, f16vec2);" + "bvec3 greaterThan(f16vec3, f16vec3);" + "bvec4 greaterThan(f16vec4, f16vec4);" + + "bvec2 greaterThanEqual(f16vec2, f16vec2);" + "bvec3 greaterThanEqual(f16vec3, f16vec3);" + "bvec4 greaterThanEqual(f16vec4, f16vec4);" + + "bvec2 equal(f16vec2, f16vec2);" + "bvec3 equal(f16vec3, f16vec3);" + "bvec4 equal(f16vec4, f16vec4);" + + "bvec2 notEqual(f16vec2, f16vec2);" + "bvec3 notEqual(f16vec3, f16vec3);" + "bvec4 notEqual(f16vec4, f16vec4);" + + "\n"); + } + + // Explicit types + if (profile != EEsProfile && version >= 450) { + commonBuiltins.append( + "int8_t abs(int8_t);" + "i8vec2 abs(i8vec2);" + "i8vec3 abs(i8vec3);" + "i8vec4 abs(i8vec4);" + + "int8_t sign(int8_t);" + "i8vec2 sign(i8vec2);" + "i8vec3 sign(i8vec3);" + "i8vec4 sign(i8vec4);" + + "int8_t min(int8_t x, int8_t y);" + "i8vec2 min(i8vec2 x, int8_t y);" + "i8vec3 min(i8vec3 x, int8_t y);" + "i8vec4 min(i8vec4 x, int8_t y);" + "i8vec2 min(i8vec2 x, i8vec2 y);" + "i8vec3 min(i8vec3 x, i8vec3 y);" + "i8vec4 min(i8vec4 x, i8vec4 y);" + + "uint8_t min(uint8_t x, uint8_t y);" + "u8vec2 min(u8vec2 x, uint8_t y);" + "u8vec3 min(u8vec3 x, uint8_t y);" + "u8vec4 min(u8vec4 x, uint8_t y);" + "u8vec2 min(u8vec2 x, u8vec2 y);" + "u8vec3 min(u8vec3 x, u8vec3 y);" + "u8vec4 min(u8vec4 x, u8vec4 y);" + + "int8_t max(int8_t x, int8_t y);" + "i8vec2 max(i8vec2 x, int8_t y);" + "i8vec3 max(i8vec3 x, int8_t y);" + "i8vec4 max(i8vec4 x, int8_t y);" + "i8vec2 max(i8vec2 x, i8vec2 y);" + "i8vec3 max(i8vec3 x, i8vec3 y);" + "i8vec4 max(i8vec4 x, i8vec4 y);" + + "uint8_t max(uint8_t x, uint8_t y);" + "u8vec2 max(u8vec2 x, uint8_t y);" + "u8vec3 max(u8vec3 x, uint8_t y);" + "u8vec4 max(u8vec4 x, uint8_t y);" + "u8vec2 max(u8vec2 x, u8vec2 y);" + "u8vec3 max(u8vec3 x, u8vec3 y);" + "u8vec4 max(u8vec4 x, u8vec4 y);" + + "int8_t clamp(int8_t x, int8_t minVal, int8_t maxVal);" + "i8vec2 clamp(i8vec2 x, int8_t minVal, int8_t maxVal);" + "i8vec3 clamp(i8vec3 x, int8_t minVal, int8_t maxVal);" + "i8vec4 clamp(i8vec4 x, int8_t minVal, int8_t maxVal);" + "i8vec2 clamp(i8vec2 x, i8vec2 minVal, i8vec2 maxVal);" + "i8vec3 clamp(i8vec3 x, i8vec3 minVal, i8vec3 maxVal);" + "i8vec4 clamp(i8vec4 x, i8vec4 minVal, i8vec4 maxVal);" + + "uint8_t clamp(uint8_t x, uint8_t minVal, uint8_t maxVal);" + "u8vec2 clamp(u8vec2 x, uint8_t minVal, uint8_t maxVal);" + "u8vec3 clamp(u8vec3 x, uint8_t minVal, uint8_t maxVal);" + "u8vec4 clamp(u8vec4 x, uint8_t minVal, uint8_t maxVal);" + "u8vec2 clamp(u8vec2 x, u8vec2 minVal, u8vec2 maxVal);" + "u8vec3 clamp(u8vec3 x, u8vec3 minVal, u8vec3 maxVal);" + "u8vec4 clamp(u8vec4 x, u8vec4 minVal, u8vec4 maxVal);" + + "int8_t mix(int8_t, int8_t, bool);" + "i8vec2 mix(i8vec2, i8vec2, bvec2);" + "i8vec3 mix(i8vec3, i8vec3, bvec3);" + "i8vec4 mix(i8vec4, i8vec4, bvec4);" + "uint8_t mix(uint8_t, uint8_t, bool);" + "u8vec2 mix(u8vec2, u8vec2, bvec2);" + "u8vec3 mix(u8vec3, u8vec3, bvec3);" + "u8vec4 mix(u8vec4, u8vec4, bvec4);" + + "bvec2 lessThan(i8vec2, i8vec2);" + "bvec3 lessThan(i8vec3, i8vec3);" + "bvec4 lessThan(i8vec4, i8vec4);" + "bvec2 lessThan(u8vec2, u8vec2);" + "bvec3 lessThan(u8vec3, u8vec3);" + "bvec4 lessThan(u8vec4, u8vec4);" + + "bvec2 lessThanEqual(i8vec2, i8vec2);" + "bvec3 lessThanEqual(i8vec3, i8vec3);" + "bvec4 lessThanEqual(i8vec4, i8vec4);" + "bvec2 lessThanEqual(u8vec2, u8vec2);" + "bvec3 lessThanEqual(u8vec3, u8vec3);" + "bvec4 lessThanEqual(u8vec4, u8vec4);" + + "bvec2 greaterThan(i8vec2, i8vec2);" + "bvec3 greaterThan(i8vec3, i8vec3);" + "bvec4 greaterThan(i8vec4, i8vec4);" + "bvec2 greaterThan(u8vec2, u8vec2);" + "bvec3 greaterThan(u8vec3, u8vec3);" + "bvec4 greaterThan(u8vec4, u8vec4);" + + "bvec2 greaterThanEqual(i8vec2, i8vec2);" + "bvec3 greaterThanEqual(i8vec3, i8vec3);" + "bvec4 greaterThanEqual(i8vec4, i8vec4);" + "bvec2 greaterThanEqual(u8vec2, u8vec2);" + "bvec3 greaterThanEqual(u8vec3, u8vec3);" + "bvec4 greaterThanEqual(u8vec4, u8vec4);" + + "bvec2 equal(i8vec2, i8vec2);" + "bvec3 equal(i8vec3, i8vec3);" + "bvec4 equal(i8vec4, i8vec4);" + "bvec2 equal(u8vec2, u8vec2);" + "bvec3 equal(u8vec3, u8vec3);" + "bvec4 equal(u8vec4, u8vec4);" + + "bvec2 notEqual(i8vec2, i8vec2);" + "bvec3 notEqual(i8vec3, i8vec3);" + "bvec4 notEqual(i8vec4, i8vec4);" + "bvec2 notEqual(u8vec2, u8vec2);" + "bvec3 notEqual(u8vec3, u8vec3);" + "bvec4 notEqual(u8vec4, u8vec4);" + + " int8_t bitfieldExtract( int8_t, int8_t, int8_t);" + "i8vec2 bitfieldExtract(i8vec2, int8_t, int8_t);" + "i8vec3 bitfieldExtract(i8vec3, int8_t, int8_t);" + "i8vec4 bitfieldExtract(i8vec4, int8_t, int8_t);" + + " uint8_t bitfieldExtract( uint8_t, int8_t, int8_t);" + "u8vec2 bitfieldExtract(u8vec2, int8_t, int8_t);" + "u8vec3 bitfieldExtract(u8vec3, int8_t, int8_t);" + "u8vec4 bitfieldExtract(u8vec4, int8_t, int8_t);" + + " int8_t bitfieldInsert( int8_t base, int8_t, int8_t, int8_t);" + "i8vec2 bitfieldInsert(i8vec2 base, i8vec2, int8_t, int8_t);" + "i8vec3 bitfieldInsert(i8vec3 base, i8vec3, int8_t, int8_t);" + "i8vec4 bitfieldInsert(i8vec4 base, i8vec4, int8_t, int8_t);" + + " uint8_t bitfieldInsert( uint8_t base, uint8_t, int8_t, int8_t);" + "u8vec2 bitfieldInsert(u8vec2 base, u8vec2, int8_t, int8_t);" + "u8vec3 bitfieldInsert(u8vec3 base, u8vec3, int8_t, int8_t);" + "u8vec4 bitfieldInsert(u8vec4 base, u8vec4, int8_t, int8_t);" + + " int8_t bitCount( int8_t);" + "i8vec2 bitCount(i8vec2);" + "i8vec3 bitCount(i8vec3);" + "i8vec4 bitCount(i8vec4);" + + " int8_t bitCount( uint8_t);" + "i8vec2 bitCount(u8vec2);" + "i8vec3 bitCount(u8vec3);" + "i8vec4 bitCount(u8vec4);" + + " int8_t findLSB( int8_t);" + "i8vec2 findLSB(i8vec2);" + "i8vec3 findLSB(i8vec3);" + "i8vec4 findLSB(i8vec4);" + + " int8_t findLSB( uint8_t);" + "i8vec2 findLSB(u8vec2);" + "i8vec3 findLSB(u8vec3);" + "i8vec4 findLSB(u8vec4);" + + " int8_t findMSB( int8_t);" + "i8vec2 findMSB(i8vec2);" + "i8vec3 findMSB(i8vec3);" + "i8vec4 findMSB(i8vec4);" + + " int8_t findMSB( uint8_t);" + "i8vec2 findMSB(u8vec2);" + "i8vec3 findMSB(u8vec3);" + "i8vec4 findMSB(u8vec4);" + + "int16_t abs(int16_t);" + "i16vec2 abs(i16vec2);" + "i16vec3 abs(i16vec3);" + "i16vec4 abs(i16vec4);" + + "int16_t sign(int16_t);" + "i16vec2 sign(i16vec2);" + "i16vec3 sign(i16vec3);" + "i16vec4 sign(i16vec4);" + + "int16_t min(int16_t x, int16_t y);" + "i16vec2 min(i16vec2 x, int16_t y);" + "i16vec3 min(i16vec3 x, int16_t y);" + "i16vec4 min(i16vec4 x, int16_t y);" + "i16vec2 min(i16vec2 x, i16vec2 y);" + "i16vec3 min(i16vec3 x, i16vec3 y);" + "i16vec4 min(i16vec4 x, i16vec4 y);" + + "uint16_t min(uint16_t x, uint16_t y);" + "u16vec2 min(u16vec2 x, uint16_t y);" + "u16vec3 min(u16vec3 x, uint16_t y);" + "u16vec4 min(u16vec4 x, uint16_t y);" + "u16vec2 min(u16vec2 x, u16vec2 y);" + "u16vec3 min(u16vec3 x, u16vec3 y);" + "u16vec4 min(u16vec4 x, u16vec4 y);" + + "int16_t max(int16_t x, int16_t y);" + "i16vec2 max(i16vec2 x, int16_t y);" + "i16vec3 max(i16vec3 x, int16_t y);" + "i16vec4 max(i16vec4 x, int16_t y);" + "i16vec2 max(i16vec2 x, i16vec2 y);" + "i16vec3 max(i16vec3 x, i16vec3 y);" + "i16vec4 max(i16vec4 x, i16vec4 y);" + + "uint16_t max(uint16_t x, uint16_t y);" + "u16vec2 max(u16vec2 x, uint16_t y);" + "u16vec3 max(u16vec3 x, uint16_t y);" + "u16vec4 max(u16vec4 x, uint16_t y);" + "u16vec2 max(u16vec2 x, u16vec2 y);" + "u16vec3 max(u16vec3 x, u16vec3 y);" + "u16vec4 max(u16vec4 x, u16vec4 y);" + + "int16_t clamp(int16_t x, int16_t minVal, int16_t maxVal);" + "i16vec2 clamp(i16vec2 x, int16_t minVal, int16_t maxVal);" + "i16vec3 clamp(i16vec3 x, int16_t minVal, int16_t maxVal);" + "i16vec4 clamp(i16vec4 x, int16_t minVal, int16_t maxVal);" + "i16vec2 clamp(i16vec2 x, i16vec2 minVal, i16vec2 maxVal);" + "i16vec3 clamp(i16vec3 x, i16vec3 minVal, i16vec3 maxVal);" + "i16vec4 clamp(i16vec4 x, i16vec4 minVal, i16vec4 maxVal);" + + "uint16_t clamp(uint16_t x, uint16_t minVal, uint16_t maxVal);" + "u16vec2 clamp(u16vec2 x, uint16_t minVal, uint16_t maxVal);" + "u16vec3 clamp(u16vec3 x, uint16_t minVal, uint16_t maxVal);" + "u16vec4 clamp(u16vec4 x, uint16_t minVal, uint16_t maxVal);" + "u16vec2 clamp(u16vec2 x, u16vec2 minVal, u16vec2 maxVal);" + "u16vec3 clamp(u16vec3 x, u16vec3 minVal, u16vec3 maxVal);" + "u16vec4 clamp(u16vec4 x, u16vec4 minVal, u16vec4 maxVal);" + + "int16_t mix(int16_t, int16_t, bool);" + "i16vec2 mix(i16vec2, i16vec2, bvec2);" + "i16vec3 mix(i16vec3, i16vec3, bvec3);" + "i16vec4 mix(i16vec4, i16vec4, bvec4);" + "uint16_t mix(uint16_t, uint16_t, bool);" + "u16vec2 mix(u16vec2, u16vec2, bvec2);" + "u16vec3 mix(u16vec3, u16vec3, bvec3);" + "u16vec4 mix(u16vec4, u16vec4, bvec4);" + + "float16_t frexp(float16_t, out int16_t);" + "f16vec2 frexp(f16vec2, out i16vec2);" + "f16vec3 frexp(f16vec3, out i16vec3);" + "f16vec4 frexp(f16vec4, out i16vec4);" + + "float16_t ldexp(float16_t, int16_t);" + "f16vec2 ldexp(f16vec2, i16vec2);" + "f16vec3 ldexp(f16vec3, i16vec3);" + "f16vec4 ldexp(f16vec4, i16vec4);" + + "int16_t halfBitsToInt16(float16_t);" + "i16vec2 halfBitsToInt16(f16vec2);" + "i16vec3 halhBitsToInt16(f16vec3);" + "i16vec4 halfBitsToInt16(f16vec4);" + + "uint16_t halfBitsToUint16(float16_t);" + "u16vec2 halfBitsToUint16(f16vec2);" + "u16vec3 halfBitsToUint16(f16vec3);" + "u16vec4 halfBitsToUint16(f16vec4);" + + "int16_t float16BitsToInt16(float16_t);" + "i16vec2 float16BitsToInt16(f16vec2);" + "i16vec3 float16BitsToInt16(f16vec3);" + "i16vec4 float16BitsToInt16(f16vec4);" + + "uint16_t float16BitsToUint16(float16_t);" + "u16vec2 float16BitsToUint16(f16vec2);" + "u16vec3 float16BitsToUint16(f16vec3);" + "u16vec4 float16BitsToUint16(f16vec4);" + + "float16_t int16BitsToFloat16(int16_t);" + "f16vec2 int16BitsToFloat16(i16vec2);" + "f16vec3 int16BitsToFloat16(i16vec3);" + "f16vec4 int16BitsToFloat16(i16vec4);" + + "float16_t uint16BitsToFloat16(uint16_t);" + "f16vec2 uint16BitsToFloat16(u16vec2);" + "f16vec3 uint16BitsToFloat16(u16vec3);" + "f16vec4 uint16BitsToFloat16(u16vec4);" + + "float16_t int16BitsToHalf(int16_t);" + "f16vec2 int16BitsToHalf(i16vec2);" + "f16vec3 int16BitsToHalf(i16vec3);" + "f16vec4 int16BitsToHalf(i16vec4);" + + "float16_t uint16BitsToHalf(uint16_t);" + "f16vec2 uint16BitsToHalf(u16vec2);" + "f16vec3 uint16BitsToHalf(u16vec3);" + "f16vec4 uint16BitsToHalf(u16vec4);" + + "int packInt2x16(i16vec2);" + "uint packUint2x16(u16vec2);" + "int64_t packInt4x16(i16vec4);" + "uint64_t packUint4x16(u16vec4);" + "i16vec2 unpackInt2x16(int);" + "u16vec2 unpackUint2x16(uint);" + "i16vec4 unpackInt4x16(int64_t);" + "u16vec4 unpackUint4x16(uint64_t);" + + "bvec2 lessThan(i16vec2, i16vec2);" + "bvec3 lessThan(i16vec3, i16vec3);" + "bvec4 lessThan(i16vec4, i16vec4);" + "bvec2 lessThan(u16vec2, u16vec2);" + "bvec3 lessThan(u16vec3, u16vec3);" + "bvec4 lessThan(u16vec4, u16vec4);" + + "bvec2 lessThanEqual(i16vec2, i16vec2);" + "bvec3 lessThanEqual(i16vec3, i16vec3);" + "bvec4 lessThanEqual(i16vec4, i16vec4);" + "bvec2 lessThanEqual(u16vec2, u16vec2);" + "bvec3 lessThanEqual(u16vec3, u16vec3);" + "bvec4 lessThanEqual(u16vec4, u16vec4);" + + "bvec2 greaterThan(i16vec2, i16vec2);" + "bvec3 greaterThan(i16vec3, i16vec3);" + "bvec4 greaterThan(i16vec4, i16vec4);" + "bvec2 greaterThan(u16vec2, u16vec2);" + "bvec3 greaterThan(u16vec3, u16vec3);" + "bvec4 greaterThan(u16vec4, u16vec4);" + + "bvec2 greaterThanEqual(i16vec2, i16vec2);" + "bvec3 greaterThanEqual(i16vec3, i16vec3);" + "bvec4 greaterThanEqual(i16vec4, i16vec4);" + "bvec2 greaterThanEqual(u16vec2, u16vec2);" + "bvec3 greaterThanEqual(u16vec3, u16vec3);" + "bvec4 greaterThanEqual(u16vec4, u16vec4);" + + "bvec2 equal(i16vec2, i16vec2);" + "bvec3 equal(i16vec3, i16vec3);" + "bvec4 equal(i16vec4, i16vec4);" + "bvec2 equal(u16vec2, u16vec2);" + "bvec3 equal(u16vec3, u16vec3);" + "bvec4 equal(u16vec4, u16vec4);" + + "bvec2 notEqual(i16vec2, i16vec2);" + "bvec3 notEqual(i16vec3, i16vec3);" + "bvec4 notEqual(i16vec4, i16vec4);" + "bvec2 notEqual(u16vec2, u16vec2);" + "bvec3 notEqual(u16vec3, u16vec3);" + "bvec4 notEqual(u16vec4, u16vec4);" + + " int16_t bitfieldExtract( int16_t, int16_t, int16_t);" + "i16vec2 bitfieldExtract(i16vec2, int16_t, int16_t);" + "i16vec3 bitfieldExtract(i16vec3, int16_t, int16_t);" + "i16vec4 bitfieldExtract(i16vec4, int16_t, int16_t);" + + " uint16_t bitfieldExtract( uint16_t, int16_t, int16_t);" + "u16vec2 bitfieldExtract(u16vec2, int16_t, int16_t);" + "u16vec3 bitfieldExtract(u16vec3, int16_t, int16_t);" + "u16vec4 bitfieldExtract(u16vec4, int16_t, int16_t);" + + " int16_t bitfieldInsert( int16_t base, int16_t, int16_t, int16_t);" + "i16vec2 bitfieldInsert(i16vec2 base, i16vec2, int16_t, int16_t);" + "i16vec3 bitfieldInsert(i16vec3 base, i16vec3, int16_t, int16_t);" + "i16vec4 bitfieldInsert(i16vec4 base, i16vec4, int16_t, int16_t);" + + " uint16_t bitfieldInsert( uint16_t base, uint16_t, int16_t, int16_t);" + "u16vec2 bitfieldInsert(u16vec2 base, u16vec2, int16_t, int16_t);" + "u16vec3 bitfieldInsert(u16vec3 base, u16vec3, int16_t, int16_t);" + "u16vec4 bitfieldInsert(u16vec4 base, u16vec4, int16_t, int16_t);" + + " int16_t bitCount( int16_t);" + "i16vec2 bitCount(i16vec2);" + "i16vec3 bitCount(i16vec3);" + "i16vec4 bitCount(i16vec4);" + + " int16_t bitCount( uint16_t);" + "i16vec2 bitCount(u16vec2);" + "i16vec3 bitCount(u16vec3);" + "i16vec4 bitCount(u16vec4);" + + " int16_t findLSB( int16_t);" + "i16vec2 findLSB(i16vec2);" + "i16vec3 findLSB(i16vec3);" + "i16vec4 findLSB(i16vec4);" + + " int16_t findLSB( uint16_t);" + "i16vec2 findLSB(u16vec2);" + "i16vec3 findLSB(u16vec3);" + "i16vec4 findLSB(u16vec4);" + + " int16_t findMSB( int16_t);" + "i16vec2 findMSB(i16vec2);" + "i16vec3 findMSB(i16vec3);" + "i16vec4 findMSB(i16vec4);" + + " int16_t findMSB( uint16_t);" + "i16vec2 findMSB(u16vec2);" + "i16vec3 findMSB(u16vec3);" + "i16vec4 findMSB(u16vec4);" + + "int16_t pack16(i8vec2);" + "uint16_t pack16(u8vec2);" + "int32_t pack32(i8vec4);" + "uint32_t pack32(u8vec4);" + "int32_t pack32(i16vec2);" + "uint32_t pack32(u16vec2);" + "int64_t pack64(i16vec4);" + "uint64_t pack64(u16vec4);" + "int64_t pack64(i32vec2);" + "uint64_t pack64(u32vec2);" + + "i8vec2 unpack8(int16_t);" + "u8vec2 unpack8(uint16_t);" + "i8vec4 unpack8(int32_t);" + "u8vec4 unpack8(uint32_t);" + "i16vec2 unpack16(int32_t);" + "u16vec2 unpack16(uint32_t);" + "i16vec4 unpack16(int64_t);" + "u16vec4 unpack16(uint64_t);" + "i32vec2 unpack32(int64_t);" + "u32vec2 unpack32(uint64_t);" + + "float64_t radians(float64_t);" + "f64vec2 radians(f64vec2);" + "f64vec3 radians(f64vec3);" + "f64vec4 radians(f64vec4);" + + "float64_t degrees(float64_t);" + "f64vec2 degrees(f64vec2);" + "f64vec3 degrees(f64vec3);" + "f64vec4 degrees(f64vec4);" + + "float64_t sin(float64_t);" + "f64vec2 sin(f64vec2);" + "f64vec3 sin(f64vec3);" + "f64vec4 sin(f64vec4);" + + "float64_t cos(float64_t);" + "f64vec2 cos(f64vec2);" + "f64vec3 cos(f64vec3);" + "f64vec4 cos(f64vec4);" + + "float64_t tan(float64_t);" + "f64vec2 tan(f64vec2);" + "f64vec3 tan(f64vec3);" + "f64vec4 tan(f64vec4);" + + "float64_t asin(float64_t);" + "f64vec2 asin(f64vec2);" + "f64vec3 asin(f64vec3);" + "f64vec4 asin(f64vec4);" + + "float64_t acos(float64_t);" + "f64vec2 acos(f64vec2);" + "f64vec3 acos(f64vec3);" + "f64vec4 acos(f64vec4);" + + "float64_t atan(float64_t, float64_t);" + "f64vec2 atan(f64vec2, f64vec2);" + "f64vec3 atan(f64vec3, f64vec3);" + "f64vec4 atan(f64vec4, f64vec4);" + + "float64_t atan(float64_t);" + "f64vec2 atan(f64vec2);" + "f64vec3 atan(f64vec3);" + "f64vec4 atan(f64vec4);" + + "float64_t sinh(float64_t);" + "f64vec2 sinh(f64vec2);" + "f64vec3 sinh(f64vec3);" + "f64vec4 sinh(f64vec4);" + + "float64_t cosh(float64_t);" + "f64vec2 cosh(f64vec2);" + "f64vec3 cosh(f64vec3);" + "f64vec4 cosh(f64vec4);" + + "float64_t tanh(float64_t);" + "f64vec2 tanh(f64vec2);" + "f64vec3 tanh(f64vec3);" + "f64vec4 tanh(f64vec4);" + + "float64_t asinh(float64_t);" + "f64vec2 asinh(f64vec2);" + "f64vec3 asinh(f64vec3);" + "f64vec4 asinh(f64vec4);" + + "float64_t acosh(float64_t);" + "f64vec2 acosh(f64vec2);" + "f64vec3 acosh(f64vec3);" + "f64vec4 acosh(f64vec4);" + + "float64_t atanh(float64_t);" + "f64vec2 atanh(f64vec2);" + "f64vec3 atanh(f64vec3);" + "f64vec4 atanh(f64vec4);" + + "float64_t pow(float64_t, float64_t);" + "f64vec2 pow(f64vec2, f64vec2);" + "f64vec3 pow(f64vec3, f64vec3);" + "f64vec4 pow(f64vec4, f64vec4);" + + "float64_t exp(float64_t);" + "f64vec2 exp(f64vec2);" + "f64vec3 exp(f64vec3);" + "f64vec4 exp(f64vec4);" + + "float64_t log(float64_t);" + "f64vec2 log(f64vec2);" + "f64vec3 log(f64vec3);" + "f64vec4 log(f64vec4);" + + "float64_t exp2(float64_t);" + "f64vec2 exp2(f64vec2);" + "f64vec3 exp2(f64vec3);" + "f64vec4 exp2(f64vec4);" + + "float64_t log2(float64_t);" + "f64vec2 log2(f64vec2);" + "f64vec3 log2(f64vec3);" + "f64vec4 log2(f64vec4);" + "\n"); + } + if (profile != EEsProfile && version >= 450) { + stageBuiltins[EShLangFragment].append( + "float64_t dFdx(float64_t);" + "f64vec2 dFdx(f64vec2);" + "f64vec3 dFdx(f64vec3);" + "f64vec4 dFdx(f64vec4);" + + "float64_t dFdy(float64_t);" + "f64vec2 dFdy(f64vec2);" + "f64vec3 dFdy(f64vec3);" + "f64vec4 dFdy(f64vec4);" + + "float64_t dFdxFine(float64_t);" + "f64vec2 dFdxFine(f64vec2);" + "f64vec3 dFdxFine(f64vec3);" + "f64vec4 dFdxFine(f64vec4);" + + "float64_t dFdyFine(float64_t);" + "f64vec2 dFdyFine(f64vec2);" + "f64vec3 dFdyFine(f64vec3);" + "f64vec4 dFdyFine(f64vec4);" + + "float64_t dFdxCoarse(float64_t);" + "f64vec2 dFdxCoarse(f64vec2);" + "f64vec3 dFdxCoarse(f64vec3);" + "f64vec4 dFdxCoarse(f64vec4);" + + "float64_t dFdyCoarse(float64_t);" + "f64vec2 dFdyCoarse(f64vec2);" + "f64vec3 dFdyCoarse(f64vec3);" + "f64vec4 dFdyCoarse(f64vec4);" + + "float64_t fwidth(float64_t);" + "f64vec2 fwidth(f64vec2);" + "f64vec3 fwidth(f64vec3);" + "f64vec4 fwidth(f64vec4);" + + "float64_t fwidthFine(float64_t);" + "f64vec2 fwidthFine(f64vec2);" + "f64vec3 fwidthFine(f64vec3);" + "f64vec4 fwidthFine(f64vec4);" + + "float64_t fwidthCoarse(float64_t);" + "f64vec2 fwidthCoarse(f64vec2);" + "f64vec3 fwidthCoarse(f64vec3);" + "f64vec4 fwidthCoarse(f64vec4);" + + "float64_t interpolateAtCentroid(float64_t);" + "f64vec2 interpolateAtCentroid(f64vec2);" + "f64vec3 interpolateAtCentroid(f64vec3);" + "f64vec4 interpolateAtCentroid(f64vec4);" + + "float64_t interpolateAtSample(float64_t, int);" + "f64vec2 interpolateAtSample(f64vec2, int);" + "f64vec3 interpolateAtSample(f64vec3, int);" + "f64vec4 interpolateAtSample(f64vec4, int);" + + "float64_t interpolateAtOffset(float64_t, f64vec2);" + "f64vec2 interpolateAtOffset(f64vec2, f64vec2);" + "f64vec3 interpolateAtOffset(f64vec3, f64vec2);" + "f64vec4 interpolateAtOffset(f64vec4, f64vec2);" + + "\n"); + + } + //============================================================================ // // Prototypes for built-in functions seen by vertex shaders only. @@ -1639,7 +4740,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec2 dFdx(vec2 p);" "vec3 dFdx(vec3 p);" "vec4 dFdx(vec4 p);" - + "float dFdy(float p);" "vec2 dFdy(vec2 p);" "vec3 dFdy(vec3 p);" @@ -1682,12 +4783,12 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec2 dFdyCoarse(vec2 p);" "vec3 dFdyCoarse(vec3 p);" "vec4 dFdyCoarse(vec4 p);" - + "float fwidthCoarse(float p);" "vec2 fwidthCoarse(vec2 p);" "vec3 fwidthCoarse(vec3 p);" "vec4 fwidthCoarse(vec4 p);" - + "\n"); } @@ -1713,6 +4814,114 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } +#ifdef AMD_EXTENSIONS + // GL_AMD_shader_explicit_vertex_parameter + if (profile != EEsProfile && version >= 450) { + stageBuiltins[EShLangFragment].append( + "float interpolateAtVertexAMD(float, uint);" + "vec2 interpolateAtVertexAMD(vec2, uint);" + "vec3 interpolateAtVertexAMD(vec3, uint);" + "vec4 interpolateAtVertexAMD(vec4, uint);" + + "int interpolateAtVertexAMD(int, uint);" + "ivec2 interpolateAtVertexAMD(ivec2, uint);" + "ivec3 interpolateAtVertexAMD(ivec3, uint);" + "ivec4 interpolateAtVertexAMD(ivec4, uint);" + + "uint interpolateAtVertexAMD(uint, uint);" + "uvec2 interpolateAtVertexAMD(uvec2, uint);" + "uvec3 interpolateAtVertexAMD(uvec3, uint);" + "uvec4 interpolateAtVertexAMD(uvec4, uint);" + + "float16_t interpolateAtVertexAMD(float16_t, uint);" + "f16vec2 interpolateAtVertexAMD(f16vec2, uint);" + "f16vec3 interpolateAtVertexAMD(f16vec3, uint);" + "f16vec4 interpolateAtVertexAMD(f16vec4, uint);" + + "\n"); + } + + // GL_AMD_gpu_shader_half_float + if (profile != EEsProfile && version >= 450) { + stageBuiltins[EShLangFragment].append( + "float16_t dFdx(float16_t);" + "f16vec2 dFdx(f16vec2);" + "f16vec3 dFdx(f16vec3);" + "f16vec4 dFdx(f16vec4);" + + "float16_t dFdy(float16_t);" + "f16vec2 dFdy(f16vec2);" + "f16vec3 dFdy(f16vec3);" + "f16vec4 dFdy(f16vec4);" + + "float16_t dFdxFine(float16_t);" + "f16vec2 dFdxFine(f16vec2);" + "f16vec3 dFdxFine(f16vec3);" + "f16vec4 dFdxFine(f16vec4);" + + "float16_t dFdyFine(float16_t);" + "f16vec2 dFdyFine(f16vec2);" + "f16vec3 dFdyFine(f16vec3);" + "f16vec4 dFdyFine(f16vec4);" + + "float16_t dFdxCoarse(float16_t);" + "f16vec2 dFdxCoarse(f16vec2);" + "f16vec3 dFdxCoarse(f16vec3);" + "f16vec4 dFdxCoarse(f16vec4);" + + "float16_t dFdyCoarse(float16_t);" + "f16vec2 dFdyCoarse(f16vec2);" + "f16vec3 dFdyCoarse(f16vec3);" + "f16vec4 dFdyCoarse(f16vec4);" + + "float16_t fwidth(float16_t);" + "f16vec2 fwidth(f16vec2);" + "f16vec3 fwidth(f16vec3);" + "f16vec4 fwidth(f16vec4);" + + "float16_t fwidthFine(float16_t);" + "f16vec2 fwidthFine(f16vec2);" + "f16vec3 fwidthFine(f16vec3);" + "f16vec4 fwidthFine(f16vec4);" + + "float16_t fwidthCoarse(float16_t);" + "f16vec2 fwidthCoarse(f16vec2);" + "f16vec3 fwidthCoarse(f16vec3);" + "f16vec4 fwidthCoarse(f16vec4);" + + "float16_t interpolateAtCentroid(float16_t);" + "f16vec2 interpolateAtCentroid(f16vec2);" + "f16vec3 interpolateAtCentroid(f16vec3);" + "f16vec4 interpolateAtCentroid(f16vec4);" + + "float16_t interpolateAtSample(float16_t, int);" + "f16vec2 interpolateAtSample(f16vec2, int);" + "f16vec3 interpolateAtSample(f16vec3, int);" + "f16vec4 interpolateAtSample(f16vec4, int);" + + "float16_t interpolateAtOffset(float16_t, f16vec2);" + "f16vec2 interpolateAtOffset(f16vec2, f16vec2);" + "f16vec3 interpolateAtOffset(f16vec3, f16vec2);" + "f16vec4 interpolateAtOffset(f16vec4, f16vec2);" + + "\n"); + } + + // GL_AMD_shader_fragment_mask + if (profile != EEsProfile && version >= 450 && spvVersion.vulkan > 0) { + stageBuiltins[EShLangFragment].append( + "uint fragmentMaskFetchAMD(subpassInputMS);" + "uint fragmentMaskFetchAMD(isubpassInputMS);" + "uint fragmentMaskFetchAMD(usubpassInputMS);" + + "vec4 fragmentFetchAMD(subpassInputMS, uint);" + "ivec4 fragmentFetchAMD(isubpassInputMS, uint);" + "uvec4 fragmentFetchAMD(usubpassInputMS, uint);" + + "\n"); + } +#endif + //============================================================================ // // Standard Uniforms @@ -1764,11 +4973,11 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "uniform mat4 gl_ModelViewMatrixInverse;" "uniform mat4 gl_ProjectionMatrixInverse;" "uniform mat4 gl_ModelViewProjectionMatrixInverse;" - + "uniform mat4 gl_ModelViewMatrixTranspose;" "uniform mat4 gl_ProjectionMatrixTranspose;" "uniform mat4 gl_ModelViewProjectionMatrixTranspose;" - + "uniform mat4 gl_ModelViewMatrixInverseTranspose;" "uniform mat4 gl_ProjectionMatrixInverseTranspose;" "uniform mat4 gl_ModelViewProjectionMatrixInverseTranspose;" @@ -1826,7 +5035,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "float quadraticAttenuation;"// K2 "};" - "struct gl_LightModelParameters {" "vec4 ambient;" // Acs "};" @@ -1861,7 +5069,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "};" "uniform gl_FogParameters gl_Fog;" - + "\n"); } @@ -1886,12 +5094,19 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } + if ((profile != EEsProfile && version >= 140) || + (profile == EEsProfile && version >= 310)) { + stageBuiltins[EShLangCompute].append( + "in highp int gl_DeviceIndex;" // GL_EXT_device_group + "\n"); + } + //============================================================================ // // Define the interface to the vertex shader. // //============================================================================ - + if (profile != EEsProfile) { if (version < 130) { stageBuiltins[EShLangVertex].append( @@ -1923,7 +5138,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "in vec4 gl_MultiTexCoord5;" "in vec4 gl_MultiTexCoord6;" "in vec4 gl_MultiTexCoord7;" - "in float gl_FogCoord;" + "in float gl_FogCoord;" "\n"); } @@ -1965,7 +5180,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec4 gl_Position;" // needs qualifier fixed later "float gl_PointSize;" // needs qualifier fixed later "float gl_ClipDistance[];" - ); + ); if (IncludeLegacy(version, profile, spvVersion)) stageBuiltins[EShLangVertex].append( "vec4 gl_ClipVertex;" // needs qualifier fixed later @@ -1992,7 +5207,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV stageBuiltins[EShLangVertex].append( "int gl_InstanceID;" // needs qualifier fixed later ); - if (spvVersion.vulkan >= 100 && version >= 140) + if (spvVersion.vulkan > 0 && version >= 140) stageBuiltins[EShLangVertex].append( "in int gl_VertexIndex;" "in int gl_InstanceIndex;" @@ -2004,6 +5219,31 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "in int gl_DrawIDARB;" ); } + if (version >= 410) { + stageBuiltins[EShLangVertex].append( + "out int gl_ViewportIndex;" + "out int gl_Layer;" + ); + } + if (version >= 460) { + stageBuiltins[EShLangVertex].append( + "in int gl_BaseVertex;" + "in int gl_BaseInstance;" + "in int gl_DrawID;" + ); + } + +#ifdef NV_EXTENSIONS + if (version >= 450) + stageBuiltins[EShLangVertex].append( + "out int gl_ViewportMask[];" // GL_NV_viewport_array2 + "out int gl_SecondaryViewportMaskNV[];" // GL_NV_stereo_view_rendering + "out vec4 gl_SecondaryPositionNV;" // GL_NV_stereo_view_rendering + "out vec4 gl_PositionPerViewNV[];" // GL_NVX_multiview_per_view_attributes + "out int gl_ViewportMaskPerViewNV[];" // GL_NVX_multiview_per_view_attributes + ); +#endif + } else { // ES profile if (version == 100) { @@ -2017,7 +5257,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "in highp int gl_VertexID;" // needs qualifier fixed later "in highp int gl_InstanceID;" // needs qualifier fixed later ); - if (spvVersion.vulkan >= 100) + if (spvVersion.vulkan > 0) stageBuiltins[EShLangVertex].append( "in highp int gl_VertexIndex;" "in highp int gl_InstanceIndex;" @@ -2037,6 +5277,21 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV } } + if ((profile != EEsProfile && version >= 140) || + (profile == EEsProfile && version >= 310)) { + stageBuiltins[EShLangVertex].append( + "in highp int gl_DeviceIndex;" // GL_EXT_device_group + "in highp int gl_ViewIndex;" // GL_EXT_multiview + "\n"); + } + + if (version >= 300 /* both ES and non-ES */) { + stageBuiltins[EShLangVertex].append( + "in highp uint gl_ViewID_OVR;" // GL_OVR_multiview, GL_OVR_multiview2 + "\n"); + } + + //============================================================================ // // Define the interface to the geometry shader. @@ -2063,6 +5318,10 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV if (version >= 450) stageBuiltins[EShLangGeometry].append( "float gl_CullDistance[];" +#ifdef NV_EXTENSIONS + "vec4 gl_SecondaryPositionNV;" // GL_NV_stereo_view_rendering + "vec4 gl_PositionPerViewNV[];" // GL_NVX_multiview_per_view_attributes +#endif ); stageBuiltins[EShLangGeometry].append( "} gl_in[];" @@ -2093,6 +5352,11 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "out int gl_PrimitiveID;" "out int gl_Layer;"); + if (version >= 150) + stageBuiltins[EShLangGeometry].append( + "out int gl_ViewportIndex;" + ); + if (profile == ECompatibilityProfile && version < 400) stageBuiltins[EShLangGeometry].append( "out vec4 gl_ClipVertex;" @@ -2102,11 +5366,18 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV stageBuiltins[EShLangGeometry].append( "in int gl_InvocationID;" ); - // GL_ARB_viewport_array - if (version >= 150) + +#ifdef NV_EXTENSIONS + if (version >= 450) stageBuiltins[EShLangGeometry].append( - "out int gl_ViewportIndex;" + "out int gl_ViewportMask[];" // GL_NV_viewport_array2 + "out int gl_SecondaryViewportMaskNV[];" // GL_NV_stereo_view_rendering + "out vec4 gl_SecondaryPositionNV;" // GL_NV_stereo_view_rendering + "out vec4 gl_PositionPerViewNV[];" // GL_NVX_multiview_per_view_attributes + "out int gl_ViewportMaskPerViewNV[];" // GL_NVX_multiview_per_view_attributes ); +#endif + stageBuiltins[EShLangGeometry].append("\n"); } else if (profile == EEsProfile && version >= 310) { stageBuiltins[EShLangGeometry].append( @@ -2129,6 +5400,13 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV ); } + if ((profile != EEsProfile && version >= 140) || + (profile == EEsProfile && version >= 310)) { + stageBuiltins[EShLangGeometry].append( + "in highp int gl_DeviceIndex;" // GL_EXT_device_group + "in highp int gl_ViewIndex;" // GL_EXT_multiview + "\n"); + } //============================================================================ // @@ -2163,6 +5441,13 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV if (version >= 450) stageBuiltins[EShLangTessControl].append( "float gl_CullDistance[];" +#ifdef NV_EXTENSIONS + "int gl_ViewportMask[];" // GL_NV_viewport_array2 + "vec4 gl_SecondaryPositionNV;" // GL_NV_stereo_view_rendering + "int gl_SecondaryViewportMaskNV[];" // GL_NV_stereo_view_rendering + "vec4 gl_PositionPerViewNV[];" // GL_NVX_multiview_per_view_attributes + "int gl_ViewportMaskPerViewNV[];" // GL_NVX_multiview_per_view_attributes +#endif ); stageBuiltins[EShLangTessControl].append( "} gl_out[];" @@ -2170,6 +5455,13 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "patch out float gl_TessLevelOuter[4];" "patch out float gl_TessLevelInner[2];" "\n"); + + if (version >= 410) + stageBuiltins[EShLangTessControl].append( + "out int gl_ViewportIndex;" + "out int gl_Layer;" + "\n"); + } else { // Note: "in gl_PerVertex {...} gl_in[gl_MaxPatchVertices];" is declared in initialize() below, // as it depends on the resource sizing of gl_MaxPatchVertices. @@ -2192,6 +5484,14 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } + if ((profile != EEsProfile && version >= 140) || + (profile == EEsProfile && version >= 310)) { + stageBuiltins[EShLangTessControl].append( + "in highp int gl_DeviceIndex;" // GL_EXT_device_group + "in highp int gl_ViewIndex;" // GL_EXT_multiview + "\n"); + } + //============================================================================ // // Define the interface to the tessellation evaluation shader. @@ -2209,7 +5509,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "patch in float gl_TessLevelOuter[4];" "patch in float gl_TessLevelInner[2];" - + "out gl_PerVertex {" "vec4 gl_Position;" "float gl_PointSize;" @@ -2232,6 +5532,24 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV stageBuiltins[EShLangTessEvaluation].append( "};" "\n"); + + if (version >= 410) + stageBuiltins[EShLangTessEvaluation].append( + "out int gl_ViewportIndex;" + "out int gl_Layer;" + "\n"); + +#ifdef NV_EXTENSIONS + if (version >= 450) + stageBuiltins[EShLangTessEvaluation].append( + "out int gl_ViewportMask[];" // GL_NV_viewport_array2 + "out vec4 gl_SecondaryPositionNV;" // GL_NV_stereo_view_rendering + "out int gl_SecondaryViewportMaskNV[];" // GL_NV_stereo_view_rendering + "out vec4 gl_PositionPerViewNV[];" // GL_NVX_multiview_per_view_attributes + "out int gl_ViewportMaskPerViewNV[];" // GL_NVX_multiview_per_view_attributes + ); +#endif + } else if (profile == EEsProfile && version >= 310) { // Note: "in gl_PerVertex {...} gl_in[gl_MaxPatchVertices];" is declared in initialize() below, // as it depends on the resource sizing of gl_MaxPatchVertices. @@ -2243,7 +5561,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "patch in highp float gl_TessLevelOuter[4];" "patch in highp float gl_TessLevelInner[2];" - + "out gl_PerVertex {" "highp vec4 gl_Position;" "highp float gl_PointSize;" @@ -2253,6 +5571,14 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } + if ((profile != EEsProfile && version >= 140) || + (profile == EEsProfile && version >= 310)) { + stageBuiltins[EShLangTessEvaluation].append( + "in highp int gl_DeviceIndex;" // GL_EXT_device_group + "in highp int gl_ViewIndex;" // GL_EXT_multiview + "\n"); + } + //============================================================================ // // Define the interface to the fragment shader. @@ -2270,6 +5596,10 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV stageBuiltins[EShLangFragment].append( "vec2 gl_PointCoord;" // needs qualifier fixed later ); + if (version >= 140) + stageBuiltins[EShLangFragment].append( + "out int gl_FragStencilRefARB;" + ); if (IncludeLegacy(version, profile, spvVersion) || (! ForwardCompatibility && version < 420)) stageBuiltins[EShLangFragment].append( "vec4 gl_FragColor;" // needs qualifier fixed later @@ -2312,14 +5642,18 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "flat in int gl_PrimitiveID;" ); - if (version >= 400) + if (version >= 400) { stageBuiltins[EShLangFragment].append( "flat in int gl_SampleID;" " in vec2 gl_SamplePosition;" "flat in int gl_SampleMaskIn[];" " out int gl_SampleMask[];" - "uniform int gl_NumSamples;" ); + if (spvVersion.spv == 0) + stageBuiltins[EShLangFragment].append( + "uniform int gl_NumSamples;" + ); + } if (version >= 430) stageBuiltins[EShLangFragment].append( @@ -2332,6 +5666,26 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "in float gl_CullDistance[];" "bool gl_HelperInvocation;" // needs qualifier fixed later ); + +#ifdef AMD_EXTENSIONS + if (version >= 450) + stageBuiltins[EShLangFragment].append( + "in vec2 gl_BaryCoordNoPerspAMD;" + "in vec2 gl_BaryCoordNoPerspCentroidAMD;" + "in vec2 gl_BaryCoordNoPerspSampleAMD;" + "in vec2 gl_BaryCoordSmoothAMD;" + "in vec2 gl_BaryCoordSmoothCentroidAMD;" + "in vec2 gl_BaryCoordSmoothSampleAMD;" + "in vec3 gl_BaryCoordPullModelAMD;" + ); +#endif + +#ifdef NV_EXTENSIONS + if (version >= 430) + stageBuiltins[EShLangFragment].append( + "in bool gl_FragFullyCoveredNV;" + ); +#endif } else { // ES profile @@ -2359,12 +5713,15 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV ); stageBuiltins[EShLangFragment].append( // GL_OES_sample_variables - "flat lowp in int gl_SampleID;" - " mediump in vec2 gl_SamplePosition;" - "flat highp in int gl_SampleMaskIn[];" - " highp out int gl_SampleMask[];" - "uniform lowp int gl_NumSamples;" + "flat in lowp int gl_SampleID;" + " in mediump vec2 gl_SamplePosition;" + "flat in highp int gl_SampleMaskIn[];" + " out highp int gl_SampleMask[];" ); + if (spvVersion.spv == 0) + stageBuiltins[EShLangFragment].append( // GL_OES_sample_variables + "uniform lowp int gl_NumSamples;" + ); } stageBuiltins[EShLangFragment].append( "highp float gl_FragDepthEXT;" // GL_EXT_frag_depth @@ -2377,25 +5734,85 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV // GL_ARB_shader_ballot if (profile != EEsProfile && version >= 450) { - commonBuiltins.append( + const char* ballotDecls = "uniform uint gl_SubGroupSizeARB;" - "in uint gl_SubGroupInvocationARB;" "in uint64_t gl_SubGroupEqMaskARB;" "in uint64_t gl_SubGroupGeMaskARB;" "in uint64_t gl_SubGroupGtMaskARB;" "in uint64_t gl_SubGroupLeMaskARB;" "in uint64_t gl_SubGroupLtMaskARB;" + "\n"; + const char* fragmentBallotDecls = + "uniform uint gl_SubGroupSizeARB;" + "flat in uint gl_SubGroupInvocationARB;" + "flat in uint64_t gl_SubGroupEqMaskARB;" + "flat in uint64_t gl_SubGroupGeMaskARB;" + "flat in uint64_t gl_SubGroupGtMaskARB;" + "flat in uint64_t gl_SubGroupLeMaskARB;" + "flat in uint64_t gl_SubGroupLtMaskARB;" + "\n"; + stageBuiltins[EShLangVertex] .append(ballotDecls); + stageBuiltins[EShLangTessControl] .append(ballotDecls); + stageBuiltins[EShLangTessEvaluation].append(ballotDecls); + stageBuiltins[EShLangGeometry] .append(ballotDecls); + stageBuiltins[EShLangCompute] .append(ballotDecls); + stageBuiltins[EShLangFragment] .append(fragmentBallotDecls); + } + if ((profile != EEsProfile && version >= 140) || + (profile == EEsProfile && version >= 310)) { + stageBuiltins[EShLangFragment].append( + "flat in highp int gl_DeviceIndex;" // GL_EXT_device_group + "flat in highp int gl_ViewIndex;" // GL_EXT_multiview "\n"); } - //printf("%s\n", commonBuiltins.c_str()); - //printf("%s\n", stageBuiltins[EShLangFragment].c_str()); + // GL_KHR_shader_subgroup + if (spvVersion.vulkan > 0) { + const char* ballotDecls = + "in mediump uint gl_SubgroupSize;" + "in mediump uint gl_SubgroupInvocationID;" + "in highp uvec4 gl_SubgroupEqMask;" + "in highp uvec4 gl_SubgroupGeMask;" + "in highp uvec4 gl_SubgroupGtMask;" + "in highp uvec4 gl_SubgroupLeMask;" + "in highp uvec4 gl_SubgroupLtMask;" + "\n"; + const char* fragmentBallotDecls = + "flat in mediump uint gl_SubgroupSize;" + "flat in mediump uint gl_SubgroupInvocationID;" + "flat in highp uvec4 gl_SubgroupEqMask;" + "flat in highp uvec4 gl_SubgroupGeMask;" + "flat in highp uvec4 gl_SubgroupGtMask;" + "flat in highp uvec4 gl_SubgroupLeMask;" + "flat in highp uvec4 gl_SubgroupLtMask;" + "\n"; + stageBuiltins[EShLangVertex] .append(ballotDecls); + stageBuiltins[EShLangTessControl] .append(ballotDecls); + stageBuiltins[EShLangTessEvaluation].append(ballotDecls); + stageBuiltins[EShLangGeometry] .append(ballotDecls); + stageBuiltins[EShLangCompute] .append(ballotDecls); + stageBuiltins[EShLangFragment] .append(fragmentBallotDecls); + + stageBuiltins[EShLangCompute].append( + "highp in uint gl_NumSubgroups;" + "highp in uint gl_SubgroupID;" + "\n"); + } + + if (version >= 300 /* both ES and non-ES */) { + stageBuiltins[EShLangFragment].append( + "flat in highp uint gl_ViewID_OVR;" // GL_OVR_multiview, GL_OVR_multiview2 + "\n"); + } + + // printf("%s\n", commonBuiltins.c_str()); + // printf("%s\n", stageBuiltins[EShLangFragment].c_str()); } // -// Helper function for initialize(), to add the second set of names for texturing, +// Helper function for initialize(), to add the second set of names for texturing, // when adding context-independent built-in functions. // void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, const SpvVersion& spvVersion) @@ -2404,8 +5821,11 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, c // In this function proper, enumerate the types, then calls the next set of functions // to enumerate all the uses for that type. // - +#ifdef AMD_EXTENSIONS + TBasicType bTypes[4] = { EbtFloat, EbtFloat16, EbtInt, EbtUint }; +#else TBasicType bTypes[3] = { EbtFloat, EbtInt, EbtUint }; +#endif bool skipBuffer = (profile == EEsProfile && version < 310) || (profile != EEsProfile && version < 140); bool skipCubeArrayed = (profile == EEsProfile && version < 310) || (profile != EEsProfile && version < 130); @@ -2445,12 +5865,20 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, c continue; if (ms && arrayed && profile == EEsProfile && version < 310) continue; +#ifdef AMD_EXTENSIONS + for (int bType = 0; bType < 4; ++bType) { // float, float16, int, uint results + if (shadow && bType > 1) + continue; + + if (bTypes[bType] == EbtFloat16 && (profile == EEsProfile ||version < 450)) + continue; +#else for (int bType = 0; bType < 3; ++bType) { // float, int, uint results if (shadow && bType > 0) continue; - +#endif if (dim == EsdRect && version < 140 && bType > 0) continue; @@ -2485,6 +5913,17 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, c else { addSamplingFunctions(sampler, typeName, version, profile); addGatherFunctions(sampler, typeName, version, profile); + + if (spvVersion.vulkan > 0 && sampler.dim == EsdBuffer && sampler.isCombined()) { + // Vulkan wants a textureBuffer to allow texelFetch() -- + // a sampled image with no sampler. + // So, add sampling functions for both the + // samplerBuffer and textureBuffer types. + sampler.setTexture(sampler.type, sampler.dim, sampler.arrayed, sampler.shadow, + sampler.ms); + TString textureTypeName = sampler.getString(); + addSamplingFunctions(sampler, textureTypeName, version, profile); + } } } } @@ -2503,12 +5942,12 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, c } // -// Helper function for add2ndGenerationSamplingImaging(), +// Helper function for add2ndGenerationSamplingImaging(), // when adding context-independent built-in functions. // // Add all the query functions for the given type. // -void TBuiltIns::addQueryFunctions(TSampler sampler, TString& typeName, int version, EProfile profile) +void TBuiltIns::addQueryFunctions(TSampler sampler, const TString& typeName, int version, EProfile profile) { if (sampler.image && ((profile == EEsProfile && version < 310) || (profile != EEsProfile && version < 430))) return; @@ -2557,15 +5996,37 @@ void TBuiltIns::addQueryFunctions(TSampler sampler, TString& typeName, int versi // if (profile != EEsProfile && version >= 400 && ! sampler.image && sampler.dim != EsdRect && ! sampler.ms && sampler.dim != EsdBuffer) { - stageBuiltins[EShLangFragment].append("vec2 textureQueryLod("); - stageBuiltins[EShLangFragment].append(typeName); - if (dimMap[sampler.dim] == 1) - stageBuiltins[EShLangFragment].append(", float"); - else { - stageBuiltins[EShLangFragment].append(", vec"); - stageBuiltins[EShLangFragment].append(postfixes[dimMap[sampler.dim]]); +#ifdef AMD_EXTENSIONS + for (int f16TexAddr = 0; f16TexAddr < 2; ++f16TexAddr) { + if (f16TexAddr && sampler.type != EbtFloat16) + continue; +#endif + stageBuiltins[EShLangFragment].append("vec2 textureQueryLod("); + stageBuiltins[EShLangFragment].append(typeName); + if (dimMap[sampler.dim] == 1) +#ifdef AMD_EXTENSIONS + if (f16TexAddr) + stageBuiltins[EShLangFragment].append(", float16_t"); + else + stageBuiltins[EShLangFragment].append(", float"); +#else + stageBuiltins[EShLangFragment].append(", float"); +#endif + else { +#ifdef AMD_EXTENSIONS + if (f16TexAddr) + stageBuiltins[EShLangFragment].append(", f16vec"); + else + stageBuiltins[EShLangFragment].append(", vec"); +#else + stageBuiltins[EShLangFragment].append(", vec"); +#endif + stageBuiltins[EShLangFragment].append(postfixes[dimMap[sampler.dim]]); + } + stageBuiltins[EShLangFragment].append(");\n"); +#ifdef AMD_EXTENSIONS } - stageBuiltins[EShLangFragment].append(");\n"); +#endif } // @@ -2580,12 +6041,12 @@ void TBuiltIns::addQueryFunctions(TSampler sampler, TString& typeName, int versi } // -// Helper function for add2ndGenerationSamplingImaging(), +// Helper function for add2ndGenerationSamplingImaging(), // when adding context-independent built-in functions. // // Add all the image access functions for the given type. // -void TBuiltIns::addImageFunctions(TSampler sampler, TString& typeName, int version, EProfile profile) +void TBuiltIns::addImageFunctions(TSampler sampler, const TString& typeName, int version, EProfile profile) { int dims = dimMap[sampler.dim]; // most things with an array add a dimension, except for cubemaps @@ -2639,7 +6100,7 @@ void TBuiltIns::addImageFunctions(TSampler sampler, TString& typeName, int versi " imageAtomicOr(volatile coherent ", " imageAtomicXor(volatile coherent ", " imageAtomicExchange(volatile coherent " - }; + }; for (size_t i = 0; i < numBuiltins; ++i) { commonBuiltins.append(dataType); @@ -2670,6 +6131,43 @@ void TBuiltIns::addImageFunctions(TSampler sampler, TString& typeName, int versi } } } + +#ifdef AMD_EXTENSIONS + if (sampler.dim == EsdRect || sampler.dim == EsdBuffer || sampler.shadow || sampler.ms) + return; + + if (profile == EEsProfile || version < 450) + return; + + TString imageLodParams = typeName; + if (dims == 1) + imageLodParams.append(", int"); + else { + imageLodParams.append(", ivec"); + imageLodParams.append(postfixes[dims]); + } + imageLodParams.append(", int"); + + commonBuiltins.append(prefixes[sampler.type]); + commonBuiltins.append("vec4 imageLoadLodAMD(readonly volatile coherent "); + commonBuiltins.append(imageLodParams); + commonBuiltins.append(");\n"); + + commonBuiltins.append("void imageStoreLodAMD(writeonly volatile coherent "); + commonBuiltins.append(imageLodParams); + commonBuiltins.append(", "); + commonBuiltins.append(prefixes[sampler.type]); + commonBuiltins.append("vec4);\n"); + + if (sampler.dim != Esd1D) { + commonBuiltins.append("int sparseImageLoadLodAMD(readonly volatile coherent "); + commonBuiltins.append(imageLodParams); + commonBuiltins.append(", out "); + commonBuiltins.append(prefixes[sampler.type]); + commonBuiltins.append("vec4"); + commonBuiltins.append(");\n"); + } +#endif } // @@ -2678,7 +6176,7 @@ void TBuiltIns::addImageFunctions(TSampler sampler, TString& typeName, int versi // // Add all the subpass access functions for the given type. // -void TBuiltIns::addSubpassSampling(TSampler sampler, TString& typeName, int /*version*/, EProfile /*profile*/) +void TBuiltIns::addSubpassSampling(TSampler sampler, const TString& typeName, int /*version*/, EProfile /*profile*/) { stageBuiltins[EShLangFragment].append(prefixes[sampler.type]); stageBuiltins[EShLangFragment].append("vec4 subpassLoad"); @@ -2690,12 +6188,12 @@ void TBuiltIns::addSubpassSampling(TSampler sampler, TString& typeName, int /*ve } // -// Helper function for add2ndGenerationSamplingImaging(), +// Helper function for add2ndGenerationSamplingImaging(), // when adding context-independent built-in functions. // // Add all the texture lookup functions for the given type. // -void TBuiltIns::addSamplingFunctions(TSampler sampler, TString& typeName, int version, EProfile profile) +void TBuiltIns::addSamplingFunctions(TSampler sampler, const TString& typeName, int version, EProfile profile) { // // texturing @@ -2718,7 +6216,7 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, TString& typeName, int ve if (bias && (lod || sampler.ms)) continue; - if (bias && sampler.dim == Esd2D && sampler.shadow && sampler.arrayed) + if (bias && (sampler.dim == Esd2D || sampler.dim == EsdCube) && sampler.shadow && sampler.arrayed) continue; if (bias && (sampler.dim == EsdRect || sampler.dim == EsdBuffer)) continue; @@ -2767,149 +6265,237 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, TString& typeName, int ve continue; if (extraProj && (sampler.dim == Esd3D || sampler.shadow)) continue; +#ifdef AMD_EXTENSIONS + for (int f16TexAddr = 0; f16TexAddr <= 1; ++f16TexAddr) { // loop over 16-bit floating-point texel addressing - for (int lodClamp = 0; lodClamp <= 1 ;++lodClamp) { // loop over "bool" lod clamp - - if (lodClamp && (profile == EEsProfile || version < 450)) + if (f16TexAddr && sampler.type != EbtFloat16) continue; - if (lodClamp && (proj || lod || fetch)) - continue; - - for (int sparse = 0; sparse <= 1; ++sparse) { // loop over "bool" sparse or not - - if (sparse && (profile == EEsProfile || version < 450)) - continue; - // Sparse sampling is not for 1D/1D array texture, buffer texture, and projective texture - if (sparse && (sampler.dim == Esd1D || sampler.dim == EsdBuffer || proj)) - continue; - - TString s; - - // return type - if (sparse) - s.append("int "); - else { - if (sampler.shadow) - s.append("float "); - else { - s.append(prefixes[sampler.type]); - s.append("vec4 "); - } - } - - // name - if (sparse) { - if (fetch) - s.append("sparseTexel"); - else - s.append("sparseTexture"); - } else { - if (fetch) - s.append("texel"); - else - s.append("texture"); - } - if (proj) - s.append("Proj"); - if (lod) - s.append("Lod"); - if (grad) - s.append("Grad"); - if (fetch) - s.append("Fetch"); - if (offset) - s.append("Offset"); - if (lodClamp) - s.append("Clamp"); - if (lodClamp || sparse) - s.append("ARB"); - s.append("("); - - // sampler type - s.append(typeName); - - // P coordinate - if (extraProj) - s.append(",vec4"); - else { - s.append(","); - TBasicType t = fetch ? EbtInt : EbtFloat; - if (totalDims == 1) - s.append(TType::getBasicString(t)); - else { - s.append(prefixes[t]); - s.append("vec"); - s.append(postfixes[totalDims]); - } - } - - if (bias && compare) - continue; - - // non-optional lod argument (lod that's not driven by lod loop) or sample - if ((fetch && sampler.dim != EsdBuffer && sampler.dim != EsdRect && !sampler.ms) || - (sampler.ms && fetch)) - s.append(",int"); - - // non-optional lod - if (lod) - s.append(",float"); - - // gradient arguments - if (grad) { - if (dimMap[sampler.dim] == 1) - s.append(",float,float"); - else { - s.append(",vec"); - s.append(postfixes[dimMap[sampler.dim]]); - s.append(",vec"); - s.append(postfixes[dimMap[sampler.dim]]); - } - } - - // offset - if (offset) { - if (dimMap[sampler.dim] == 1) - s.append(",int"); - else { - s.append(",ivec"); - s.append(postfixes[dimMap[sampler.dim]]); - } - } - - // non-optional compare - if (compare) - s.append(",float"); - - // lod clamp - if (lodClamp) - s.append(",float"); - - // texel out (for sparse texture) - if (sparse) { - s.append(",out "); - if (sampler.shadow) - s.append("float "); - else { - s.append(prefixes[sampler.type]); - s.append("vec4 "); - } - } - - // optional bias - if (bias) - s.append(",float"); - - s.append(");\n"); - - // Add to the per-language set of built-ins - - if (bias) - stageBuiltins[EShLangFragment].append(s); - else - commonBuiltins.append(s); + if (f16TexAddr && sampler.shadow && ! compare) { + compare = true; // compare argument is always present + totalDims--; } +#endif + for (int lodClamp = 0; lodClamp <= 1 ;++lodClamp) { // loop over "bool" lod clamp + + if (lodClamp && (profile == EEsProfile || version < 450)) + continue; + if (lodClamp && (proj || lod || fetch)) + continue; + + for (int sparse = 0; sparse <= 1; ++sparse) { // loop over "bool" sparse or not + + if (sparse && (profile == EEsProfile || version < 450)) + continue; + // Sparse sampling is not for 1D/1D array texture, buffer texture, and projective texture + if (sparse && (sampler.dim == Esd1D || sampler.dim == EsdBuffer || proj)) + continue; + + TString s; + + // return type + if (sparse) + s.append("int "); + else { + if (sampler.shadow) +#ifdef AMD_EXTENSIONS + if (sampler.type == EbtFloat16) + s.append("float16_t "); + else + s.append("float "); +#else + s.append("float "); +#endif + else { + s.append(prefixes[sampler.type]); + s.append("vec4 "); + } + } + + // name + if (sparse) { + if (fetch) + s.append("sparseTexel"); + else + s.append("sparseTexture"); + } + else { + if (fetch) + s.append("texel"); + else + s.append("texture"); + } + if (proj) + s.append("Proj"); + if (lod) + s.append("Lod"); + if (grad) + s.append("Grad"); + if (fetch) + s.append("Fetch"); + if (offset) + s.append("Offset"); + if (lodClamp) + s.append("Clamp"); + if (lodClamp || sparse) + s.append("ARB"); + s.append("("); + + // sampler type + s.append(typeName); +#ifdef AMD_EXTENSIONS + // P coordinate + if (extraProj) { + if (f16TexAddr) + s.append(",f16vec4"); + else + s.append(",vec4"); + } else { + s.append(","); + TBasicType t = fetch ? EbtInt : (f16TexAddr ? EbtFloat16 : EbtFloat); + if (totalDims == 1) + s.append(TType::getBasicString(t)); + else { + s.append(prefixes[t]); + s.append("vec"); + s.append(postfixes[totalDims]); + } + } +#else + // P coordinate + if (extraProj) + s.append(",vec4"); + else { + s.append(","); + TBasicType t = fetch ? EbtInt : EbtFloat; + if (totalDims == 1) + s.append(TType::getBasicString(t)); + else { + s.append(prefixes[t]); + s.append("vec"); + s.append(postfixes[totalDims]); + } + } +#endif + // non-optional compare + if (compare) + s.append(",float"); + + // non-optional lod argument (lod that's not driven by lod loop) or sample + if ((fetch && sampler.dim != EsdBuffer && sampler.dim != EsdRect && !sampler.ms) || + (sampler.ms && fetch)) + s.append(",int"); +#ifdef AMD_EXTENSIONS + // non-optional lod + if (lod) { + if (f16TexAddr) + s.append(",float16_t"); + else + s.append(",float"); + } + + // gradient arguments + if (grad) { + if (dimMap[sampler.dim] == 1) { + if (f16TexAddr) + s.append(",float16_t,float16_t"); + else + s.append(",float,float"); + } else { + if (f16TexAddr) + s.append(",f16vec"); + else + s.append(",vec"); + s.append(postfixes[dimMap[sampler.dim]]); + if (f16TexAddr) + s.append(",f16vec"); + else + s.append(",vec"); + s.append(postfixes[dimMap[sampler.dim]]); + } + } +#else + // non-optional lod + if (lod) + s.append(",float"); + + // gradient arguments + if (grad) { + if (dimMap[sampler.dim] == 1) + s.append(",float,float"); + else { + s.append(",vec"); + s.append(postfixes[dimMap[sampler.dim]]); + s.append(",vec"); + s.append(postfixes[dimMap[sampler.dim]]); + } + } +#endif + // offset + if (offset) { + if (dimMap[sampler.dim] == 1) + s.append(",int"); + else { + s.append(",ivec"); + s.append(postfixes[dimMap[sampler.dim]]); + } + } + +#ifdef AMD_EXTENSIONS + // lod clamp + if (lodClamp) { + if (f16TexAddr) + s.append(",float16_t"); + else + s.append(",float"); + } +#else + // lod clamp + if (lodClamp) + s.append(",float"); +#endif + // texel out (for sparse texture) + if (sparse) { + s.append(",out "); + if (sampler.shadow) +#ifdef AMD_EXTENSIONS + if (sampler.type == EbtFloat16) + s.append("float16_t"); + else + s.append("float"); +#else + s.append("float"); +#endif + else { + s.append(prefixes[sampler.type]); + s.append("vec4"); + } + } +#ifdef AMD_EXTENSIONS + // optional bias + if (bias) { + if (f16TexAddr) + s.append(",float16_t"); + else + s.append(",float"); + } +#else + // optional bias + if (bias) + s.append(",float"); +#endif + s.append(");\n"); + + // Add to the per-language set of built-ins + if (bias || lodClamp) + stageBuiltins[EShLangFragment].append(s); + else + commonBuiltins.append(s); + + } + } +#ifdef AMD_EXTENSIONS } +#endif } } } @@ -2919,14 +6505,13 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, TString& typeName, int ve } } - // -// Helper function for add2ndGenerationSamplingImaging(), +// Helper function for add2ndGenerationSamplingImaging(), // when adding context-independent built-in functions. // // Add all the texture gather functions for the given type. // -void TBuiltIns::addGatherFunctions(TSampler sampler, TString& typeName, int version, EProfile profile) +void TBuiltIns::addGatherFunctions(TSampler sampler, const TString& typeName, int version, EProfile profile) { switch (sampler.dim) { case Esd2D: @@ -2943,83 +6528,228 @@ void TBuiltIns::addGatherFunctions(TSampler sampler, TString& typeName, int vers if (version < 140 && sampler.dim == EsdRect && sampler.type != EbtFloat) return; - for (int offset = 0; offset < 3; ++offset) { // loop over three forms of offset in the call name: none, Offset, and Offsets +#ifdef AMD_EXTENSIONS + for (int f16TexAddr = 0; f16TexAddr <= 1; ++f16TexAddr) { // loop over 16-bit floating-point texel addressing - for (int comp = 0; comp < 2; ++comp) { // loop over presence of comp argument + if (f16TexAddr && sampler.type != EbtFloat16) + continue; +#endif + for (int offset = 0; offset < 3; ++offset) { // loop over three forms of offset in the call name: none, Offset, and Offsets - if (comp > 0 && sampler.shadow) - continue; + for (int comp = 0; comp < 2; ++comp) { // loop over presence of comp argument - if (offset > 0 && sampler.dim == EsdCube) - continue; - - for (int sparse = 0; sparse <= 1; ++sparse) { // loop over "bool" sparse or not - if (sparse && (profile == EEsProfile || version < 450)) + if (comp > 0 && sampler.shadow) continue; - TString s; + if (offset > 0 && sampler.dim == EsdCube) + continue; - // return type - if (sparse) - s.append("int "); - else { - s.append(prefixes[sampler.type]); - s.append("vec4 "); + for (int sparse = 0; sparse <= 1; ++sparse) { // loop over "bool" sparse or not + if (sparse && (profile == EEsProfile || version < 450)) + continue; + + TString s; + + // return type + if (sparse) + s.append("int "); + else { + s.append(prefixes[sampler.type]); + s.append("vec4 "); + } + + // name + if (sparse) + s.append("sparseTextureGather"); + else + s.append("textureGather"); + switch (offset) { + case 1: + s.append("Offset"); + break; + case 2: + s.append("Offsets"); + break; + default: + break; + } + if (sparse) + s.append("ARB"); + s.append("("); + + // sampler type argument + s.append(typeName); + + // P coordinate argument +#ifdef AMD_EXTENSIONS + if (f16TexAddr) + s.append(",f16vec"); + else + s.append(",vec"); +#else + s.append(",vec"); +#endif + int totalDims = dimMap[sampler.dim] + (sampler.arrayed ? 1 : 0); + s.append(postfixes[totalDims]); + + // refZ argument + if (sampler.shadow) + s.append(",float"); + + // offset argument + if (offset > 0) { + s.append(",ivec2"); + if (offset == 2) + s.append("[4]"); + } + + // texel out (for sparse texture) + if (sparse) { + s.append(",out "); + s.append(prefixes[sampler.type]); + s.append("vec4 "); + } + + // comp argument + if (comp) + s.append(",int"); + + s.append(");\n"); + commonBuiltins.append(s); +#ifdef AMD_EXTENSIONS } - - // name - if (sparse) - s.append("sparseTextureGather"); - else - s.append("textureGather"); - switch (offset) { - case 1: - s.append("Offset"); - break; - case 2: - s.append("Offsets"); - default: - break; - } - if (sparse) - s.append("ARB"); - s.append("("); - - // sampler type argument - s.append(typeName); - - // P coordinate argument - s.append(",vec"); - int totalDims = dimMap[sampler.dim] + (sampler.arrayed ? 1 : 0); - s.append(postfixes[totalDims]); - - // refZ argument - if (sampler.shadow) - s.append(",float"); - - // offset argument - if (offset > 0) { - s.append(",ivec2"); - if (offset == 2) - s.append("[4]"); - } - - // texel out (for sparse texture) - if (sparse) { - s.append(",out "); - s.append(prefixes[sampler.type]); - s.append("vec4 "); - } - - // comp argument - if (comp) - s.append(",int"); - - s.append(");\n"); - commonBuiltins.append(s); +#endif } } } + +#ifdef AMD_EXTENSIONS + if (sampler.dim == EsdRect || sampler.shadow) + return; + + if (profile == EEsProfile || version < 450) + return; + + for (int bias = 0; bias < 2; ++bias) { // loop over presence of bias argument + + for (int lod = 0; lod < 2; ++lod) { // loop over presence of lod argument + + if ((lod && bias) || (lod == 0 && bias == 0)) + continue; + + for (int f16TexAddr = 0; f16TexAddr <= 1; ++f16TexAddr) { // loop over 16-bit floating-point texel addressing + + if (f16TexAddr && sampler.type != EbtFloat16) + continue; + + for (int offset = 0; offset < 3; ++offset) { // loop over three forms of offset in the call name: none, Offset, and Offsets + + for (int comp = 0; comp < 2; ++comp) { // loop over presence of comp argument + + if (comp == 0 && bias) + continue; + + if (offset > 0 && sampler.dim == EsdCube) + continue; + + for (int sparse = 0; sparse <= 1; ++sparse) { // loop over "bool" sparse or not + if (sparse && (profile == EEsProfile || version < 450)) + continue; + + TString s; + + // return type + if (sparse) + s.append("int "); + else { + s.append(prefixes[sampler.type]); + s.append("vec4 "); + } + + // name + if (sparse) + s.append("sparseTextureGather"); + else + s.append("textureGather"); + + if (lod) + s.append("Lod"); + + switch (offset) { + case 1: + s.append("Offset"); + break; + case 2: + s.append("Offsets"); + break; + default: + break; + } + + if (lod) + s.append("AMD"); + else if (sparse) + s.append("ARB"); + + s.append("("); + + // sampler type argument + s.append(typeName); + + // P coordinate argument + if (f16TexAddr) + s.append(",f16vec"); + else + s.append(",vec"); + int totalDims = dimMap[sampler.dim] + (sampler.arrayed ? 1 : 0); + s.append(postfixes[totalDims]); + + // lod argument + if (lod) { + if (f16TexAddr) + s.append(",float16_t"); + else + s.append(",float"); + } + + // offset argument + if (offset > 0) { + s.append(",ivec2"); + if (offset == 2) + s.append("[4]"); + } + + // texel out (for sparse texture) + if (sparse) { + s.append(",out "); + s.append(prefixes[sampler.type]); + s.append("vec4 "); + } + + // comp argument + if (comp) + s.append(",int"); + + // bias argument + if (bias) { + if (f16TexAddr) + s.append(",float16_t"); + else + s.append(",float"); + } + + s.append(");\n"); + if (bias) + stageBuiltins[EShLangFragment].append(s); + else + commonBuiltins.append(s); + } + } + } + } + } + } +#endif } // @@ -3122,7 +6852,7 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf s.append(builtInConstant); snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlTotalOutputComponents = %d;", resources.maxTessControlTotalOutputComponents); s.append(builtInConstant); - + snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationInputComponents = %d;", resources.maxTessEvaluationInputComponents); s.append(builtInConstant); snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationOutputComponents = %d;", resources.maxTessEvaluationOutputComponents); @@ -3131,7 +6861,7 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf s.append(builtInConstant); snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationUniformComponents = %d;", resources.maxTessEvaluationUniformComponents); s.append(builtInConstant); - + snprintf(builtInConstant, maxSize, "const int gl_MaxTessPatchComponents = %d;", resources.maxTessPatchComponents); s.append(builtInConstant); @@ -3146,6 +6876,10 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf "in gl_PerVertex {" "highp vec4 gl_Position;" "highp float gl_PointSize;" +#ifdef NV_EXTENSIONS + "highp vec4 gl_SecondaryPositionNV;" // GL_NV_stereo_view_rendering + "highp vec4 gl_PositionPerViewNV[];" // GL_NVX_multiview_per_view_attributes +#endif "} gl_in[gl_MaxPatchVertices];" "\n"); } @@ -3294,7 +7028,7 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf s.append(builtInConstant); snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlTotalOutputComponents = %d;", resources.maxTessControlTotalOutputComponents); s.append(builtInConstant); - + snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationInputComponents = %d;", resources.maxTessEvaluationInputComponents); s.append(builtInConstant); snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationOutputComponents = %d;", resources.maxTessEvaluationOutputComponents); @@ -3303,7 +7037,7 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf s.append(builtInConstant); snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationUniformComponents = %d;", resources.maxTessEvaluationUniformComponents); s.append(builtInConstant); - + snprintf(builtInConstant, maxSize, "const int gl_MaxTessPatchComponents = %d;", resources.maxTessPatchComponents); s.append(builtInConstant); snprintf(builtInConstant, maxSize, "const int gl_MaxTessGenLevel = %d;", resources.maxTessGenLevel); @@ -3332,6 +7066,10 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf if (profile != EEsProfile && version >= 450) s.append( "float gl_CullDistance[];" +#ifdef NV_EXTENSIONS + "vec4 gl_SecondaryPositionNV;" // GL_NV_stereo_view_rendering + "vec4 gl_PositionPerViewNV[];" // GL_NVX_multiview_per_view_attributes +#endif ); s.append( "} gl_in[gl_MaxPatchVertices];" @@ -3368,7 +7106,7 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf } // images (some in compute below) - if ((profile == EEsProfile && version >= 310) || + if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 130)) { snprintf(builtInConstant, maxSize, "const int gl_MaxImageUnits = %d;", resources.maxImageUnits); s.append(builtInConstant); @@ -3383,7 +7121,7 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf } // atomic counters (some in compute below) - if ((profile == EEsProfile && version >= 310) || + if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 420)) { snprintf(builtInConstant, maxSize, "const int gl_MaxVertexAtomicCounters = %d;", resources. maxVertexAtomicCounters); s.append(builtInConstant); @@ -3419,12 +7157,11 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf s.append("\n"); } - // compute if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 420)) { snprintf(builtInConstant, maxSize, "const ivec3 gl_MaxComputeWorkGroupCount = ivec3(%d,%d,%d);", resources.maxComputeWorkGroupCountX, resources.maxComputeWorkGroupCountY, - resources.maxComputeWorkGroupCountZ); + resources.maxComputeWorkGroupCountZ); s.append(builtInConstant); snprintf(builtInConstant, maxSize, "const ivec3 gl_MaxComputeWorkGroupSize = ivec3(%d,%d,%d);", resources.maxComputeWorkGroupSizeX, resources.maxComputeWorkGroupSizeY, @@ -3460,6 +7197,14 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf s.append(builtInConstant); } +#ifdef AMD_EXTENSIONS + // GL_AMD_gcn_shader + if (profile != EEsProfile && version >= 450) { + snprintf(builtInConstant, maxSize, "const int gl_SIMDGroupSizeAMD = 64;"); + s.append(builtInConstant); + } +#endif + s.append("\n"); } @@ -3546,23 +7291,26 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion // N.B.: a symbol should only be tagged once, and this function is called multiple times, once // per stage that's used for this profile. So // - generally, stick common ones in the fragment stage to ensure they are tagged exactly once - // - for ES, which has different precisions for different stages, the coarsest-grained tagging + // - for ES, which has different precisions for different stages, the coarsest-grained tagging // for a built-in used in many stages needs to be once for the fragment stage and once for // the vertex stage switch(language) { case EShLangVertex: if (profile != EEsProfile) { - symbolTable.setVariableExtensions("gl_BaseVertexARB", 1, &E_GL_ARB_shader_draw_parameters); - symbolTable.setVariableExtensions("gl_BaseInstanceARB", 1, &E_GL_ARB_shader_draw_parameters); - symbolTable.setVariableExtensions("gl_DrawIDARB", 1, &E_GL_ARB_shader_draw_parameters); - - BuiltInVariable("gl_BaseVertexARB", EbvBaseVertex, symbolTable); - BuiltInVariable("gl_BaseInstanceARB", EbvBaseInstance, symbolTable); - BuiltInVariable("gl_DrawIDARB", EbvDrawId, symbolTable); - } - - if (profile != EEsProfile) { + if (version >= 440) { + symbolTable.setVariableExtensions("gl_BaseVertexARB", 1, &E_GL_ARB_shader_draw_parameters); + symbolTable.setVariableExtensions("gl_BaseInstanceARB", 1, &E_GL_ARB_shader_draw_parameters); + symbolTable.setVariableExtensions("gl_DrawIDARB", 1, &E_GL_ARB_shader_draw_parameters); + BuiltInVariable("gl_BaseVertexARB", EbvBaseVertex, symbolTable); + BuiltInVariable("gl_BaseInstanceARB", EbvBaseInstance, symbolTable); + BuiltInVariable("gl_DrawIDARB", EbvDrawId, symbolTable); + } + if (version >= 460) { + BuiltInVariable("gl_BaseVertex", EbvBaseVertex, symbolTable); + BuiltInVariable("gl_BaseInstance", EbvBaseInstance, symbolTable); + BuiltInVariable("gl_DrawID", EbvDrawId, symbolTable); + } symbolTable.setVariableExtensions("gl_SubGroupSizeARB", 1, &E_GL_ARB_shader_ballot); symbolTable.setVariableExtensions("gl_SubGroupInvocationARB", 1, &E_GL_ARB_shader_ballot); symbolTable.setVariableExtensions("gl_SubGroupEqMaskARB", 1, &E_GL_ARB_shader_ballot); @@ -3575,7 +7323,6 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setFunctionExtensions("readInvocationARB", 1, &E_GL_ARB_shader_ballot); symbolTable.setFunctionExtensions("readFirstInvocationARB", 1, &E_GL_ARB_shader_ballot); - BuiltInVariable("gl_SubGroupSizeARB", EbvSubGroupSize, symbolTable); BuiltInVariable("gl_SubGroupInvocationARB", EbvSubGroupInvocation, symbolTable); BuiltInVariable("gl_SubGroupEqMaskARB", EbvSubGroupEqMask, symbolTable); BuiltInVariable("gl_SubGroupGeMaskARB", EbvSubGroupGeMask, symbolTable); @@ -3583,11 +7330,64 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_SubGroupLeMaskARB", EbvSubGroupLeMask, symbolTable); BuiltInVariable("gl_SubGroupLtMaskARB", EbvSubGroupLtMask, symbolTable); - symbolTable.setFunctionExtensions("anyInvocationARB", 1, &E_GL_ARB_shader_group_vote); - symbolTable.setFunctionExtensions("allInvocationsARB", 1, &E_GL_ARB_shader_group_vote); - symbolTable.setFunctionExtensions("allInvocationsEqualARB", 1, &E_GL_ARB_shader_group_vote); + if (spvVersion.vulkan > 0) + // Treat "gl_SubGroupSizeARB" as shader input instead of uniform for Vulkan + SpecialQualifier("gl_SubGroupSizeARB", EvqVaryingIn, EbvSubGroupSize, symbolTable); + else + BuiltInVariable("gl_SubGroupSizeARB", EbvSubGroupSize, symbolTable); + + if (version >= 430) { + symbolTable.setFunctionExtensions("anyInvocationARB", 1, &E_GL_ARB_shader_group_vote); + symbolTable.setFunctionExtensions("allInvocationsARB", 1, &E_GL_ARB_shader_group_vote); + symbolTable.setFunctionExtensions("allInvocationsEqualARB", 1, &E_GL_ARB_shader_group_vote); + } } +#ifdef AMD_EXTENSIONS + if (profile != EEsProfile) { + symbolTable.setFunctionExtensions("minInvocationsAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("maxInvocationsAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("addInvocationsAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("minInvocationsNonUniformAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("maxInvocationsNonUniformAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("addInvocationsNonUniformAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("swizzleInvocationsAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("swizzleInvocationsWithPatternAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("writeInvocationAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("mbcntAMD", 1, &E_GL_AMD_shader_ballot); + + symbolTable.setFunctionExtensions("minInvocationsInclusiveScanAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("maxInvocationsInclusiveScanAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("addInvocationsInclusiveScanAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("minInvocationsInclusiveScanNonUniformAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("maxInvocationsInclusiveScanNonUniformAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("addInvocationsInclusiveScanNonUniformAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("minInvocationsExclusiveScanAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("maxInvocationsExclusiveScanAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("addInvocationsExclusiveScanAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("minInvocationsExclusiveScanNonUniformAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("maxInvocationsExclusiveScanNonUniformAMD", 1, &E_GL_AMD_shader_ballot); + symbolTable.setFunctionExtensions("addInvocationsExclusiveScanNonUniformAMD", 1, &E_GL_AMD_shader_ballot); + } + + if (profile != EEsProfile) { + symbolTable.setFunctionExtensions("min3", 1, &E_GL_AMD_shader_trinary_minmax); + symbolTable.setFunctionExtensions("max3", 1, &E_GL_AMD_shader_trinary_minmax); + symbolTable.setFunctionExtensions("mid3", 1, &E_GL_AMD_shader_trinary_minmax); + } + + if (profile != EEsProfile) { + symbolTable.setFunctionExtensions("cubeFaceIndexAMD", 1, &E_GL_AMD_gcn_shader); + symbolTable.setFunctionExtensions("cubeFaceCoordAMD", 1, &E_GL_AMD_gcn_shader); + symbolTable.setFunctionExtensions("timeAMD", 1, &E_GL_AMD_gcn_shader); + } + + if (profile != EEsProfile) { + symbolTable.setFunctionExtensions("fragmentMaskFetchAMD", 1, &E_GL_AMD_shader_fragment_mask); + symbolTable.setFunctionExtensions("fragmentFetchAMD", 1, &E_GL_AMD_shader_fragment_mask); + } +#endif + // Compatibility variables, vertex only if (spvVersion.spv == 0) { BuiltInVariable("gl_Color", EbvColor, symbolTable); @@ -3610,13 +7410,14 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setFunctionExtensions("texture2DGradEXT", 1, &E_GL_EXT_shader_texture_lod); symbolTable.setFunctionExtensions("texture2DProjGradEXT", 1, &E_GL_EXT_shader_texture_lod); symbolTable.setFunctionExtensions("textureCubeGradEXT", 1, &E_GL_EXT_shader_texture_lod); - symbolTable.setFunctionExtensions("textureGatherOffsets", Num_AEP_gpu_shader5, AEP_gpu_shader5); + if (version == 310) + symbolTable.setFunctionExtensions("textureGatherOffsets", Num_AEP_gpu_shader5, AEP_gpu_shader5); } - if (version >= 310) + if (version == 310) symbolTable.setFunctionExtensions("fma", Num_AEP_gpu_shader5, AEP_gpu_shader5); } - if (profile == EEsProfile) { + if (profile == EEsProfile && version < 320) { symbolTable.setFunctionExtensions("imageAtomicAdd", 1, &E_GL_OES_shader_image_atomic); symbolTable.setFunctionExtensions("imageAtomicMin", 1, &E_GL_OES_shader_image_atomic); symbolTable.setFunctionExtensions("imageAtomicMax", 1, &E_GL_OES_shader_image_atomic); @@ -3632,17 +7433,29 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion SpecialQualifier("gl_InstanceID", EvqInstanceId, EbvInstanceId, symbolTable); } - if (spvVersion.vulkan >= 100) { + if (spvVersion.vulkan > 0) { BuiltInVariable("gl_VertexIndex", EbvVertexIndex, symbolTable); BuiltInVariable("gl_InstanceIndex", EbvInstanceIndex, symbolTable); } + if (version >= 300 /* both ES and non-ES */) { + symbolTable.setVariableExtensions("gl_ViewID_OVR", Num_OVR_multiview_EXTs, OVR_multiview_EXTs); + BuiltInVariable("gl_ViewID_OVR", EbvViewIndex, symbolTable); + } + + if (profile == EEsProfile) { + symbolTable.setFunctionExtensions("shadow2DEXT", 1, &E_GL_EXT_shadow_samplers); + symbolTable.setFunctionExtensions("shadow2DProjEXT", 1, &E_GL_EXT_shadow_samplers); + } + // Fall through case EShLangTessControl: if (profile == EEsProfile && version >= 310) { - symbolTable.setVariableExtensions("gl_BoundingBoxOES", Num_AEP_primitive_bounding_box, AEP_primitive_bounding_box); BuiltInVariable("gl_BoundingBoxOES", EbvBoundingBox, symbolTable); + if (version < 320) + symbolTable.setVariableExtensions("gl_BoundingBoxOES", Num_AEP_primitive_bounding_box, + AEP_primitive_bounding_box); } // Fall through @@ -3670,6 +7483,43 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_InvocationID", EbvInvocationId, symbolTable); BuiltInVariable("gl_Layer", EbvLayer, symbolTable); BuiltInVariable("gl_ViewportIndex", EbvViewportIndex, symbolTable); + +#ifdef NV_EXTENSIONS + if (language != EShLangGeometry) { + symbolTable.setVariableExtensions("gl_Layer", Num_viewportEXTs, viewportEXTs); + symbolTable.setVariableExtensions("gl_ViewportIndex", Num_viewportEXTs, viewportEXTs); + } +#else + if (language != EShLangGeometry && version >= 410) { + symbolTable.setVariableExtensions("gl_Layer", 1, &E_GL_ARB_shader_viewport_layer_array); + symbolTable.setVariableExtensions("gl_ViewportIndex", 1, &E_GL_ARB_shader_viewport_layer_array); + } +#endif + +#ifdef NV_EXTENSIONS + symbolTable.setVariableExtensions("gl_ViewportMask", 1, &E_GL_NV_viewport_array2); + symbolTable.setVariableExtensions("gl_SecondaryPositionNV", 1, &E_GL_NV_stereo_view_rendering); + symbolTable.setVariableExtensions("gl_SecondaryViewportMaskNV", 1, &E_GL_NV_stereo_view_rendering); + symbolTable.setVariableExtensions("gl_PositionPerViewNV", 1, &E_GL_NVX_multiview_per_view_attributes); + symbolTable.setVariableExtensions("gl_ViewportMaskPerViewNV", 1, &E_GL_NVX_multiview_per_view_attributes); + + BuiltInVariable("gl_ViewportMask", EbvViewportMaskNV, symbolTable); + BuiltInVariable("gl_SecondaryPositionNV", EbvSecondaryPositionNV, symbolTable); + BuiltInVariable("gl_SecondaryViewportMaskNV", EbvSecondaryViewportMaskNV, symbolTable); + BuiltInVariable("gl_PositionPerViewNV", EbvPositionPerViewNV, symbolTable); + BuiltInVariable("gl_ViewportMaskPerViewNV", EbvViewportMaskPerViewNV, symbolTable); + + if (language != EShLangVertex) { + BuiltInVariable("gl_in", "gl_SecondaryPositionNV", EbvSecondaryPositionNV, symbolTable); + BuiltInVariable("gl_in", "gl_PositionPerViewNV", EbvPositionPerViewNV, symbolTable); + } + BuiltInVariable("gl_out", "gl_ViewportMask", EbvViewportMaskNV, symbolTable); + BuiltInVariable("gl_out", "gl_SecondaryPositionNV", EbvSecondaryPositionNV, symbolTable); + BuiltInVariable("gl_out", "gl_SecondaryViewportMaskNV", EbvSecondaryViewportMaskNV, symbolTable); + BuiltInVariable("gl_out", "gl_PositionPerViewNV", EbvPositionPerViewNV, symbolTable); + BuiltInVariable("gl_out", "gl_ViewportMaskPerViewNV", EbvViewportMaskPerViewNV, symbolTable); +#endif + BuiltInVariable("gl_PatchVerticesIn", EbvPatchVertices, symbolTable); BuiltInVariable("gl_TessLevelOuter", EbvTessLevelOuter, symbolTable); BuiltInVariable("gl_TessLevelInner", EbvTessLevelInner, symbolTable); @@ -3709,20 +7559,55 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion // However, the current automatic extension scheme does not work per block member, // so for now check when parsing. // - //if (profile == EEsProfile) { + // if (profile == EEsProfile) { // if (language == EShLangGeometry) // symbolTable.setVariableExtensions("gl_PointSize", Num_AEP_geometry_point_size, AEP_geometry_point_size); // else if (language == EShLangTessEvaluation || language == EShLangTessControl) // symbolTable.setVariableExtensions("gl_PointSize", Num_AEP_tessellation_point_size, AEP_tessellation_point_size); //} + if ((profile != EEsProfile && version >= 140) || + (profile == EEsProfile && version >= 310)) { + symbolTable.setVariableExtensions("gl_DeviceIndex", 1, &E_GL_EXT_device_group); + BuiltInVariable("gl_DeviceIndex", EbvDeviceIndex, symbolTable); + symbolTable.setVariableExtensions("gl_ViewIndex", 1, &E_GL_EXT_multiview); + BuiltInVariable("gl_ViewIndex", EbvViewIndex, symbolTable); + } + + // GL_KHR_shader_subgroup + if (spvVersion.vulkan > 0) { + symbolTable.setVariableExtensions("gl_SubgroupSize", 1, &E_GL_KHR_shader_subgroup_basic); + symbolTable.setVariableExtensions("gl_SubgroupInvocationID", 1, &E_GL_KHR_shader_subgroup_basic); + symbolTable.setVariableExtensions("gl_SubgroupEqMask", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setVariableExtensions("gl_SubgroupGeMask", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setVariableExtensions("gl_SubgroupGtMask", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setVariableExtensions("gl_SubgroupLeMask", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setVariableExtensions("gl_SubgroupLtMask", 1, &E_GL_KHR_shader_subgroup_ballot); + + BuiltInVariable("gl_SubgroupSize", EbvSubgroupSize2, symbolTable); + BuiltInVariable("gl_SubgroupInvocationID", EbvSubgroupInvocation2, symbolTable); + BuiltInVariable("gl_SubgroupEqMask", EbvSubgroupEqMask2, symbolTable); + BuiltInVariable("gl_SubgroupGeMask", EbvSubgroupGeMask2, symbolTable); + BuiltInVariable("gl_SubgroupGtMask", EbvSubgroupGtMask2, symbolTable); + BuiltInVariable("gl_SubgroupLeMask", EbvSubgroupLeMask2, symbolTable); + BuiltInVariable("gl_SubgroupLtMask", EbvSubgroupLtMask2, symbolTable); + } + break; case EShLangFragment: SpecialQualifier("gl_FrontFacing", EvqFace, EbvFace, symbolTable); SpecialQualifier("gl_FragCoord", EvqFragCoord, EbvFragCoord, symbolTable); SpecialQualifier("gl_PointCoord", EvqPointCoord, EbvPointCoord, symbolTable); - SpecialQualifier("gl_FragColor", EvqFragColor, EbvFragColor, symbolTable); + if (spvVersion.spv == 0) + SpecialQualifier("gl_FragColor", EvqFragColor, EbvFragColor, symbolTable); + else { + TSymbol* symbol = symbolTable.find("gl_FragColor"); + if (symbol) { + symbol->getWritableType().getQualifier().storage = EvqVaryingOut; + symbol->getWritableType().getQualifier().layoutLocation = 0; + } + } SpecialQualifier("gl_FragDepth", EvqFragDepth, EbvFragDepth, symbolTable); SpecialQualifier("gl_FragDepthEXT", EvqFragDepth, EbvFragDepth, symbolTable); SpecialQualifier("gl_HelperInvocation", EvqVaryingIn, EbvHelperInvocation, symbolTable); @@ -3731,13 +7616,18 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_CullDistance", EbvCullDistance, symbolTable); BuiltInVariable("gl_PrimitiveID", EbvPrimitiveId, symbolTable); + if (profile != EEsProfile && version >= 140) { + symbolTable.setVariableExtensions("gl_FragStencilRefARB", 1, &E_GL_ARB_shader_stencil_export); + BuiltInVariable("gl_FragStencilRefARB", EbvFragStencilRef, symbolTable); + } + if ((profile != EEsProfile && version >= 400) || (profile == EEsProfile && version >= 310)) { BuiltInVariable("gl_SampleID", EbvSampleId, symbolTable); BuiltInVariable("gl_SamplePosition", EbvSamplePosition, symbolTable); BuiltInVariable("gl_SampleMaskIn", EbvSampleMask, symbolTable); BuiltInVariable("gl_SampleMask", EbvSampleMask, symbolTable); - if (profile == EEsProfile) { + if (profile == EEsProfile && version < 320) { symbolTable.setVariableExtensions("gl_SampleID", 1, &E_GL_OES_sample_variables); symbolTable.setVariableExtensions("gl_SamplePosition", 1, &E_GL_OES_sample_variables); symbolTable.setVariableExtensions("gl_SampleMaskIn", 1, &E_GL_OES_sample_variables); @@ -3745,7 +7635,7 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setVariableExtensions("gl_NumSamples", 1, &E_GL_OES_sample_variables); } } - + BuiltInVariable("gl_Layer", EbvLayer, symbolTable); BuiltInVariable("gl_ViewportIndex", EbvViewportIndex, symbolTable); @@ -3771,14 +7661,15 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setFunctionExtensions("texture2DGradEXT", 1, &E_GL_EXT_shader_texture_lod); symbolTable.setFunctionExtensions("texture2DProjGradEXT", 1, &E_GL_EXT_shader_texture_lod); symbolTable.setFunctionExtensions("textureCubeGradEXT", 1, &E_GL_EXT_shader_texture_lod); - symbolTable.setFunctionExtensions("textureGatherOffsets", Num_AEP_gpu_shader5, AEP_gpu_shader5); + if (version < 320) + symbolTable.setFunctionExtensions("textureGatherOffsets", Num_AEP_gpu_shader5, AEP_gpu_shader5); } if (version == 100) { symbolTable.setFunctionExtensions("dFdx", 1, &E_GL_OES_standard_derivatives); symbolTable.setFunctionExtensions("dFdy", 1, &E_GL_OES_standard_derivatives); symbolTable.setFunctionExtensions("fwidth", 1, &E_GL_OES_standard_derivatives); } - if (version >= 310) { + if (version == 310) { symbolTable.setFunctionExtensions("fma", Num_AEP_gpu_shader5, AEP_gpu_shader5); symbolTable.setFunctionExtensions("interpolateAtCentroid", 1, &E_GL_OES_shader_multisample_interpolation); symbolTable.setFunctionExtensions("interpolateAtSample", 1, &E_GL_OES_shader_multisample_interpolation); @@ -3872,14 +7763,61 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setFunctionExtensions("textureGradOffsetClampARB", 1, &E_GL_ARB_sparse_texture_clamp); } +#ifdef AMD_EXTENSIONS + // E_GL_AMD_shader_explicit_vertex_parameter + if (profile != EEsProfile) { + symbolTable.setVariableExtensions("gl_BaryCoordNoPerspAMD", 1, &E_GL_AMD_shader_explicit_vertex_parameter); + symbolTable.setVariableExtensions("gl_BaryCoordNoPerspCentroidAMD", 1, &E_GL_AMD_shader_explicit_vertex_parameter); + symbolTable.setVariableExtensions("gl_BaryCoordNoPerspSampleAMD", 1, &E_GL_AMD_shader_explicit_vertex_parameter); + symbolTable.setVariableExtensions("gl_BaryCoordSmoothAMD", 1, &E_GL_AMD_shader_explicit_vertex_parameter); + symbolTable.setVariableExtensions("gl_BaryCoordSmoothCentroidAMD", 1, &E_GL_AMD_shader_explicit_vertex_parameter); + symbolTable.setVariableExtensions("gl_BaryCoordSmoothSampleAMD", 1, &E_GL_AMD_shader_explicit_vertex_parameter); + symbolTable.setVariableExtensions("gl_BaryCoordPullModelAMD", 1, &E_GL_AMD_shader_explicit_vertex_parameter); + + symbolTable.setFunctionExtensions("interpolateAtVertexAMD", 1, &E_GL_AMD_shader_explicit_vertex_parameter); + + BuiltInVariable("gl_BaryCoordNoPerspAMD", EbvBaryCoordNoPersp, symbolTable); + BuiltInVariable("gl_BaryCoordNoPerspCentroidAMD", EbvBaryCoordNoPerspCentroid, symbolTable); + BuiltInVariable("gl_BaryCoordNoPerspSampleAMD", EbvBaryCoordNoPerspSample, symbolTable); + BuiltInVariable("gl_BaryCoordSmoothAMD", EbvBaryCoordSmooth, symbolTable); + BuiltInVariable("gl_BaryCoordSmoothCentroidAMD", EbvBaryCoordSmoothCentroid, symbolTable); + BuiltInVariable("gl_BaryCoordSmoothSampleAMD", EbvBaryCoordSmoothSample, symbolTable); + BuiltInVariable("gl_BaryCoordPullModelAMD", EbvBaryCoordPullModel, symbolTable); + } + + // E_GL_AMD_texture_gather_bias_lod + if (profile != EEsProfile) { + symbolTable.setFunctionExtensions("textureGatherLodAMD", 1, &E_GL_AMD_texture_gather_bias_lod); + symbolTable.setFunctionExtensions("textureGatherLodOffsetAMD", 1, &E_GL_AMD_texture_gather_bias_lod); + symbolTable.setFunctionExtensions("textureGatherLodOffsetsAMD", 1, &E_GL_AMD_texture_gather_bias_lod); + symbolTable.setFunctionExtensions("sparseTextureGatherLodAMD", 1, &E_GL_AMD_texture_gather_bias_lod); + symbolTable.setFunctionExtensions("sparseTextureGatherLodOffsetAMD", 1, &E_GL_AMD_texture_gather_bias_lod); + symbolTable.setFunctionExtensions("sparseTextureGatherLodOffsetsAMD", 1, &E_GL_AMD_texture_gather_bias_lod); + } + + // E_GL_AMD_shader_image_load_store_lod + if (profile != EEsProfile) { + symbolTable.setFunctionExtensions("imageLoadLodAMD", 1, &E_GL_AMD_shader_image_load_store_lod); + symbolTable.setFunctionExtensions("imageStoreLodAMD", 1, &E_GL_AMD_shader_image_load_store_lod); + symbolTable.setFunctionExtensions("sparseImageLoadLodAMD", 1, &E_GL_AMD_shader_image_load_store_lod); + } +#endif + +#ifdef NV_EXTENSIONS + if (profile != EEsProfile && version >= 430) { + symbolTable.setVariableExtensions("gl_FragFullyCoveredNV", 1, &E_GL_NV_conservative_raster_underestimation); + BuiltInVariable("gl_FragFullyCoveredNV", EbvFragFullyCoveredNV, symbolTable); + } +#endif + symbolTable.setVariableExtensions("gl_FragDepthEXT", 1, &E_GL_EXT_frag_depth); - if (profile == EEsProfile) { + if (profile == EEsProfile && version < 320) { symbolTable.setVariableExtensions("gl_PrimitiveID", Num_AEP_geometry_shader, AEP_geometry_shader); symbolTable.setVariableExtensions("gl_Layer", Num_AEP_geometry_shader, AEP_geometry_shader); } - if (profile == EEsProfile) { + if (profile == EEsProfile && version < 320) { symbolTable.setFunctionExtensions("imageAtomicAdd", 1, &E_GL_OES_shader_image_atomic); symbolTable.setFunctionExtensions("imageAtomicMin", 1, &E_GL_OES_shader_image_atomic); symbolTable.setFunctionExtensions("imageAtomicMax", 1, &E_GL_OES_shader_image_atomic); @@ -3889,6 +7827,144 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setFunctionExtensions("imageAtomicExchange", 1, &E_GL_OES_shader_image_atomic); symbolTable.setFunctionExtensions("imageAtomicCompSwap", 1, &E_GL_OES_shader_image_atomic); } + + symbolTable.setVariableExtensions("gl_DeviceIndex", 1, &E_GL_EXT_device_group); + BuiltInVariable("gl_DeviceIndex", EbvDeviceIndex, symbolTable); + symbolTable.setVariableExtensions("gl_ViewIndex", 1, &E_GL_EXT_multiview); + BuiltInVariable("gl_ViewIndex", EbvViewIndex, symbolTable); + if (version >= 300 /* both ES and non-ES */) { + symbolTable.setVariableExtensions("gl_ViewID_OVR", Num_OVR_multiview_EXTs, OVR_multiview_EXTs); + BuiltInVariable("gl_ViewID_OVR", EbvViewIndex, symbolTable); + } + + // GL_ARB_shader_ballot + if (profile != EEsProfile) { + symbolTable.setVariableExtensions("gl_SubGroupSizeARB", 1, &E_GL_ARB_shader_ballot); + symbolTable.setVariableExtensions("gl_SubGroupInvocationARB", 1, &E_GL_ARB_shader_ballot); + symbolTable.setVariableExtensions("gl_SubGroupEqMaskARB", 1, &E_GL_ARB_shader_ballot); + symbolTable.setVariableExtensions("gl_SubGroupGeMaskARB", 1, &E_GL_ARB_shader_ballot); + symbolTable.setVariableExtensions("gl_SubGroupGtMaskARB", 1, &E_GL_ARB_shader_ballot); + symbolTable.setVariableExtensions("gl_SubGroupLeMaskARB", 1, &E_GL_ARB_shader_ballot); + symbolTable.setVariableExtensions("gl_SubGroupLtMaskARB", 1, &E_GL_ARB_shader_ballot); + + BuiltInVariable("gl_SubGroupInvocationARB", EbvSubGroupInvocation, symbolTable); + BuiltInVariable("gl_SubGroupEqMaskARB", EbvSubGroupEqMask, symbolTable); + BuiltInVariable("gl_SubGroupGeMaskARB", EbvSubGroupGeMask, symbolTable); + BuiltInVariable("gl_SubGroupGtMaskARB", EbvSubGroupGtMask, symbolTable); + BuiltInVariable("gl_SubGroupLeMaskARB", EbvSubGroupLeMask, symbolTable); + BuiltInVariable("gl_SubGroupLtMaskARB", EbvSubGroupLtMask, symbolTable); + + if (spvVersion.vulkan > 0) + // Treat "gl_SubGroupSizeARB" as shader input instead of uniform for Vulkan + SpecialQualifier("gl_SubGroupSizeARB", EvqVaryingIn, EbvSubGroupSize, symbolTable); + else + BuiltInVariable("gl_SubGroupSizeARB", EbvSubGroupSize, symbolTable); + } + + // GL_KHR_shader_subgroup + if (spvVersion.vulkan > 0) { + symbolTable.setVariableExtensions("gl_SubgroupSize", 1, &E_GL_KHR_shader_subgroup_basic); + symbolTable.setVariableExtensions("gl_SubgroupInvocationID", 1, &E_GL_KHR_shader_subgroup_basic); + symbolTable.setVariableExtensions("gl_SubgroupEqMask", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setVariableExtensions("gl_SubgroupGeMask", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setVariableExtensions("gl_SubgroupGtMask", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setVariableExtensions("gl_SubgroupLeMask", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setVariableExtensions("gl_SubgroupLtMask", 1, &E_GL_KHR_shader_subgroup_ballot); + + BuiltInVariable("gl_SubgroupSize", EbvSubgroupSize2, symbolTable); + BuiltInVariable("gl_SubgroupInvocationID", EbvSubgroupInvocation2, symbolTable); + BuiltInVariable("gl_SubgroupEqMask", EbvSubgroupEqMask2, symbolTable); + BuiltInVariable("gl_SubgroupGeMask", EbvSubgroupGeMask2, symbolTable); + BuiltInVariable("gl_SubgroupGtMask", EbvSubgroupGtMask2, symbolTable); + BuiltInVariable("gl_SubgroupLeMask", EbvSubgroupLeMask2, symbolTable); + BuiltInVariable("gl_SubgroupLtMask", EbvSubgroupLtMask2, symbolTable); + + symbolTable.setFunctionExtensions("subgroupBarrier", 1, &E_GL_KHR_shader_subgroup_basic); + symbolTable.setFunctionExtensions("subgroupMemoryBarrier", 1, &E_GL_KHR_shader_subgroup_basic); + symbolTable.setFunctionExtensions("subgroupMemoryBarrierBuffer", 1, &E_GL_KHR_shader_subgroup_basic); + symbolTable.setFunctionExtensions("subgroupMemoryBarrierImage", 1, &E_GL_KHR_shader_subgroup_basic); + symbolTable.setFunctionExtensions("subgroupElect", 1, &E_GL_KHR_shader_subgroup_basic); + symbolTable.setFunctionExtensions("subgroupAll", 1, &E_GL_KHR_shader_subgroup_vote); + symbolTable.setFunctionExtensions("subgroupAny", 1, &E_GL_KHR_shader_subgroup_vote); + symbolTable.setFunctionExtensions("subgroupAllEqual", 1, &E_GL_KHR_shader_subgroup_vote); + symbolTable.setFunctionExtensions("subgroupBroadcast", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setFunctionExtensions("subgroupBroadcastFirst", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setFunctionExtensions("subgroupBallot", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setFunctionExtensions("subgroupInverseBallot", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setFunctionExtensions("subgroupBallotBitExtract", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setFunctionExtensions("subgroupBallotBitCount", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setFunctionExtensions("subgroupBallotInclusiveBitCount", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setFunctionExtensions("subgroupBallotExclusiveBitCount", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setFunctionExtensions("subgroupBallotFindLSB", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setFunctionExtensions("subgroupBallotFindMSB", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setFunctionExtensions("subgroupShuffle", 1, &E_GL_KHR_shader_subgroup_shuffle); + symbolTable.setFunctionExtensions("subgroupShuffleXor", 1, &E_GL_KHR_shader_subgroup_shuffle); + symbolTable.setFunctionExtensions("subgroupShuffleUp", 1, &E_GL_KHR_shader_subgroup_shuffle_relative); + symbolTable.setFunctionExtensions("subgroupShuffleDown", 1, &E_GL_KHR_shader_subgroup_shuffle_relative); + symbolTable.setFunctionExtensions("subgroupAdd", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupMul", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupMin", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupMax", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupAnd", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupOr", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupXor", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupInclusiveAdd", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupInclusiveMul", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupInclusiveMin", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupInclusiveMax", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupInclusiveAnd", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupInclusiveOr", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupInclusiveXor", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupExclusiveAdd", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupExclusiveMul", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupExclusiveMin", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupExclusiveMax", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupExclusiveAnd", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupExclusiveOr", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupExclusiveXor", 1, &E_GL_KHR_shader_subgroup_arithmetic); + symbolTable.setFunctionExtensions("subgroupClusteredAdd", 1, &E_GL_KHR_shader_subgroup_clustered); + symbolTable.setFunctionExtensions("subgroupClusteredMul", 1, &E_GL_KHR_shader_subgroup_clustered); + symbolTable.setFunctionExtensions("subgroupClusteredMin", 1, &E_GL_KHR_shader_subgroup_clustered); + symbolTable.setFunctionExtensions("subgroupClusteredMax", 1, &E_GL_KHR_shader_subgroup_clustered); + symbolTable.setFunctionExtensions("subgroupClusteredAnd", 1, &E_GL_KHR_shader_subgroup_clustered); + symbolTable.setFunctionExtensions("subgroupClusteredOr", 1, &E_GL_KHR_shader_subgroup_clustered); + symbolTable.setFunctionExtensions("subgroupClusteredXor", 1, &E_GL_KHR_shader_subgroup_clustered); + symbolTable.setFunctionExtensions("subgroupQuadBroadcast", 1, &E_GL_KHR_shader_subgroup_quad); + symbolTable.setFunctionExtensions("subgroupQuadSwapHorizontal", 1, &E_GL_KHR_shader_subgroup_quad); + symbolTable.setFunctionExtensions("subgroupQuadSwapVertical", 1, &E_GL_KHR_shader_subgroup_quad); + symbolTable.setFunctionExtensions("subgroupQuadSwapDiagonal", 1, &E_GL_KHR_shader_subgroup_quad); + +#ifdef NV_EXTENSIONS + symbolTable.setFunctionExtensions("subgroupPartitionNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedAddNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedMulNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedMinNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedMaxNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedAndNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedOrNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedXorNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedInclusiveAddNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedInclusiveMulNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedInclusiveMinNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedInclusiveMaxNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedInclusiveAndNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedInclusiveOrNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedInclusiveXorNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedExclusiveAddNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedExclusiveMulNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedExclusiveMinNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedExclusiveMaxNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedExclusiveAndNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedExclusiveOrNV", 1, &E_GL_NV_shader_subgroup_partitioned); + symbolTable.setFunctionExtensions("subgroupPartitionedExclusiveXorNV", 1, &E_GL_NV_shader_subgroup_partitioned); +#endif + + } + + if (profile == EEsProfile) { + symbolTable.setFunctionExtensions("shadow2DEXT", 1, &E_GL_EXT_shadow_samplers); + symbolTable.setFunctionExtensions("shadow2DProjEXT", 1, &E_GL_EXT_shadow_samplers); + } break; case EShLangCompute: @@ -3922,6 +7998,68 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setFunctionExtensions("memoryBarrierShared", 1, &E_GL_ARB_compute_shader); symbolTable.setFunctionExtensions("groupMemoryBarrier", 1, &E_GL_ARB_compute_shader); } + + // GL_ARB_shader_ballot + if (profile != EEsProfile) { + symbolTable.setVariableExtensions("gl_SubGroupSizeARB", 1, &E_GL_ARB_shader_ballot); + symbolTable.setVariableExtensions("gl_SubGroupInvocationARB", 1, &E_GL_ARB_shader_ballot); + symbolTable.setVariableExtensions("gl_SubGroupEqMaskARB", 1, &E_GL_ARB_shader_ballot); + symbolTable.setVariableExtensions("gl_SubGroupGeMaskARB", 1, &E_GL_ARB_shader_ballot); + symbolTable.setVariableExtensions("gl_SubGroupGtMaskARB", 1, &E_GL_ARB_shader_ballot); + symbolTable.setVariableExtensions("gl_SubGroupLeMaskARB", 1, &E_GL_ARB_shader_ballot); + symbolTable.setVariableExtensions("gl_SubGroupLtMaskARB", 1, &E_GL_ARB_shader_ballot); + + BuiltInVariable("gl_SubGroupInvocationARB", EbvSubGroupInvocation, symbolTable); + BuiltInVariable("gl_SubGroupEqMaskARB", EbvSubGroupEqMask, symbolTable); + BuiltInVariable("gl_SubGroupGeMaskARB", EbvSubGroupGeMask, symbolTable); + BuiltInVariable("gl_SubGroupGtMaskARB", EbvSubGroupGtMask, symbolTable); + BuiltInVariable("gl_SubGroupLeMaskARB", EbvSubGroupLeMask, symbolTable); + BuiltInVariable("gl_SubGroupLtMaskARB", EbvSubGroupLtMask, symbolTable); + + if (spvVersion.vulkan > 0) + // Treat "gl_SubGroupSizeARB" as shader input instead of uniform for Vulkan + SpecialQualifier("gl_SubGroupSizeARB", EvqVaryingIn, EbvSubGroupSize, symbolTable); + else + BuiltInVariable("gl_SubGroupSizeARB", EbvSubGroupSize, symbolTable); + } + + // GL_ARB_shader_ballot + if (spvVersion.vulkan > 0) { + symbolTable.setVariableExtensions("gl_SubgroupSize", 1, &E_GL_KHR_shader_subgroup_basic); + symbolTable.setVariableExtensions("gl_SubgroupInvocationID", 1, &E_GL_KHR_shader_subgroup_basic); + symbolTable.setVariableExtensions("gl_SubgroupEqMask", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setVariableExtensions("gl_SubgroupGeMask", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setVariableExtensions("gl_SubgroupGtMask", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setVariableExtensions("gl_SubgroupLeMask", 1, &E_GL_KHR_shader_subgroup_ballot); + symbolTable.setVariableExtensions("gl_SubgroupLtMask", 1, &E_GL_KHR_shader_subgroup_ballot); + + BuiltInVariable("gl_SubgroupSize", EbvSubgroupSize2, symbolTable); + BuiltInVariable("gl_SubgroupInvocationID", EbvSubgroupInvocation2, symbolTable); + BuiltInVariable("gl_SubgroupEqMask", EbvSubgroupEqMask2, symbolTable); + BuiltInVariable("gl_SubgroupGeMask", EbvSubgroupGeMask2, symbolTable); + BuiltInVariable("gl_SubgroupGtMask", EbvSubgroupGtMask2, symbolTable); + BuiltInVariable("gl_SubgroupLeMask", EbvSubgroupLeMask2, symbolTable); + BuiltInVariable("gl_SubgroupLtMask", EbvSubgroupLtMask2, symbolTable); + } + + if ((profile != EEsProfile && version >= 140) || + (profile == EEsProfile && version >= 310)) { + symbolTable.setVariableExtensions("gl_DeviceIndex", 1, &E_GL_EXT_device_group); + BuiltInVariable("gl_DeviceIndex", EbvDeviceIndex, symbolTable); + symbolTable.setVariableExtensions("gl_ViewIndex", 1, &E_GL_EXT_multiview); + BuiltInVariable("gl_ViewIndex", EbvViewIndex, symbolTable); + } + + // GL_KHR_shader_subgroup + if (spvVersion.vulkan > 0) { + symbolTable.setVariableExtensions("gl_NumSubgroups", 1, &E_GL_KHR_shader_subgroup_basic); + symbolTable.setVariableExtensions("gl_SubgroupID", 1, &E_GL_KHR_shader_subgroup_basic); + + BuiltInVariable("gl_NumSubgroups", EbvNumSubgroups, symbolTable); + BuiltInVariable("gl_SubgroupID", EbvSubgroupID, symbolTable); + + symbolTable.setFunctionExtensions("subgroupMemoryBarrierShared", 1, &E_GL_KHR_shader_subgroup_basic); + } break; default: @@ -4007,6 +8145,15 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("doubleBitsToUint64", EOpDoubleBitsToUint64); symbolTable.relateToOperator("int64BitsToDouble", EOpInt64BitsToDouble); symbolTable.relateToOperator("uint64BitsToDouble", EOpUint64BitsToDouble); + symbolTable.relateToOperator("halfBitsToInt16", EOpFloat16BitsToInt16); + symbolTable.relateToOperator("halfBitsToUint16", EOpFloat16BitsToUint16); + symbolTable.relateToOperator("float16BitsToInt16", EOpFloat16BitsToInt16); + symbolTable.relateToOperator("float16BitsToUint16", EOpFloat16BitsToUint16); + symbolTable.relateToOperator("int16BitsToFloat16", EOpInt16BitsToFloat16); + symbolTable.relateToOperator("uint16BitsToFloat16", EOpUint16BitsToFloat16); + + symbolTable.relateToOperator("int16BitsToHalf", EOpInt16BitsToFloat16); + symbolTable.relateToOperator("uint16BitsToHalf", EOpUint16BitsToFloat16); symbolTable.relateToOperator("packSnorm2x16", EOpPackSnorm2x16); symbolTable.relateToOperator("unpackSnorm2x16", EOpUnpackSnorm2x16); @@ -4029,6 +8176,26 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("packUint2x32", EOpPackUint2x32); symbolTable.relateToOperator("unpackUint2x32", EOpUnpackUint2x32); + symbolTable.relateToOperator("packInt2x16", EOpPackInt2x16); + symbolTable.relateToOperator("unpackInt2x16", EOpUnpackInt2x16); + symbolTable.relateToOperator("packUint2x16", EOpPackUint2x16); + symbolTable.relateToOperator("unpackUint2x16", EOpUnpackUint2x16); + + symbolTable.relateToOperator("packInt4x16", EOpPackInt4x16); + symbolTable.relateToOperator("unpackInt4x16", EOpUnpackInt4x16); + symbolTable.relateToOperator("packUint4x16", EOpPackUint4x16); + symbolTable.relateToOperator("unpackUint4x16", EOpUnpackUint4x16); + symbolTable.relateToOperator("packFloat2x16", EOpPackFloat2x16); + symbolTable.relateToOperator("unpackFloat2x16", EOpUnpackFloat2x16); + + symbolTable.relateToOperator("pack16", EOpPack16); + symbolTable.relateToOperator("pack32", EOpPack32); + symbolTable.relateToOperator("pack64", EOpPack64); + + symbolTable.relateToOperator("unpack32", EOpUnpack32); + symbolTable.relateToOperator("unpack16", EOpUnpack16); + symbolTable.relateToOperator("unpack8", EOpUnpack8); + symbolTable.relateToOperator("length", EOpLength); symbolTable.relateToOperator("distance", EOpDistance); symbolTable.relateToOperator("dot", EOpDot); @@ -4060,6 +8227,18 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("atomicCounterDecrement", EOpAtomicCounterDecrement); symbolTable.relateToOperator("atomicCounter", EOpAtomicCounter); + if (profile != EEsProfile && version >= 460) { + symbolTable.relateToOperator("atomicCounterAdd", EOpAtomicCounterAdd); + symbolTable.relateToOperator("atomicCounterSubtract", EOpAtomicCounterSubtract); + symbolTable.relateToOperator("atomicCounterMin", EOpAtomicCounterMin); + symbolTable.relateToOperator("atomicCounterMax", EOpAtomicCounterMax); + symbolTable.relateToOperator("atomicCounterAnd", EOpAtomicCounterAnd); + symbolTable.relateToOperator("atomicCounterOr", EOpAtomicCounterOr); + symbolTable.relateToOperator("atomicCounterXor", EOpAtomicCounterXor); + symbolTable.relateToOperator("atomicCounterExchange", EOpAtomicCounterExchange); + symbolTable.relateToOperator("atomicCounterCompSwap", EOpAtomicCounterCompSwap); + } + symbolTable.relateToOperator("fma", EOpFma); symbolTable.relateToOperator("frexp", EOpFrexp); symbolTable.relateToOperator("ldexp", EOpLdexp); @@ -4202,9 +8381,150 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("readInvocationARB", EOpReadInvocation); symbolTable.relateToOperator("readFirstInvocationARB", EOpReadFirstInvocation); - symbolTable.relateToOperator("anyInvocationARB", EOpAnyInvocation); - symbolTable.relateToOperator("allInvocationsARB", EOpAllInvocations); - symbolTable.relateToOperator("allInvocationsEqualARB", EOpAllInvocationsEqual); + if (version >= 430) { + symbolTable.relateToOperator("anyInvocationARB", EOpAnyInvocation); + symbolTable.relateToOperator("allInvocationsARB", EOpAllInvocations); + symbolTable.relateToOperator("allInvocationsEqualARB", EOpAllInvocationsEqual); + } + if (version >= 460) { + symbolTable.relateToOperator("anyInvocation", EOpAnyInvocation); + symbolTable.relateToOperator("allInvocations", EOpAllInvocations); + symbolTable.relateToOperator("allInvocationsEqual", EOpAllInvocationsEqual); + } +#ifdef AMD_EXTENSIONS + symbolTable.relateToOperator("minInvocationsAMD", EOpMinInvocations); + symbolTable.relateToOperator("maxInvocationsAMD", EOpMaxInvocations); + symbolTable.relateToOperator("addInvocationsAMD", EOpAddInvocations); + symbolTable.relateToOperator("minInvocationsNonUniformAMD", EOpMinInvocationsNonUniform); + symbolTable.relateToOperator("maxInvocationsNonUniformAMD", EOpMaxInvocationsNonUniform); + symbolTable.relateToOperator("addInvocationsNonUniformAMD", EOpAddInvocationsNonUniform); + symbolTable.relateToOperator("minInvocationsInclusiveScanAMD", EOpMinInvocationsInclusiveScan); + symbolTable.relateToOperator("maxInvocationsInclusiveScanAMD", EOpMaxInvocationsInclusiveScan); + symbolTable.relateToOperator("addInvocationsInclusiveScanAMD", EOpAddInvocationsInclusiveScan); + symbolTable.relateToOperator("minInvocationsInclusiveScanNonUniformAMD", EOpMinInvocationsInclusiveScanNonUniform); + symbolTable.relateToOperator("maxInvocationsInclusiveScanNonUniformAMD", EOpMaxInvocationsInclusiveScanNonUniform); + symbolTable.relateToOperator("addInvocationsInclusiveScanNonUniformAMD", EOpAddInvocationsInclusiveScanNonUniform); + symbolTable.relateToOperator("minInvocationsExclusiveScanAMD", EOpMinInvocationsExclusiveScan); + symbolTable.relateToOperator("maxInvocationsExclusiveScanAMD", EOpMaxInvocationsExclusiveScan); + symbolTable.relateToOperator("addInvocationsExclusiveScanAMD", EOpAddInvocationsExclusiveScan); + symbolTable.relateToOperator("minInvocationsExclusiveScanNonUniformAMD", EOpMinInvocationsExclusiveScanNonUniform); + symbolTable.relateToOperator("maxInvocationsExclusiveScanNonUniformAMD", EOpMaxInvocationsExclusiveScanNonUniform); + symbolTable.relateToOperator("addInvocationsExclusiveScanNonUniformAMD", EOpAddInvocationsExclusiveScanNonUniform); + symbolTable.relateToOperator("swizzleInvocationsAMD", EOpSwizzleInvocations); + symbolTable.relateToOperator("swizzleInvocationsMaskedAMD", EOpSwizzleInvocationsMasked); + symbolTable.relateToOperator("writeInvocationAMD", EOpWriteInvocation); + symbolTable.relateToOperator("mbcntAMD", EOpMbcnt); + + symbolTable.relateToOperator("min3", EOpMin3); + symbolTable.relateToOperator("max3", EOpMax3); + symbolTable.relateToOperator("mid3", EOpMid3); + + symbolTable.relateToOperator("cubeFaceIndexAMD", EOpCubeFaceIndex); + symbolTable.relateToOperator("cubeFaceCoordAMD", EOpCubeFaceCoord); + symbolTable.relateToOperator("timeAMD", EOpTime); + + symbolTable.relateToOperator("textureGatherLodAMD", EOpTextureGatherLod); + symbolTable.relateToOperator("textureGatherLodOffsetAMD", EOpTextureGatherLodOffset); + symbolTable.relateToOperator("textureGatherLodOffsetsAMD", EOpTextureGatherLodOffsets); + symbolTable.relateToOperator("sparseTextureGatherLodAMD", EOpSparseTextureGatherLod); + symbolTable.relateToOperator("sparseTextureGatherLodOffsetAMD", EOpSparseTextureGatherLodOffset); + symbolTable.relateToOperator("sparseTextureGatherLodOffsetsAMD", EOpSparseTextureGatherLodOffsets); + + symbolTable.relateToOperator("imageLoadLodAMD", EOpImageLoadLod); + symbolTable.relateToOperator("imageStoreLodAMD", EOpImageStoreLod); + symbolTable.relateToOperator("sparseImageLoadLodAMD", EOpSparseImageLoadLod); + + symbolTable.relateToOperator("fragmentMaskFetchAMD", EOpFragmentMaskFetch); + symbolTable.relateToOperator("fragmentFetchAMD", EOpFragmentFetch); +#endif + } + + // GL_KHR_shader_subgroup + if (spvVersion.vulkan > 0) { + symbolTable.relateToOperator("subgroupBarrier", EOpSubgroupBarrier); + symbolTable.relateToOperator("subgroupMemoryBarrier", EOpSubgroupMemoryBarrier); + symbolTable.relateToOperator("subgroupMemoryBarrierBuffer", EOpSubgroupMemoryBarrierBuffer); + symbolTable.relateToOperator("subgroupMemoryBarrierImage", EOpSubgroupMemoryBarrierImage); + symbolTable.relateToOperator("subgroupElect", EOpSubgroupElect); + symbolTable.relateToOperator("subgroupAll", EOpSubgroupAll); + symbolTable.relateToOperator("subgroupAny", EOpSubgroupAny); + symbolTable.relateToOperator("subgroupAllEqual", EOpSubgroupAllEqual); + symbolTable.relateToOperator("subgroupBroadcast", EOpSubgroupBroadcast); + symbolTable.relateToOperator("subgroupBroadcastFirst", EOpSubgroupBroadcastFirst); + symbolTable.relateToOperator("subgroupBallot", EOpSubgroupBallot); + symbolTable.relateToOperator("subgroupInverseBallot", EOpSubgroupInverseBallot); + symbolTable.relateToOperator("subgroupBallotBitExtract", EOpSubgroupBallotBitExtract); + symbolTable.relateToOperator("subgroupBallotBitCount", EOpSubgroupBallotBitCount); + symbolTable.relateToOperator("subgroupBallotInclusiveBitCount", EOpSubgroupBallotInclusiveBitCount); + symbolTable.relateToOperator("subgroupBallotExclusiveBitCount", EOpSubgroupBallotExclusiveBitCount); + symbolTable.relateToOperator("subgroupBallotFindLSB", EOpSubgroupBallotFindLSB); + symbolTable.relateToOperator("subgroupBallotFindMSB", EOpSubgroupBallotFindMSB); + symbolTable.relateToOperator("subgroupShuffle", EOpSubgroupShuffle); + symbolTable.relateToOperator("subgroupShuffleXor", EOpSubgroupShuffleXor); + symbolTable.relateToOperator("subgroupShuffleUp", EOpSubgroupShuffleUp); + symbolTable.relateToOperator("subgroupShuffleDown", EOpSubgroupShuffleDown); + symbolTable.relateToOperator("subgroupAdd", EOpSubgroupAdd); + symbolTable.relateToOperator("subgroupMul", EOpSubgroupMul); + symbolTable.relateToOperator("subgroupMin", EOpSubgroupMin); + symbolTable.relateToOperator("subgroupMax", EOpSubgroupMax); + symbolTable.relateToOperator("subgroupAnd", EOpSubgroupAnd); + symbolTable.relateToOperator("subgroupOr", EOpSubgroupOr); + symbolTable.relateToOperator("subgroupXor", EOpSubgroupXor); + symbolTable.relateToOperator("subgroupInclusiveAdd", EOpSubgroupInclusiveAdd); + symbolTable.relateToOperator("subgroupInclusiveMul", EOpSubgroupInclusiveMul); + symbolTable.relateToOperator("subgroupInclusiveMin", EOpSubgroupInclusiveMin); + symbolTable.relateToOperator("subgroupInclusiveMax", EOpSubgroupInclusiveMax); + symbolTable.relateToOperator("subgroupInclusiveAnd", EOpSubgroupInclusiveAnd); + symbolTable.relateToOperator("subgroupInclusiveOr", EOpSubgroupInclusiveOr); + symbolTable.relateToOperator("subgroupInclusiveXor", EOpSubgroupInclusiveXor); + symbolTable.relateToOperator("subgroupExclusiveAdd", EOpSubgroupExclusiveAdd); + symbolTable.relateToOperator("subgroupExclusiveMul", EOpSubgroupExclusiveMul); + symbolTable.relateToOperator("subgroupExclusiveMin", EOpSubgroupExclusiveMin); + symbolTable.relateToOperator("subgroupExclusiveMax", EOpSubgroupExclusiveMax); + symbolTable.relateToOperator("subgroupExclusiveAnd", EOpSubgroupExclusiveAnd); + symbolTable.relateToOperator("subgroupExclusiveOr", EOpSubgroupExclusiveOr); + symbolTable.relateToOperator("subgroupExclusiveXor", EOpSubgroupExclusiveXor); + symbolTable.relateToOperator("subgroupClusteredAdd", EOpSubgroupClusteredAdd); + symbolTable.relateToOperator("subgroupClusteredMul", EOpSubgroupClusteredMul); + symbolTable.relateToOperator("subgroupClusteredMin", EOpSubgroupClusteredMin); + symbolTable.relateToOperator("subgroupClusteredMax", EOpSubgroupClusteredMax); + symbolTable.relateToOperator("subgroupClusteredAnd", EOpSubgroupClusteredAnd); + symbolTable.relateToOperator("subgroupClusteredOr", EOpSubgroupClusteredOr); + symbolTable.relateToOperator("subgroupClusteredXor", EOpSubgroupClusteredXor); + symbolTable.relateToOperator("subgroupQuadBroadcast", EOpSubgroupQuadBroadcast); + symbolTable.relateToOperator("subgroupQuadSwapHorizontal", EOpSubgroupQuadSwapHorizontal); + symbolTable.relateToOperator("subgroupQuadSwapVertical", EOpSubgroupQuadSwapVertical); + symbolTable.relateToOperator("subgroupQuadSwapDiagonal", EOpSubgroupQuadSwapDiagonal); + +#ifdef NV_EXTENSIONS + symbolTable.relateToOperator("subgroupPartitionNV", EOpSubgroupPartition); + symbolTable.relateToOperator("subgroupPartitionedAddNV", EOpSubgroupPartitionedAdd); + symbolTable.relateToOperator("subgroupPartitionedMulNV", EOpSubgroupPartitionedMul); + symbolTable.relateToOperator("subgroupPartitionedMinNV", EOpSubgroupPartitionedMin); + symbolTable.relateToOperator("subgroupPartitionedMaxNV", EOpSubgroupPartitionedMax); + symbolTable.relateToOperator("subgroupPartitionedAndNV", EOpSubgroupPartitionedAnd); + symbolTable.relateToOperator("subgroupPartitionedOrNV", EOpSubgroupPartitionedOr); + symbolTable.relateToOperator("subgroupPartitionedXorNV", EOpSubgroupPartitionedXor); + symbolTable.relateToOperator("subgroupPartitionedInclusiveAddNV", EOpSubgroupPartitionedInclusiveAdd); + symbolTable.relateToOperator("subgroupPartitionedInclusiveMulNV", EOpSubgroupPartitionedInclusiveMul); + symbolTable.relateToOperator("subgroupPartitionedInclusiveMinNV", EOpSubgroupPartitionedInclusiveMin); + symbolTable.relateToOperator("subgroupPartitionedInclusiveMaxNV", EOpSubgroupPartitionedInclusiveMax); + symbolTable.relateToOperator("subgroupPartitionedInclusiveAndNV", EOpSubgroupPartitionedInclusiveAnd); + symbolTable.relateToOperator("subgroupPartitionedInclusiveOrNV", EOpSubgroupPartitionedInclusiveOr); + symbolTable.relateToOperator("subgroupPartitionedInclusiveXorNV", EOpSubgroupPartitionedInclusiveXor); + symbolTable.relateToOperator("subgroupPartitionedExclusiveAddNV", EOpSubgroupPartitionedExclusiveAdd); + symbolTable.relateToOperator("subgroupPartitionedExclusiveMulNV", EOpSubgroupPartitionedExclusiveMul); + symbolTable.relateToOperator("subgroupPartitionedExclusiveMinNV", EOpSubgroupPartitionedExclusiveMin); + symbolTable.relateToOperator("subgroupPartitionedExclusiveMaxNV", EOpSubgroupPartitionedExclusiveMax); + symbolTable.relateToOperator("subgroupPartitionedExclusiveAndNV", EOpSubgroupPartitionedExclusiveAnd); + symbolTable.relateToOperator("subgroupPartitionedExclusiveOrNV", EOpSubgroupPartitionedExclusiveOr); + symbolTable.relateToOperator("subgroupPartitionedExclusiveXorNV", EOpSubgroupPartitionedExclusiveXor); +#endif + } + + if (profile == EEsProfile) { + symbolTable.relateToOperator("shadow2DEXT", EOpTexture); + symbolTable.relateToOperator("shadow2DProjEXT", EOpTextureProj); } } @@ -4238,11 +8558,17 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("interpolateAtCentroid", EOpInterpolateAtCentroid); symbolTable.relateToOperator("interpolateAtSample", EOpInterpolateAtSample); symbolTable.relateToOperator("interpolateAtOffset", EOpInterpolateAtOffset); + +#ifdef AMD_EXTENSIONS + if (profile != EEsProfile) + symbolTable.relateToOperator("interpolateAtVertexAMD", EOpInterpolateAtVertex); +#endif break; case EShLangCompute: - symbolTable.relateToOperator("memoryBarrierShared", EOpMemoryBarrierShared); - symbolTable.relateToOperator("groupMemoryBarrier", EOpGroupMemoryBarrier); + symbolTable.relateToOperator("memoryBarrierShared", EOpMemoryBarrierShared); + symbolTable.relateToOperator("groupMemoryBarrier", EOpGroupMemoryBarrier); + symbolTable.relateToOperator("subgroupMemoryBarrierShared", EOpSubgroupMemoryBarrierShared); break; default: @@ -4252,7 +8578,7 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion // // Add context-dependent (resource-specific) built-ins not handled by the above. These -// would be ones that need to be programmatically added because they cannot +// would be ones that need to be programmatically added because they cannot // be added by simple text strings. For these, also // 1) Map built-in functions to operators, for those that will turn into an operation node // instead of remaining a function call. @@ -4278,9 +8604,9 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion if (version == 100 || IncludeLegacy(version, profile, spvVersion) || (! ForwardCompatibility && profile != EEsProfile && version < 420)) { TPrecisionQualifier pq = profile == EEsProfile ? EpqMedium : EpqNone; TType fragData(EbtFloat, EvqFragColor, pq, 4); - TArraySizes& arraySizes = *new TArraySizes; - arraySizes.addInnerSize(resources.maxDrawBuffers); - fragData.newArraySizes(arraySizes); + TArraySizes* arraySizes = new TArraySizes; + arraySizes->addInnerSize(resources.maxDrawBuffers); + fragData.transferArraySizes(arraySizes); symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"), fragData)); SpecialQualifier("gl_FragData", EvqFragColor, EbvFragData, symbolTable); } diff --git a/Externals/glslang/glslang/MachineIndependent/Initialize.h b/Externals/glslang/glslang/MachineIndependent/Initialize.h index 23f57acc17..b5de324233 100644 --- a/Externals/glslang/glslang/MachineIndependent/Initialize.h +++ b/Externals/glslang/glslang/MachineIndependent/Initialize.h @@ -1,12 +1,12 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2013-2016 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2013-2016 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,18 +20,18 @@ // 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. +// 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 _INITIALIZE_INCLUDED_ @@ -67,7 +67,6 @@ public: virtual const TString& getStageString(EShLanguage language) const { return stageBuiltins[language]; } virtual void identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable) = 0; - virtual void identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources) = 0; protected: @@ -89,16 +88,15 @@ public: void initialize(const TBuiltInResource& resources, int version, EProfile, const SpvVersion& spvVersion, EShLanguage); void identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable); - void identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources); protected: void add2ndGenerationSamplingImaging(int version, EProfile profile, const SpvVersion& spvVersion); - void addSubpassSampling(TSampler, TString& typeName, int version, EProfile profile); - void addQueryFunctions(TSampler, TString& typeName, int version, EProfile profile); - void addImageFunctions(TSampler, TString& typeName, int version, EProfile profile); - void addSamplingFunctions(TSampler, TString& typeName, int version, EProfile profile); - void addGatherFunctions(TSampler, TString& typeName, int version, EProfile profile); + void addSubpassSampling(TSampler, const TString& typeName, int version, EProfile profile); + void addQueryFunctions(TSampler, const TString& typeName, int version, EProfile profile); + void addImageFunctions(TSampler, const TString& typeName, int version, EProfile profile); + void addSamplingFunctions(TSampler, const TString& typeName, int version, EProfile profile); + void addGatherFunctions(TSampler, const TString& typeName, int version, EProfile profile); // Helpers for making textual representations of the permutations // of texturing/imaging functions. @@ -107,7 +105,6 @@ protected: int dimMap[EsdNumDims]; }; - } // end namespace glslang #endif // _INITIALIZE_INCLUDED_ diff --git a/Externals/glslang/glslang/MachineIndependent/IntermTraverse.cpp b/Externals/glslang/glslang/MachineIndependent/IntermTraverse.cpp index b910f47388..f46010b712 100644 --- a/Externals/glslang/glslang/MachineIndependent/IntermTraverse.cpp +++ b/Externals/glslang/glslang/MachineIndependent/IntermTraverse.cpp @@ -1,13 +1,13 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2013 LunarG, Inc. -//Copyright (c) 2002-2010 The ANGLE Project Authors. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2013 LunarG, Inc. +// Copyright (c) 2002-2010 The ANGLE Project Authors. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -21,18 +21,18 @@ // 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. +// 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. // #include "../Include/intermediate.h" diff --git a/Externals/glslang/glslang/MachineIndependent/Intermediate.cpp b/Externals/glslang/glslang/MachineIndependent/Intermediate.cpp index 02681ac556..de722179c7 100644 --- a/Externals/glslang/glslang/MachineIndependent/Intermediate.cpp +++ b/Externals/glslang/glslang/MachineIndependent/Intermediate.cpp @@ -1,13 +1,14 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2012-2015 LunarG, Inc. -//Copyright (C) 2015-2016 Google, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2012-2015 LunarG, Inc. +// Copyright (C) 2015-2016 Google, Inc. +// Copyright (C) 2017 ARM Limited. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -21,18 +22,18 @@ // 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. +// 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. // // @@ -44,7 +45,9 @@ #include "SymbolTable.h" #include "propagateNoContraction.h" -#include +#include +#include +#include namespace glslang { @@ -73,6 +76,16 @@ TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType return node; } +TIntermSymbol* TIntermediate::addSymbol(const TIntermSymbol& intermSymbol) +{ + return addSymbol(intermSymbol.getId(), + intermSymbol.getName(), + intermSymbol.getType(), + intermSymbol.getConstArray(), + intermSymbol.getConstSubtree(), + intermSymbol.getLoc()); +} + TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable) { glslang::TSourceLoc loc; // just a null location @@ -98,37 +111,34 @@ TIntermSymbol* TIntermediate::addSymbol(const TType& type, const TSourceLoc& loc // // Returns the added node. // +// Returns nullptr if the working conversions and promotions could not be found. +// TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc loc) { // No operations work on blocks if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock) - return 0; + return nullptr; // Try converting the children's base types to compatible types. - TIntermTyped* child = addConversion(op, left->getType(), right); - if (child) - right = child; - else { - child = addConversion(op, right->getType(), left); - if (child) - left = child; - else - return 0; - } + auto children = addConversion(op, left, right); + left = std::get<0>(children); + right = std::get<1>(children); + + if (left == nullptr || right == nullptr) + return nullptr; + + // Convert the children's type shape to be compatible. + addBiShapeConversion(op, left, right); + if (left == nullptr || right == nullptr) + return nullptr; // // Need a new node holding things together. Make // one and promote it to the right type. // - TIntermBinary* node = new TIntermBinary(op); - if (loc.line == 0) - loc = right->getLoc(); - node->setLoc(loc); - - node->setLeft(left); - node->setRight(right); - if (! node->promote()) - return 0; + TIntermBinary* node = addBinaryNode(op, left, right, loc); + if (! promote(node)) + return nullptr; node->updatePrecision(); @@ -136,23 +146,74 @@ TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIn // If they are both (non-specialization) constants, they must be folded. // (Unless it's the sequence (comma) operator, but that's handled in addComma().) // - TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion(); - TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion(); + TIntermConstantUnion *leftTempConstant = node->getLeft()->getAsConstantUnion(); + TIntermConstantUnion *rightTempConstant = node->getRight()->getAsConstantUnion(); if (leftTempConstant && rightTempConstant) { TIntermTyped* folded = leftTempConstant->fold(node->getOp(), rightTempConstant); if (folded) return folded; } - // If either is a specialization constant, while the other is - // a constant (or specialization constant), the result is still - // a specialization constant, if the operation is an allowed - // specialization-constant operation. - if (( left->getType().getQualifier().isSpecConstant() && right->getType().getQualifier().isConstant()) || - (right->getType().getQualifier().isSpecConstant() && left->getType().getQualifier().isConstant())) - if (isSpecializationOperation(*node)) - node->getWritableType().getQualifier().makeSpecConstant(); + // If can propagate spec-constantness and if the operation is an allowed + // specialization-constant operation, make a spec-constant. + if (specConstantPropagates(*node->getLeft(), *node->getRight()) && isSpecializationOperation(*node)) + node->getWritableType().getQualifier().makeSpecConstant(); + // If must propagate nonuniform, make a nonuniform. + if ((node->getLeft()->getQualifier().nonUniform || node->getRight()->getQualifier().nonUniform) && + isNonuniformPropagating(node->getOp())) + node->getWritableType().getQualifier().nonUniform = true; + + return node; +} + +// +// Low level: add binary node (no promotions or other argument modifications) +// +TIntermBinary* TIntermediate::addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc loc) const +{ + // build the node + TIntermBinary* node = new TIntermBinary(op); + if (loc.line == 0) + loc = left->getLoc(); + node->setLoc(loc); + node->setLeft(left); + node->setRight(right); + + return node; +} + +// +// like non-type form, but sets node's type. +// +TIntermBinary* TIntermediate::addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc loc, const TType& type) const +{ + TIntermBinary* node = addBinaryNode(op, left, right, loc); + node->setType(type); + return node; +} + +// +// Low level: add unary node (no promotions or other argument modifications) +// +TIntermUnary* TIntermediate::addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc loc) const +{ + TIntermUnary* node = new TIntermUnary(op); + if (loc.line == 0) + loc = child->getLoc(); + node->setLoc(loc); + node->setOperand(child); + + return node; +} + +// +// like non-type form, but sets node's type. +// +TIntermUnary* TIntermediate::addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc loc, const TType& type) const +{ + TIntermUnary* node = addUnaryNode(op, child, loc); + node->setType(type); return node; } @@ -161,29 +222,33 @@ TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIn // // Returns the added node. // +// Returns nullptr if the 'right' type could not be converted to match the 'left' type, +// or the resulting operation cannot be properly promoted. +// TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc loc) { // No block assignment if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock) - return 0; + return nullptr; // // Like adding binary math, except the conversion can only go // from right to left. // - TIntermBinary* node = new TIntermBinary(op); - if (loc.line == 0) - loc = left->getLoc(); - node->setLoc(loc); - TIntermTyped* child = addConversion(op, left->getType(), right); - if (child == 0) - return 0; + // convert base types, nullptr return means not possible + right = addConversion(op, left->getType(), right); + if (right == nullptr) + return nullptr; - node->setLeft(left); - node->setRight(child); - if (! node->promote()) - return 0; + // convert shape + right = addUniShapeConversion(op, left->getType(), right); + + // build the node + TIntermBinary* node = addBinaryNode(op, left, right, loc); + + if (! promote(node)) + return nullptr; node->updatePrecision(); @@ -199,16 +264,8 @@ TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TInterm // TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc loc) { - TIntermBinary* node = new TIntermBinary(op); - if (loc.line == 0) - loc = index->getLoc(); - node->setLoc(loc); - node->setLeft(base); - node->setRight(index); - // caller should set the type - - return node; + return addBinaryNode(op, base, index, loc); } // @@ -219,15 +276,19 @@ TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermT TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, TSourceLoc loc) { if (child == 0) - return 0; + return nullptr; if (child->getType().getBasicType() == EbtBlock) - return 0; + return nullptr; switch (op) { case EOpLogicalNot: + if (source == EShSourceHlsl) { + break; // HLSL can promote logical not + } + if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) { - return 0; + return nullptr; } break; @@ -237,7 +298,7 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, TSo case EOpPreDecrement: case EOpNegative: if (child->getType().getBasicType() == EbtStruct || child->getType().isArray()) - return 0; + return nullptr; default: break; // some compilers want this } @@ -246,6 +307,10 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, TSo // TBasicType newType = EbtVoid; switch (op) { + case EOpConstructInt8: newType = EbtInt8; break; + case EOpConstructUint8: newType = EbtUint8; break; + case EOpConstructInt16: newType = EbtInt16; break; + case EOpConstructUint16: newType = EbtUint16; break; case EOpConstructInt: newType = EbtInt; break; case EOpConstructUint: newType = EbtUint; break; case EOpConstructInt64: newType = EbtInt64; break; @@ -253,16 +318,18 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, TSo case EOpConstructBool: newType = EbtBool; break; case EOpConstructFloat: newType = EbtFloat; break; case EOpConstructDouble: newType = EbtDouble; break; + case EOpConstructFloat16: newType = EbtFloat16; break; default: break; // some compilers want this } if (newType != EbtVoid) { child = addConversion(op, TType(newType, EvqTemporary, child->getVectorSize(), child->getMatrixCols(), - child->getMatrixRows()), + child->getMatrixRows(), + child->isVector()), child); - if (child == 0) - return 0; + if (child == nullptr) + return nullptr; } // @@ -270,6 +337,10 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, TSo // TODO: but, did this bypass constant folding? // switch (op) { + case EOpConstructInt8: + case EOpConstructUint8: + case EOpConstructInt16: + case EOpConstructUint16: case EOpConstructInt: case EOpConstructUint: case EOpConstructInt64: @@ -277,6 +348,7 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, TSo case EOpConstructBool: case EOpConstructFloat: case EOpConstructDouble: + case EOpConstructFloat16: return child; default: break; // some compilers want this } @@ -284,30 +356,31 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, TSo // // Make a new node for the operator. // - TIntermUnary* node = new TIntermUnary(op); - if (loc.line == 0) - loc = child->getLoc(); - node->setLoc(loc); - node->setOperand(child); + TIntermUnary* node = addUnaryNode(op, child, loc); - if (! node->promote()) - return 0; + if (! promote(node)) + return nullptr; node->updatePrecision(); // If it's a (non-specialization) constant, it must be folded. - if (child->getAsConstantUnion()) - return child->getAsConstantUnion()->fold(op, node->getType()); + if (node->getOperand()->getAsConstantUnion()) + return node->getOperand()->getAsConstantUnion()->fold(op, node->getType()); // If it's a specialization constant, the result is too, // if the operation is allowed for specialization constants. - if (child->getType().getQualifier().isSpecConstant() && isSpecializationOperation(*node)) + if (node->getOperand()->getType().getQualifier().isSpecConstant() && isSpecializationOperation(*node)) node->getWritableType().getQualifier().makeSpecConstant(); + // If must propagate nonuniform, make a nonuniform. + if (node->getOperand()->getQualifier().nonUniform && isNonuniformPropagating(node->getOp())) + node->getWritableType().getQualifier().nonUniform = true; + return node; } -TIntermTyped* TIntermediate::addBuiltInFunctionCall(const TSourceLoc& loc, TOperator op, bool unary, TIntermNode* childNode, const TType& returnType) +TIntermTyped* TIntermediate::addBuiltInFunctionCall(const TSourceLoc& loc, TOperator op, bool unary, + TIntermNode* childNode, const TType& returnType) { if (unary) { // @@ -316,8 +389,8 @@ TIntermTyped* TIntermediate::addBuiltInFunctionCall(const TSourceLoc& loc, TOper // including constness (which would differ from the prototype). // TIntermTyped* child = childNode->getAsTyped(); - if (child == 0) - return 0; + if (child == nullptr) + return nullptr; if (child->getAsConstantUnion()) { TIntermTyped* folded = child->getAsConstantUnion()->fold(op, returnType); @@ -325,40 +398,11 @@ TIntermTyped* TIntermediate::addBuiltInFunctionCall(const TSourceLoc& loc, TOper return folded; } - TIntermUnary* node = new TIntermUnary(op); - node->setLoc(child->getLoc()); - node->setOperand(child); - node->setType(returnType); - - // propagate precision up from child - if (profile == EEsProfile && returnType.getQualifier().precision == EpqNone && returnType.getBasicType() != EbtBool) - node->getQualifier().precision = child->getQualifier().precision; - - // propagate precision down to child - if (node->getQualifier().precision != EpqNone) - child->propagatePrecision(node->getQualifier().precision); - - return node; + return addUnaryNode(op, child, child->getLoc(), returnType); } else { // setAggregateOperater() calls fold() for constant folding TIntermTyped* node = setAggregateOperator(childNode, op, returnType, loc); - // if not folded, we'll still have an aggregate node to propagate precision with - if (node->getAsAggregate()) { - TPrecisionQualifier correctPrecision = returnType.getQualifier().precision; - if (correctPrecision == EpqNone && profile == EEsProfile) { - // find the maximum precision from the arguments, for the built-in's return precision - TIntermSequence& sequence = node->getAsAggregate()->getSequence(); - for (unsigned int arg = 0; arg < sequence.size(); ++arg) - correctPrecision = std::max(correctPrecision, sequence[arg]->getAsTyped()->getQualifier().precision); - } - - // Propagate precision through this node and its children. That algorithm stops - // when a precision is found, so start by clearing this subroot precision - node->getQualifier().precision = EpqNone; - node->propagatePrecision(correctPrecision); - } - return node; } } @@ -380,9 +424,9 @@ TIntermTyped* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator o // // Make sure we have an aggregate. If not turn it into one. // - if (node) { + if (node != nullptr) { aggNode = node->getAsAggregate(); - if (aggNode == 0 || aggNode->getOp() != EOpNull) { + if (aggNode == nullptr || aggNode->getOp() != EOpNull) { // // Make an aggregate containing this node. // @@ -406,84 +450,305 @@ TIntermTyped* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator o return fold(aggNode); } -// -// Convert the node's type to the given type, as allowed by the operation involved: 'op'. -// For implicit conversions, 'op' is not the requested conversion, it is the explicit -// operation requiring the implicit conversion. -// -// Returns a node representing the conversion, which could be the same -// node passed in if no conversion was needed. -// -// Return 0 if a conversion can't be done. -// -TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) const +bool TIntermediate::isConversionAllowed(TOperator op, TIntermTyped* node) const { // // Does the base type even allow the operation? // switch (node->getBasicType()) { case EbtVoid: - return 0; + return false; case EbtAtomicUint: case EbtSampler: // opaque types can be passed to functions if (op == EOpFunction) break; + + // HLSL can assign samplers directly (no constructor) + if (source == EShSourceHlsl && node->getBasicType() == EbtSampler) + break; + // samplers can get assigned via a sampler constructor // (well, not yet, but code in the rest of this function is ready for it) - if (node->getBasicType() == EbtSampler && op == EOpAssign && + if (node->getBasicType() == EbtSampler && op == EOpAssign && node->getAsOperator() != nullptr && node->getAsOperator()->getOp() == EOpConstructTextureSampler) break; // otherwise, opaque types can't even be operated on, let alone converted - return 0; + return false; default: break; } - // Otherwise, if types are identical, no problem - if (type == node->getType()) - return node; + return true; +} - // If one's a structure, then no conversions. - if (type.isStruct() || node->isStruct()) - return 0; +// This is 'mechanism' here, it does any conversion told. +// It is about basic type, not about shape. +// The policy comes from the shader or the calling code. +TIntermUnary* TIntermediate::createConversion(TBasicType convertTo, TIntermTyped* node) const +{ + // + // Add a new newNode for the conversion. + // + TIntermUnary* newNode = nullptr; - // If one's an array, then no conversions. - if (type.isArray() || node->getType().isArray()) - return 0; + TOperator newOp = EOpNull; - // Note: callers are responsible for other aspects of shape, - // like vector and matrix sizes. + switch (convertTo) { + case EbtDouble: + switch (node->getBasicType()) { + case EbtInt8: newOp = EOpConvInt8ToDouble; break; + case EbtUint8: newOp = EOpConvUint8ToDouble; break; + case EbtInt16: newOp = EOpConvInt16ToDouble; break; + case EbtUint16: newOp = EOpConvUint16ToDouble; break; + case EbtInt: newOp = EOpConvIntToDouble; break; + case EbtUint: newOp = EOpConvUintToDouble; break; + case EbtBool: newOp = EOpConvBoolToDouble; break; + case EbtFloat: newOp = EOpConvFloatToDouble; break; + case EbtFloat16: newOp = EOpConvFloat16ToDouble; break; + case EbtInt64: newOp = EOpConvInt64ToDouble; break; + case EbtUint64: newOp = EOpConvUint64ToDouble; break; + default: + return nullptr; + } + break; + case EbtFloat: + switch (node->getBasicType()) { + case EbtInt8: newOp = EOpConvInt8ToFloat; break; + case EbtUint8: newOp = EOpConvUint8ToFloat; break; + case EbtInt16: newOp = EOpConvInt16ToFloat; break; + case EbtUint16: newOp = EOpConvUint16ToFloat; break; + case EbtInt: newOp = EOpConvIntToFloat; break; + case EbtUint: newOp = EOpConvUintToFloat; break; + case EbtBool: newOp = EOpConvBoolToFloat; break; + case EbtDouble: newOp = EOpConvDoubleToFloat; break; + case EbtFloat16: newOp = EOpConvFloat16ToFloat; break; + case EbtInt64: newOp = EOpConvInt64ToFloat; break; + case EbtUint64: newOp = EOpConvUint64ToFloat; break; + default: + return nullptr; + } + break; + case EbtFloat16: + switch (node->getBasicType()) { + 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 nullptr; + } + break; + case EbtBool: + switch (node->getBasicType()) { + case EbtInt8: newOp = EOpConvInt8ToBool; break; + case EbtUint8: newOp = EOpConvUint8ToBool; break; + case EbtInt16: newOp = EOpConvInt16ToBool; break; + case EbtUint16: newOp = EOpConvUint16ToBool; break; + case EbtInt: newOp = EOpConvIntToBool; break; + case EbtUint: newOp = EOpConvUintToBool; break; + case EbtFloat: newOp = EOpConvFloatToBool; break; + case EbtDouble: newOp = EOpConvDoubleToBool; break; + case EbtFloat16: newOp = EOpConvFloat16ToBool; break; + case EbtInt64: newOp = EOpConvInt64ToBool; break; + case EbtUint64: newOp = EOpConvUint64ToBool; break; + default: + return nullptr; + } + break; + case EbtInt8: + switch (node->getBasicType()) { + 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 nullptr; + } + break; + case EbtUint8: + switch (node->getBasicType()) { + 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 nullptr; + } + break; - TBasicType promoteTo; + case EbtInt16: + switch (node->getBasicType()) { + 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 nullptr; + } + break; + case EbtUint16: + switch (node->getBasicType()) { + 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 nullptr; + } + break; + + case EbtInt: + switch (node->getBasicType()) { + case EbtInt8: newOp = EOpConvInt8ToInt; break; + case EbtUint8: newOp = EOpConvUint8ToInt; break; + case EbtInt16: newOp = EOpConvInt16ToInt; break; + case EbtUint16: newOp = EOpConvUint16ToInt; break; + case EbtUint: newOp = EOpConvUintToInt; break; + case EbtBool: newOp = EOpConvBoolToInt; break; + case EbtFloat: newOp = EOpConvFloatToInt; break; + case EbtDouble: newOp = EOpConvDoubleToInt; break; + case EbtFloat16: newOp = EOpConvFloat16ToInt; break; + case EbtInt64: newOp = EOpConvInt64ToInt; break; + case EbtUint64: newOp = EOpConvUint64ToInt; break; + default: + return nullptr; + } + break; + case EbtUint: + switch (node->getBasicType()) { + case EbtInt8: newOp = EOpConvInt8ToUint; break; + case EbtUint8: newOp = EOpConvUint8ToUint; break; + case EbtInt16: newOp = EOpConvInt16ToUint; break; + case EbtUint16: newOp = EOpConvUint16ToUint; break; + case EbtInt: newOp = EOpConvIntToUint; break; + case EbtBool: newOp = EOpConvBoolToUint; break; + case EbtFloat: newOp = EOpConvFloatToUint; break; + case EbtDouble: newOp = EOpConvDoubleToUint; break; + case EbtFloat16: newOp = EOpConvFloat16ToUint; break; + case EbtInt64: newOp = EOpConvInt64ToUint; break; + case EbtUint64: newOp = EOpConvUint64ToUint; break; + default: + return nullptr; + } + break; + case EbtInt64: + switch (node->getBasicType()) { + 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 nullptr; + } + break; + case EbtUint64: + switch (node->getBasicType()) { + 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 nullptr; + } + break; + default: + return nullptr; + } + + TType newType(convertTo, EvqTemporary, node->getVectorSize(), node->getMatrixCols(), node->getMatrixRows()); + newNode = addUnaryNode(newOp, node, node->getLoc(), newType); + + // TODO: it seems that some unary folding operations should occur here, but are not + + // Propagate specialization-constant-ness, if allowed + if (node->getType().getQualifier().isSpecConstant() && isSpecializationOperation(*newNode)) + newNode->getWritableType().getQualifier().makeSpecConstant(); + + return newNode; +} + +// For converting a pair of operands to a binary operation to compatible +// types with each other, relative to the operation in 'op'. +// This does not cover assignment operations, which is asymmetric in that the +// left type is not changeable. +// See addConversion(op, type, node) for assignments and unary operation +// conversions. +// +// Generally, this is focused on basic type conversion, not shape conversion. +// See addShapeConversion() for shape conversions. +// +// Returns the converted pair of nodes. +// Returns when there is no conversion. +std::tuple +TIntermediate::addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1) const +{ + if (!isConversionAllowed(op, node0) || !isConversionAllowed(op, node1)) + return std::make_tuple(nullptr, nullptr); + + if (node0->getType() != node1->getType()) { + // If differing structure, then no conversions. + if (node0->isStruct() || node1->isStruct()) + return std::make_tuple(nullptr, nullptr); + + // If differing arrays, then no conversions. + if (node0->getType().isArray() || node1->getType().isArray()) + return std::make_tuple(nullptr, nullptr); + } + + auto promoteTo = std::make_tuple(EbtNumTypes, EbtNumTypes); switch (op) { - // - // Explicit conversions (unary operations) - // - case EOpConstructBool: - promoteTo = EbtBool; - break; - case EOpConstructFloat: - promoteTo = EbtFloat; - break; - case EOpConstructDouble: - promoteTo = EbtDouble; - break; - case EOpConstructInt: - promoteTo = EbtInt; - break; - case EOpConstructUint: - promoteTo = EbtUint; - break; - case EOpConstructInt64: - promoteTo = EbtInt64; - break; - case EOpConstructUint64: - promoteTo = EbtUint64; - break; - // // List all the binary ops that can implicitly convert one operand to the other's type; // This implements the 'policy' for implicit type conversion. @@ -509,11 +774,159 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt case EOpAnd: case EOpInclusiveOr: case EOpExclusiveOr: - case EOpAndAssign: - case EOpInclusiveOrAssign: - case EOpExclusiveOrAssign: + + case EOpSequence: // used by ?: + + if (node0->getBasicType() == node1->getBasicType()) + return std::make_tuple(node0, node1); + + promoteTo = getConversionDestinatonType(node0->getBasicType(), node1->getBasicType(), op); + if (std::get<0>(promoteTo) == EbtNumTypes || std::get<1>(promoteTo) == EbtNumTypes) + return std::make_tuple(nullptr, nullptr); + + break; + + case EOpLogicalAnd: + case EOpLogicalOr: + case EOpLogicalXor: + if (source == EShSourceHlsl) + promoteTo = std::make_tuple(EbtBool, EbtBool); + else + return std::make_tuple(node0, node1); + break; + + // There are no conversions needed for GLSL; the shift amount just needs to be an + // integer type, as does the base. + // HLSL can promote bools to ints to make this work. + case EOpLeftShift: + case EOpRightShift: + if (source == EShSourceHlsl) { + TBasicType node0BasicType = node0->getBasicType(); + if (node0BasicType == EbtBool) + node0BasicType = EbtInt; + if (node1->getBasicType() == EbtBool) + promoteTo = std::make_tuple(node0BasicType, EbtInt); + else + promoteTo = std::make_tuple(node0BasicType, node1->getBasicType()); + } else { + if (isTypeInt(node0->getBasicType()) && isTypeInt(node1->getBasicType())) + return std::make_tuple(node0, node1); + else + return std::make_tuple(nullptr, nullptr); + } + break; + + default: + if (node0->getType() == node1->getType()) + return std::make_tuple(node0, node1); + + return std::make_tuple(nullptr, nullptr); + } + + TIntermTyped* newNode0; + TIntermTyped* newNode1; + + if (std::get<0>(promoteTo) != node0->getType().getBasicType()) { + if (node0->getAsConstantUnion()) + newNode0 = promoteConstantUnion(std::get<0>(promoteTo), node0->getAsConstantUnion()); + else + newNode0 = createConversion(std::get<0>(promoteTo), node0); + } else + newNode0 = node0; + + if (std::get<1>(promoteTo) != node1->getType().getBasicType()) { + if (node1->getAsConstantUnion()) + newNode1 = promoteConstantUnion(std::get<1>(promoteTo), node1->getAsConstantUnion()); + else + newNode1 = createConversion(std::get<1>(promoteTo), node1); + } else + newNode1 = node1; + + return std::make_tuple(newNode0, newNode1); +} + +// +// Convert the node's type to the given type, as allowed by the operation involved: 'op'. +// For implicit conversions, 'op' is not the requested conversion, it is the explicit +// operation requiring the implicit conversion. +// +// Binary operation conversions should be handled by addConversion(op, node, node), not here. +// +// Returns a node representing the conversion, which could be the same +// node passed in if no conversion was needed. +// +// Generally, this is focused on basic type conversion, not shape conversion. +// See addShapeConversion() for shape conversions. +// +// Return nullptr if a conversion can't be done. +// +TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) const +{ + if (!isConversionAllowed(op, node)) + return nullptr; + + // Otherwise, if types are identical, no problem + if (type == node->getType()) + return node; + + // If one's a structure, then no conversions. + if (type.isStruct() || node->isStruct()) + return nullptr; + + // If one's an array, then no conversions. + if (type.isArray() || node->getType().isArray()) + return nullptr; + + // Note: callers are responsible for other aspects of shape, + // like vector and matrix sizes. + + TBasicType promoteTo; + + switch (op) { + // + // Explicit conversions (unary operations) + // + case EOpConstructBool: + promoteTo = EbtBool; + break; + case EOpConstructFloat: + promoteTo = EbtFloat; + break; + case EOpConstructDouble: + promoteTo = EbtDouble; + break; + case EOpConstructFloat16: + promoteTo = EbtFloat16; + break; + case EOpConstructInt8: + promoteTo = EbtInt8; + break; + case EOpConstructUint8: + promoteTo = EbtUint8; + break; + case EOpConstructInt16: + promoteTo = EbtInt16; + break; + case EOpConstructUint16: + promoteTo = EbtUint16; + break; + case EOpConstructInt: + promoteTo = EbtInt; + break; + case EOpConstructUint: + promoteTo = EbtUint; + break; + case EOpConstructInt64: + promoteTo = EbtInt64; + break; + case EOpConstructUint64: + promoteTo = EbtUint64; + break; + + case EOpLogicalNot: case EOpFunctionCall: + case EOpReturn: case EOpAssign: case EOpAddAssign: @@ -523,6 +936,30 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt case EOpMatrixTimesScalarAssign: case EOpDivAssign: case EOpModAssign: + case EOpAndAssign: + case EOpInclusiveOrAssign: + case EOpExclusiveOrAssign: + + case EOpAtan: + case EOpClamp: + case EOpCross: + case EOpDistance: + case EOpDot: + case EOpDst: + case EOpFaceForward: + case EOpFma: + case EOpFrexp: + case EOpLdexp: + case EOpMix: + case EOpLit: + case EOpMax: + case EOpMin: + case EOpModf: + case EOpPow: + case EOpReflect: + case EOpRefract: + case EOpSmoothStep: + case EOpStep: case EOpSequence: case EOpConstructStruct: @@ -530,32 +967,28 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt if (type.getBasicType() == node->getType().getBasicType()) return node; - if (canImplicitlyPromote(node->getType().getBasicType(), type.getBasicType())) + if (canImplicitlyPromote(node->getBasicType(), type.getBasicType(), op)) promoteTo = type.getBasicType(); else - return 0; - + return nullptr; break; - // Shifts can have mixed types as long as they are integer, without converting. - // It's the left operand's type that determines the resulting type, so no issue - // with assign shift ops either. - case EOpLeftShift: - case EOpRightShift: + // For GLSL, there are no conversions needed; the shift amount just needs to be an + // integer type, as do the base/result. + // HLSL can convert the shift from a bool to an int. case EOpLeftShiftAssign: case EOpRightShiftAssign: - if ((type.getBasicType() == EbtInt || - type.getBasicType() == EbtUint || - type.getBasicType() == EbtInt64 || - type.getBasicType() == EbtUint64) && - (node->getType().getBasicType() == EbtInt || - node->getType().getBasicType() == EbtUint || - node->getType().getBasicType() == EbtInt64 || - node->getType().getBasicType() == EbtUint64)) - - return node; - else - return 0; + { + if (source == EShSourceHlsl && node->getType().getBasicType() == EbtBool) + promoteTo = type.getBasicType(); + else { + if (isTypeInt(type.getBasicType()) && isTypeInt(node->getBasicType())) + return node; + else + return nullptr; + } + break; + } default: // default is to require a match; all exceptions should have case statements above @@ -563,7 +996,7 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt if (type.getBasicType() == node->getType().getBasicType()) return node; else - return 0; + return nullptr; } if (node->getAsConstantUnion()) @@ -572,207 +1005,1083 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt // // Add a new newNode for the conversion. // - TIntermUnary* newNode = 0; + TIntermUnary* newNode = createConversion(promoteTo, node); - TOperator newOp = EOpNull; + return newNode; +} - // This is 'mechanism' here, it does any conversion told. The policy comes - // from the shader or the above code. - switch (promoteTo) { - case EbtDouble: - switch (node->getBasicType()) { - case EbtInt: newOp = EOpConvIntToDouble; break; - case EbtUint: newOp = EOpConvUintToDouble; break; - case EbtBool: newOp = EOpConvBoolToDouble; break; - case EbtFloat: newOp = EOpConvFloatToDouble; break; - case EbtInt64: newOp = EOpConvInt64ToDouble; break; - case EbtUint64: newOp = EOpConvUint64ToDouble; break; +// Convert the node's shape of type for the given type, as allowed by the +// operation involved: 'op'. This is for situations where there is only one +// direction to consider doing the shape conversion. +// +// This implements policy, it call addShapeConversion() for the mechanism. +// +// Generally, the AST represents allowed GLSL shapes, so this isn't needed +// for GLSL. Bad shapes are caught in conversion or promotion. +// +// Return 'node' if no conversion was done. Promotion handles final shape +// checking. +// +TIntermTyped* TIntermediate::addUniShapeConversion(TOperator op, const TType& type, TIntermTyped* node) +{ + // some source languages don't do this + switch (source) { + case EShSourceHlsl: + break; + case EShSourceGlsl: + default: + return node; + } + + // some operations don't do this + switch (op) { + case EOpFunctionCall: + case EOpReturn: + break; + + case EOpMulAssign: + // want to support vector *= scalar native ops in AST and lower, not smear, similarly for + // matrix *= scalar, etc. + + case EOpAddAssign: + case EOpSubAssign: + case EOpDivAssign: + case EOpAndAssign: + case EOpInclusiveOrAssign: + case EOpExclusiveOrAssign: + case EOpRightShiftAssign: + case EOpLeftShiftAssign: + if (node->getVectorSize() == 1) + return node; + break; + + case EOpAssign: + break; + + case EOpMix: + break; + + default: + return node; + } + + return addShapeConversion(type, node); +} + +// Convert the nodes' shapes to be compatible for the operation 'op'. +// +// This implements policy, it call addShapeConversion() for the mechanism. +// +// Generally, the AST represents allowed GLSL shapes, so this isn't needed +// for GLSL. Bad shapes are caught in conversion or promotion. +// +void TIntermediate::addBiShapeConversion(TOperator op, TIntermTyped*& lhsNode, TIntermTyped*& rhsNode) +{ + // some source languages don't do this + switch (source) { + case EShSourceHlsl: + break; + case EShSourceGlsl: + default: + return; + } + + // some operations don't do this + // 'break' will mean attempt bidirectional conversion + switch (op) { + case EOpMulAssign: + case EOpAssign: + case EOpAddAssign: + case EOpSubAssign: + case EOpDivAssign: + case EOpAndAssign: + case EOpInclusiveOrAssign: + case EOpExclusiveOrAssign: + case EOpRightShiftAssign: + case EOpLeftShiftAssign: + // switch to unidirectional conversion (the lhs can't change) + rhsNode = addUniShapeConversion(op, lhsNode->getType(), rhsNode); + return; + + case EOpAdd: + case EOpSub: + case EOpMul: + case EOpDiv: + // want to support vector * scalar native ops in AST and lower, not smear, similarly for + // matrix * vector, etc. + if (lhsNode->getVectorSize() == 1 || rhsNode->getVectorSize() == 1) + return; + break; + + case EOpRightShift: + case EOpLeftShift: + // can natively support the right operand being a scalar and the left a vector, + // but not the reverse + if (rhsNode->getVectorSize() == 1) + return; + break; + + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + + case EOpEqual: + case EOpNotEqual: + + case EOpLogicalAnd: + case EOpLogicalOr: + case EOpLogicalXor: + + case EOpAnd: + case EOpInclusiveOr: + case EOpExclusiveOr: + + case EOpMix: + break; + + default: + return; + } + + // Do bidirectional conversions + if (lhsNode->getType().isScalarOrVec1() || rhsNode->getType().isScalarOrVec1()) { + if (lhsNode->getType().isScalarOrVec1()) + lhsNode = addShapeConversion(rhsNode->getType(), lhsNode); + else + rhsNode = addShapeConversion(lhsNode->getType(), rhsNode); + } + lhsNode = addShapeConversion(rhsNode->getType(), lhsNode); + rhsNode = addShapeConversion(lhsNode->getType(), rhsNode); +} + +// Convert the node's shape of type for the given type, as allowed by the +// operation involved: 'op'. +// +// Generally, the AST represents allowed GLSL shapes, so this isn't needed +// for GLSL. Bad shapes are caught in conversion or promotion. +// +// Return 'node' if no conversion was done. Promotion handles final shape +// checking. +// +TIntermTyped* TIntermediate::addShapeConversion(const TType& type, TIntermTyped* node) +{ + // no conversion needed + if (node->getType() == type) + return node; + + // structures and arrays don't change shape, either to or from + if (node->getType().isStruct() || node->getType().isArray() || + type.isStruct() || type.isArray()) + return node; + + // The new node that handles the conversion + TOperator constructorOp = mapTypeToConstructorOp(type); + + // HLSL has custom semantics for scalar->mat shape conversions. + if (source == EShSourceHlsl) { + if (node->getType().isScalarOrVec1() && type.isMatrix()) { + + // HLSL semantics: the scalar (or vec1) is replicated to every component of the matrix. Left to its + // own devices, the constructor from a scalar would populate the diagonal. This forces replication + // to every matrix element. + + // Note that if the node is complex (e.g, a function call), we don't want to duplicate it here + // repeatedly, so we copy it to a temp, then use the temp. + const int matSize = type.getMatrixRows() * type.getMatrixCols(); + TIntermAggregate* rhsAggregate = new TIntermAggregate(); + + const bool isSimple = (node->getAsSymbolNode() != nullptr) || (node->getAsConstantUnion() != nullptr); + + if (!isSimple) { + assert(0); // TODO: use node replicator service when available. + } + + for (int x=0; xgetSequence().push_back(node); + + return setAggregateOperator(rhsAggregate, constructorOp, type, node->getLoc()); + } + } + + // scalar -> vector or vec1 -> vector or + // vector -> scalar or + // bigger vector -> smaller vector + if ((node->getType().isScalarOrVec1() && type.isVector()) || + (node->getType().isVector() && type.isScalar()) || + (node->isVector() && type.isVector() && node->getVectorSize() > type.getVectorSize())) + return setAggregateOperator(makeAggregate(node), constructorOp, type, node->getLoc()); + + return node; +} + +bool TIntermediate::isIntegralPromotion(TBasicType from, TBasicType to) const +{ + // integral promotions + if (to == EbtInt) { + switch(from) { + case EbtInt8: + case EbtInt16: + case EbtUint8: + case EbtUint16: + return true; default: - return 0; + break; + } + } + return false; +} + +bool TIntermediate::isFPPromotion(TBasicType from, TBasicType to) const +{ + // floating-point promotions + if (to == EbtDouble) { + switch(from) { + case EbtFloat16: + case EbtFloat: + return true; + default: + break; + } + } + return false; +} + +bool TIntermediate::isIntegralConversion(TBasicType from, TBasicType to) const +{ + switch (from) { + case EbtInt8: + switch (to) { + case EbtUint8: + case EbtInt16: + case EbtUint16: + case EbtUint: + case EbtInt64: + case EbtUint64: + return true; + default: + break; } break; - case EbtFloat: - switch (node->getBasicType()) { - case EbtInt: newOp = EOpConvIntToFloat; break; - case EbtUint: newOp = EOpConvUintToFloat; break; - case EbtBool: newOp = EOpConvBoolToFloat; break; - case EbtDouble: newOp = EOpConvDoubleToFloat; break; - case EbtInt64: newOp = EOpConvInt64ToFloat; break; - case EbtUint64: newOp = EOpConvUint64ToFloat; break; + case EbtUint8: + switch (to) { + case EbtInt16: + case EbtUint16: + case EbtUint: + case EbtInt64: + case EbtUint64: + return true; default: - return 0; + break; } break; - case EbtBool: - switch (node->getBasicType()) { - case EbtInt: newOp = EOpConvIntToBool; break; - case EbtUint: newOp = EOpConvUintToBool; break; - case EbtFloat: newOp = EOpConvFloatToBool; break; - case EbtDouble: newOp = EOpConvDoubleToBool; break; - case EbtInt64: newOp = EOpConvInt64ToBool; break; - case EbtUint64: newOp = EOpConvUint64ToBool; break; + case EbtInt16: + switch(to) { + case EbtUint16: + case EbtUint: + case EbtInt64: + case EbtUint64: + return true; default: - return 0; + break; + } + break; + case EbtUint16: + switch(to) { + case EbtUint: + case EbtInt64: + case EbtUint64: + return true; + default: + break; } break; case EbtInt: - switch (node->getBasicType()) { - case EbtUint: newOp = EOpConvUintToInt; break; - case EbtBool: newOp = EOpConvBoolToInt; break; - case EbtFloat: newOp = EOpConvFloatToInt; break; - case EbtDouble: newOp = EOpConvDoubleToInt; break; - case EbtInt64: newOp = EOpConvInt64ToInt; break; - case EbtUint64: newOp = EOpConvUint64ToInt; break; + switch(to) { + case EbtUint: + return version >= 400 || (source == EShSourceHlsl); + case EbtInt64: + case EbtUint64: + return true; default: - return 0; + break; } break; case EbtUint: - switch (node->getBasicType()) { - case EbtInt: newOp = EOpConvIntToUint; break; - case EbtBool: newOp = EOpConvBoolToUint; break; - case EbtFloat: newOp = EOpConvFloatToUint; break; - case EbtDouble: newOp = EOpConvDoubleToUint; break; - case EbtInt64: newOp = EOpConvInt64ToUint; break; - case EbtUint64: newOp = EOpConvUint64ToUint; break; + switch(to) { + case EbtInt64: + case EbtUint64: + return true; default: - return 0; + break; } break; case EbtInt64: - switch (node->getBasicType()) { - 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 EbtUint64: newOp = EOpConvUint64ToInt64; break; - default: - return 0; - } - break; - case EbtUint64: - switch (node->getBasicType()) { - 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 EbtInt64: newOp = EOpConvInt64ToUint64; break; - default: - return 0; + if (to == EbtUint64) { + return true; } break; default: - return 0; + break; } + return false; +} - TType newType(promoteTo, EvqTemporary, node->getVectorSize(), node->getMatrixCols(), node->getMatrixRows()); - newNode = new TIntermUnary(newOp, newType); - newNode->setLoc(node->getLoc()); - newNode->setOperand(node); +bool TIntermediate::isFPConversion(TBasicType from, TBasicType to) const +{ + if (to == EbtFloat && from == EbtFloat16) { + return true; + } else { + return false; + } +} - // TODO: it seems that some unary folding operations should occur here, but are not +bool TIntermediate::isFPIntegralConversion(TBasicType from, TBasicType to) const +{ + switch (from) { + case EbtInt8: + case EbtUint8: + case EbtInt16: + case EbtUint16: + switch (to) { + case EbtFloat16: + case EbtFloat: + case EbtDouble: + return true; + default: + break; + } + break; + case EbtInt: + case EbtUint: + switch(to) { + case EbtFloat: + case EbtDouble: + return true; + default: + break; + } + break; + case EbtInt64: + case EbtUint64: + if (to == EbtDouble) { + return true; + } + break; - // Propagate specialization-constant-ness, if allowed - if (node->getType().getQualifier().isSpecConstant() && isSpecializationOperation(*newNode)) - newNode->getWritableType().getQualifier().makeSpecConstant(); - - return newNode; + default: + break; + } + return false; } // // See if the 'from' type is allowed to be implicitly converted to the // 'to' type. This is not about vector/array/struct, only about basic type. // -bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to) const +bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperator op) const { if (profile == EEsProfile || version == 110) return false; - switch (to) { - case EbtDouble: - switch (from) { - case EbtInt: - case EbtUint: - case EbtInt64: - case EbtUint64: - case EbtFloat: + if (from == to) + return true; + + // TODO: Move more policies into language-specific handlers. + // Some languages allow more general (or potentially, more specific) conversions under some conditions. + if (source == EShSourceHlsl) { + const bool fromConvertable = (from == EbtFloat || from == EbtDouble || from == EbtInt || from == EbtUint || from == EbtBool); + const bool toConvertable = (to == EbtFloat || to == EbtDouble || to == EbtInt || to == EbtUint || to == EbtBool); + + if (fromConvertable && toConvertable) { + switch (op) { + case EOpAndAssign: // assignments can perform arbitrary conversions + case EOpInclusiveOrAssign: // ... + case EOpExclusiveOrAssign: // ... + case EOpAssign: // ... + case EOpAddAssign: // ... + case EOpSubAssign: // ... + case EOpMulAssign: // ... + case EOpVectorTimesScalarAssign: // ... + case EOpMatrixTimesScalarAssign: // ... + case EOpDivAssign: // ... + case EOpModAssign: // ... + case EOpReturn: // function returns can also perform arbitrary conversions + case EOpFunctionCall: // conversion of a calling parameter + case EOpLogicalNot: + case EOpLogicalAnd: + case EOpLogicalOr: + case EOpLogicalXor: + case EOpConstructStruct: + return true; + default: + break; + } + } + } + + bool explicitTypesEnabled = extensionRequested(E_GL_KHX_shader_explicit_arithmetic_types) || + extensionRequested(E_GL_KHX_shader_explicit_arithmetic_types_int8) || + extensionRequested(E_GL_KHX_shader_explicit_arithmetic_types_int16) || + extensionRequested(E_GL_KHX_shader_explicit_arithmetic_types_int32) || + extensionRequested(E_GL_KHX_shader_explicit_arithmetic_types_int64) || + extensionRequested(E_GL_KHX_shader_explicit_arithmetic_types_float16) || + extensionRequested(E_GL_KHX_shader_explicit_arithmetic_types_float32) || + extensionRequested(E_GL_KHX_shader_explicit_arithmetic_types_float64); + + if (explicitTypesEnabled) { + // integral promotions + if (isIntegralPromotion(from, to)) { + return true; + } + + // floating-point promotions + if (isFPPromotion(from, to)) { + return true; + } + + // integral conversions + if (isIntegralConversion(from, to)) { + return true; + } + + // floating-point conversions + if (isFPConversion(from, to)) { + return true; + } + + // floating-integral conversions + if (isFPIntegralConversion(from, to)) { + return true; + } + + // hlsl supported conversions + if (source == EShSourceHlsl) { + if (from == EbtBool && (to == EbtInt || to == EbtUint || to == EbtFloat)) + return true; + } + } else { + switch (to) { case EbtDouble: - return true; - default: - return false; - } - case EbtFloat: - switch (from) { - case EbtInt: - case EbtUint: + switch (from) { + case EbtInt: + case EbtUint: + case EbtInt64: + case EbtUint64: +#ifdef AMD_EXTENSIONS + case EbtInt16: + case EbtUint16: +#endif + case EbtFloat: + case EbtDouble: +#ifdef AMD_EXTENSIONS + case EbtFloat16: +#endif + return true; + default: + return false; + } case EbtFloat: - return true; - default: - return false; - } - case EbtUint: - switch (from) { - case EbtInt: - return version >= 400; + switch (from) { + case EbtInt: + case EbtUint: +#ifdef AMD_EXTENSIONS + case EbtInt16: + case EbtUint16: +#endif + case EbtFloat: +#ifdef AMD_EXTENSIONS + case EbtFloat16: +#endif + return true; + case EbtBool: + return (source == EShSourceHlsl); + default: + return false; + } case EbtUint: - return true; - default: - return false; - } - case EbtInt: - switch (from) { + switch (from) { + case EbtInt: + return version >= 400 || (source == EShSourceHlsl); + case EbtUint: +#ifdef AMD_EXTENSIONS + case EbtInt16: + case EbtUint16: +#endif + return true; + case EbtBool: + return (source == EShSourceHlsl); + default: + return false; + } case EbtInt: - return true; - default: - return false; - } - case EbtUint64: - switch (from) { - case EbtInt: - case EbtUint: - case EbtInt64: + switch (from) { + case EbtInt: +#ifdef AMD_EXTENSIONS + case EbtInt16: +#endif + return true; + case EbtBool: + return (source == EShSourceHlsl); + default: + return false; + } case EbtUint64: - return true; - default: - return false; - } - case EbtInt64: - switch (from) { - case EbtInt: + switch (from) { + case EbtInt: + case EbtUint: + case EbtInt64: + case EbtUint64: +#ifdef AMD_EXTENSIONS + case EbtInt16: + case EbtUint16: +#endif + return true; + default: + return false; + } case EbtInt64: - return true; + switch (from) { + case EbtInt: + case EbtInt64: +#ifdef AMD_EXTENSIONS + case EbtInt16: +#endif + return true; + default: + return false; + } +#ifdef AMD_EXTENSIONS + case EbtFloat16: + switch (from) { + case EbtInt16: + case EbtUint16: + case EbtFloat16: + return true; + default: + return false; + } + case EbtUint16: + switch (from) { + case EbtInt16: + case EbtUint16: + return true; + default: + return false; + } +#endif default: return false; } + } + + return false; +} + +static bool canSignedIntTypeRepresentAllUnsignedValues(TBasicType sintType, TBasicType uintType) { + switch(sintType) { + case EbtInt8: + switch(uintType) { + case EbtUint8: + case EbtUint16: + case EbtUint: + case EbtUint64: + return false; + default: + assert(false); + return false; + } + break; + case EbtInt16: + switch(uintType) { + case EbtUint8: + return true; + case EbtUint16: + case EbtUint: + case EbtUint64: + return false; + default: + assert(false); + return false; + } + break; + case EbtInt: + switch(uintType) { + case EbtUint8: + case EbtUint16: + return true; + case EbtUint: + return false; + default: + assert(false); + return false; + } + break; + case EbtInt64: + switch(uintType) { + case EbtUint8: + case EbtUint16: + case EbtUint: + return true; + case EbtUint64: + return false; + default: + assert(false); + return false; + } + break; default: + assert(false); return false; } } + +static TBasicType getCorrespondingUnsignedType(TBasicType type) { + switch(type) { + case EbtInt8: + return EbtUint8; + case EbtInt16: + return EbtUint16; + case EbtInt: + return EbtUint; + case EbtInt64: + return EbtUint64; + default: + assert(false); + return EbtNumTypes; + } +} + +// Implements the following rules +// - If either operand has type float64_t or derived from float64_t, +// the other shall be converted to float64_t or derived type. +// - Otherwise, if either operand has type float32_t or derived from +// float32_t, the other shall be converted to float32_t or derived type. +// - Otherwise, if either operand has type float16_t or derived from +// float16_t, the other shall be converted to float16_t or derived type. +// - Otherwise, if both operands have integer types the following rules +// shall be applied to the operands: +// - If both operands have the same type, no further conversion +// is needed. +// - Otherwise, if both operands have signed integer types or both +// have unsigned integer types, the operand with the type of lesser +// integer conversion rank shall be converted to the type of the +// operand with greater rank. +// - Otherwise, if the operand that has unsigned integer type has rank +// greater than or equal to the rank of the type of the other +// operand, the operand with signed integer type shall be converted +// to the type of the operand with unsigned integer type. +// - Otherwise, if the type of the operand with signed integer type can +// represent all of the values of the type of the operand with +// unsigned integer type, the operand with unsigned integer type +// shall be converted to the type of the operand with signed +// integer type. +// - Otherwise, both operands shall be converted to the unsigned +// integer type corresponding to the type of the operand with signed +// integer type. + +std::tuple TIntermediate::getConversionDestinatonType(TBasicType type0, TBasicType type1, TOperator op) const +{ + TBasicType res0 = EbtNumTypes; + TBasicType res1 = EbtNumTypes; + + if (profile == EEsProfile || version == 110) + return std::make_tuple(res0, res1);; + + if (source == EShSourceHlsl) { + if (canImplicitlyPromote(type1, type0, op)) { + res0 = type0; + res1 = type0; + } else if (canImplicitlyPromote(type0, type1, op)) { + res0 = type1; + res1 = type1; + } + return std::make_tuple(res0, res1); + } + + if ((type0 == EbtDouble && canImplicitlyPromote(type1, EbtDouble, op)) || + (type1 == EbtDouble && canImplicitlyPromote(type0, EbtDouble, op)) ) { + res0 = EbtDouble; + res1 = EbtDouble; + } else if ((type0 == EbtFloat && canImplicitlyPromote(type1, EbtFloat, op)) || + (type1 == EbtFloat && canImplicitlyPromote(type0, EbtFloat, op)) ) { + res0 = EbtFloat; + res1 = EbtFloat; + } else if ((type0 == EbtFloat16 && canImplicitlyPromote(type1, EbtFloat16, op)) || + (type1 == EbtFloat16 && canImplicitlyPromote(type0, EbtFloat16, op)) ) { + res0 = EbtFloat16; + res1 = EbtFloat16; + } else if (isTypeInt(type0) && isTypeInt(type1) && + (canImplicitlyPromote(type0, type1, op) || canImplicitlyPromote(type1, type0, op))) { + if ((isTypeSignedInt(type0) && isTypeSignedInt(type1)) || + (isTypeUnsignedInt(type0) && isTypeUnsignedInt(type1))) { + if (getTypeRank(type0) < getTypeRank(type1)) { + res0 = type1; + res1 = type1; + } else { + res0 = type0; + res1 = type0; + } + } else if (isTypeUnsignedInt(type0) && (getTypeRank(type0) > getTypeRank(type1))) { + res0 = type0; + res1 = type0; + } else if (isTypeUnsignedInt(type1) && (getTypeRank(type1) > getTypeRank(type0))) { + res0 = type1; + res1 = type1; + } else if (isTypeSignedInt(type0)) { + if (canSignedIntTypeRepresentAllUnsignedValues(type0, type1)) { + res0 = type0; + res1 = type0; + } else { + res0 = getCorrespondingUnsignedType(type0); + res1 = getCorrespondingUnsignedType(type0); + } + } else if (isTypeSignedInt(type1)) { + if (canSignedIntTypeRepresentAllUnsignedValues(type1, type0)) { + res0 = type1; + res1 = type1; + } else { + res0 = getCorrespondingUnsignedType(type1); + res1 = getCorrespondingUnsignedType(type1); + } + } + } + + return std::make_tuple(res0, res1); +} + +// +// Given a type, find what operation would fully construct it. +// +TOperator TIntermediate::mapTypeToConstructorOp(const TType& type) const +{ + TOperator op = EOpNull; + + if (type.getQualifier().nonUniform) + return EOpConstructNonuniform; + + switch (type.getBasicType()) { + case EbtStruct: + op = EOpConstructStruct; + break; + case EbtSampler: + if (type.getSampler().combined) + op = EOpConstructTextureSampler; + break; + case EbtFloat: + if (type.isMatrix()) { + switch (type.getMatrixCols()) { + case 2: + switch (type.getMatrixRows()) { + case 2: op = EOpConstructMat2x2; break; + case 3: op = EOpConstructMat2x3; break; + case 4: op = EOpConstructMat2x4; break; + default: break; // some compilers want this + } + break; + case 3: + switch (type.getMatrixRows()) { + case 2: op = EOpConstructMat3x2; break; + case 3: op = EOpConstructMat3x3; break; + case 4: op = EOpConstructMat3x4; break; + default: break; // some compilers want this + } + break; + case 4: + switch (type.getMatrixRows()) { + case 2: op = EOpConstructMat4x2; break; + case 3: op = EOpConstructMat4x3; break; + case 4: op = EOpConstructMat4x4; break; + default: break; // some compilers want this + } + break; + default: break; // some compilers want this + } + } else { + switch(type.getVectorSize()) { + case 1: op = EOpConstructFloat; break; + case 2: op = EOpConstructVec2; break; + case 3: op = EOpConstructVec3; break; + case 4: op = EOpConstructVec4; break; + default: break; // some compilers want this + } + } + break; + case EbtDouble: + if (type.getMatrixCols()) { + switch (type.getMatrixCols()) { + case 2: + switch (type.getMatrixRows()) { + case 2: op = EOpConstructDMat2x2; break; + case 3: op = EOpConstructDMat2x3; break; + case 4: op = EOpConstructDMat2x4; break; + default: break; // some compilers want this + } + break; + case 3: + switch (type.getMatrixRows()) { + case 2: op = EOpConstructDMat3x2; break; + case 3: op = EOpConstructDMat3x3; break; + case 4: op = EOpConstructDMat3x4; break; + default: break; // some compilers want this + } + break; + case 4: + switch (type.getMatrixRows()) { + case 2: op = EOpConstructDMat4x2; break; + case 3: op = EOpConstructDMat4x3; break; + case 4: op = EOpConstructDMat4x4; break; + default: break; // some compilers want this + } + break; + } + } else { + switch(type.getVectorSize()) { + case 1: op = EOpConstructDouble; break; + case 2: op = EOpConstructDVec2; break; + case 3: op = EOpConstructDVec3; break; + case 4: op = EOpConstructDVec4; break; + default: break; // some compilers want this + } + } + break; + case EbtFloat16: + if (type.getMatrixCols()) { + switch (type.getMatrixCols()) { + case 2: + switch (type.getMatrixRows()) { + case 2: op = EOpConstructF16Mat2x2; break; + case 3: op = EOpConstructF16Mat2x3; break; + case 4: op = EOpConstructF16Mat2x4; break; + default: break; // some compilers want this + } + break; + case 3: + switch (type.getMatrixRows()) { + case 2: op = EOpConstructF16Mat3x2; break; + case 3: op = EOpConstructF16Mat3x3; break; + case 4: op = EOpConstructF16Mat3x4; break; + default: break; // some compilers want this + } + break; + case 4: + switch (type.getMatrixRows()) { + case 2: op = EOpConstructF16Mat4x2; break; + case 3: op = EOpConstructF16Mat4x3; break; + case 4: op = EOpConstructF16Mat4x4; break; + default: break; // some compilers want this + } + break; + } + } + else { + switch (type.getVectorSize()) { + case 1: op = EOpConstructFloat16; break; + case 2: op = EOpConstructF16Vec2; break; + case 3: op = EOpConstructF16Vec3; break; + case 4: op = EOpConstructF16Vec4; break; + default: break; // some compilers want this + } + } + break; + case EbtInt8: + switch(type.getVectorSize()) { + case 1: op = EOpConstructInt8; break; + case 2: op = EOpConstructI8Vec2; break; + case 3: op = EOpConstructI8Vec3; break; + case 4: op = EOpConstructI8Vec4; break; + default: break; // some compilers want this + } + break; + case EbtUint8: + switch(type.getVectorSize()) { + case 1: op = EOpConstructUint8; break; + case 2: op = EOpConstructU8Vec2; break; + case 3: op = EOpConstructU8Vec3; break; + case 4: op = EOpConstructU8Vec4; break; + default: break; // some compilers want this + } + break; + case EbtInt16: + switch(type.getVectorSize()) { + case 1: op = EOpConstructInt16; break; + case 2: op = EOpConstructI16Vec2; break; + case 3: op = EOpConstructI16Vec3; break; + case 4: op = EOpConstructI16Vec4; break; + default: break; // some compilers want this + } + break; + case EbtUint16: + switch(type.getVectorSize()) { + case 1: op = EOpConstructUint16; break; + case 2: op = EOpConstructU16Vec2; break; + case 3: op = EOpConstructU16Vec3; break; + case 4: op = EOpConstructU16Vec4; break; + default: break; // some compilers want this + } + break; + case EbtInt: + if (type.getMatrixCols()) { + switch (type.getMatrixCols()) { + case 2: + switch (type.getMatrixRows()) { + case 2: op = EOpConstructIMat2x2; break; + case 3: op = EOpConstructIMat2x3; break; + case 4: op = EOpConstructIMat2x4; break; + default: break; // some compilers want this + } + break; + case 3: + switch (type.getMatrixRows()) { + case 2: op = EOpConstructIMat3x2; break; + case 3: op = EOpConstructIMat3x3; break; + case 4: op = EOpConstructIMat3x4; break; + default: break; // some compilers want this + } + break; + case 4: + switch (type.getMatrixRows()) { + case 2: op = EOpConstructIMat4x2; break; + case 3: op = EOpConstructIMat4x3; break; + case 4: op = EOpConstructIMat4x4; break; + default: break; // some compilers want this + } + break; + } + } else { + switch(type.getVectorSize()) { + case 1: op = EOpConstructInt; break; + case 2: op = EOpConstructIVec2; break; + case 3: op = EOpConstructIVec3; break; + case 4: op = EOpConstructIVec4; break; + default: break; // some compilers want this + } + } + break; + case EbtUint: + if (type.getMatrixCols()) { + switch (type.getMatrixCols()) { + case 2: + switch (type.getMatrixRows()) { + case 2: op = EOpConstructUMat2x2; break; + case 3: op = EOpConstructUMat2x3; break; + case 4: op = EOpConstructUMat2x4; break; + default: break; // some compilers want this + } + break; + case 3: + switch (type.getMatrixRows()) { + case 2: op = EOpConstructUMat3x2; break; + case 3: op = EOpConstructUMat3x3; break; + case 4: op = EOpConstructUMat3x4; break; + default: break; // some compilers want this + } + break; + case 4: + switch (type.getMatrixRows()) { + case 2: op = EOpConstructUMat4x2; break; + case 3: op = EOpConstructUMat4x3; break; + case 4: op = EOpConstructUMat4x4; break; + default: break; // some compilers want this + } + break; + } + } else { + switch(type.getVectorSize()) { + case 1: op = EOpConstructUint; break; + case 2: op = EOpConstructUVec2; break; + case 3: op = EOpConstructUVec3; break; + case 4: op = EOpConstructUVec4; break; + default: break; // some compilers want this + } + } + break; + case EbtInt64: + switch(type.getVectorSize()) { + case 1: op = EOpConstructInt64; break; + case 2: op = EOpConstructI64Vec2; break; + case 3: op = EOpConstructI64Vec3; break; + case 4: op = EOpConstructI64Vec4; break; + default: break; // some compilers want this + } + break; + case EbtUint64: + switch(type.getVectorSize()) { + case 1: op = EOpConstructUint64; break; + case 2: op = EOpConstructU64Vec2; break; + case 3: op = EOpConstructU64Vec3; break; + case 4: op = EOpConstructU64Vec4; break; + default: break; // some compilers want this + } + break; + case EbtBool: + if (type.getMatrixCols()) { + switch (type.getMatrixCols()) { + case 2: + switch (type.getMatrixRows()) { + case 2: op = EOpConstructBMat2x2; break; + case 3: op = EOpConstructBMat2x3; break; + case 4: op = EOpConstructBMat2x4; break; + default: break; // some compilers want this + } + break; + case 3: + switch (type.getMatrixRows()) { + case 2: op = EOpConstructBMat3x2; break; + case 3: op = EOpConstructBMat3x3; break; + case 4: op = EOpConstructBMat3x4; break; + default: break; // some compilers want this + } + break; + case 4: + switch (type.getMatrixRows()) { + case 2: op = EOpConstructBMat4x2; break; + case 3: op = EOpConstructBMat4x3; break; + case 4: op = EOpConstructBMat4x4; break; + default: break; // some compilers want this + } + break; + } + } else { + switch(type.getVectorSize()) { + case 1: op = EOpConstructBool; break; + case 2: op = EOpConstructBVec2; break; + case 3: op = EOpConstructBVec3; break; + case 4: op = EOpConstructBVec4; break; + default: break; // some compilers want this + } + } + break; + default: + break; + } + + return op; +} + // // Safe way to combine two nodes into an aggregate. Works with null pointers, // a node that's not a aggregate yet, etc. // -// Returns the resulting aggregate, unless 0 was passed in for +// Returns the resulting aggregate, unless nullptr was passed in for // both existing nodes. // TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right) { - if (left == 0 && right == 0) - return 0; + if (left == nullptr && right == nullptr) + return nullptr; - TIntermAggregate* aggNode = 0; - if (left) + TIntermAggregate* aggNode = nullptr; + if (left != nullptr) aggNode = left->getAsAggregate(); - if (! aggNode || aggNode->getOp() != EOpNull) { + if (aggNode == nullptr || aggNode->getOp() != EOpNull) { aggNode = new TIntermAggregate; - if (left) + if (left != nullptr) aggNode->getSequence().push_back(left); } - if (right) + if (right != nullptr) aggNode->getSequence().push_back(right); return aggNode; @@ -790,12 +2099,12 @@ TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* r // // Turn an existing node into an aggregate. // -// Returns an aggregate, unless 0 was passed in for the existing node. +// Returns an aggregate, unless nullptr was passed in for the existing node. // TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node) { - if (node == 0) - return 0; + if (node == nullptr) + return nullptr; TIntermAggregate* aggNode = new TIntermAggregate; aggNode->getSequence().push_back(node); @@ -806,8 +2115,8 @@ TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node) TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc& loc) { - if (node == 0) - return 0; + if (node == nullptr) + return nullptr; TIntermAggregate* aggNode = new TIntermAggregate; aggNode->getSequence().push_back(node); @@ -816,6 +2125,17 @@ TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceL return aggNode; } +// +// Make an aggregate with an empty sequence. +// +TIntermAggregate* TIntermediate::makeAggregate(const TSourceLoc& loc) +{ + TIntermAggregate* aggNode = new TIntermAggregate; + aggNode->setLoc(loc); + + return aggNode; +} + // // For "if" test nodes. There are three children; a condition, // a true path, and a false path. The two paths are in the @@ -823,7 +2143,7 @@ TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceL // // Returns the selection node created. // -TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& loc) +TIntermSelection* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& loc) { // // Don't prune the false path for compile-time constants; it's needed @@ -836,13 +2156,12 @@ TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nod return node; } - TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc& loc) { // However, the lowest precedence operators of the sequence operator ( , ) and the assignment operators // ... are not included in the operators that can create a constant expression. // - //if (left->getType().getQualifier().storage == EvqConst && + // if (left->getType().getQualifier().storage == EvqConst && // right->getType().getQualifier().storage == EvqConst) { // return right; @@ -867,34 +2186,70 @@ TIntermTyped* TIntermediate::addMethod(TIntermTyped* object, const TType& type, // // For "?:" test nodes. There are three children; a condition, // a true path, and a false path. The two paths are specified -// as separate parameters. +// as separate parameters. For vector 'cond', the true and false +// are not paths, but vectors to mix. // -// Returns the selection node created, or 0 if one could not be. +// Specialization constant operations include +// - The ternary operator ( ? : ) // -TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& loc) +// Returns the selection node created, or nullptr if one could not be. +// +TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, + const TSourceLoc& loc) { + // If it's void, go to the if-then-else selection() + if (trueBlock->getBasicType() == EbtVoid && falseBlock->getBasicType() == EbtVoid) { + TIntermNodePair pair = { trueBlock, falseBlock }; + TIntermSelection* selection = addSelection(cond, pair, loc); + if (getSource() == EShSourceHlsl) + selection->setNoShortCircuit(); + + return selection; + } + // // Get compatible types. // - TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock); - if (child) - falseBlock = child; - else { - child = addConversion(EOpSequence, falseBlock->getType(), trueBlock); - if (child) - trueBlock = child; - else - return 0; + auto children = addConversion(EOpSequence, trueBlock, falseBlock); + trueBlock = std::get<0>(children); + falseBlock = std::get<1>(children); + + if (trueBlock == nullptr || falseBlock == nullptr) + return nullptr; + + // Handle a vector condition as a mix + if (!cond->getType().isScalarOrVec1()) { + TType targetVectorType(trueBlock->getType().getBasicType(), EvqTemporary, + cond->getType().getVectorSize()); + // smear true/false operands as needed + trueBlock = addUniShapeConversion(EOpMix, targetVectorType, trueBlock); + falseBlock = addUniShapeConversion(EOpMix, targetVectorType, falseBlock); + + // After conversion, types have to match. + if (falseBlock->getType() != trueBlock->getType()) + return nullptr; + + // make the mix operation + TIntermAggregate* mix = makeAggregate(loc); + mix = growAggregate(mix, falseBlock); + mix = growAggregate(mix, trueBlock); + mix = growAggregate(mix, cond); + mix->setType(targetVectorType); + mix->setOp(EOpMix); + + return mix; } + // Now have a scalar condition... + + // Convert true and false expressions to matching types + addBiShapeConversion(EOpMix, trueBlock, falseBlock); + // After conversion, types have to match. if (falseBlock->getType() != trueBlock->getType()) - return 0; - - // - // See if all the operands are constant, then fold it otherwise not. - // + return nullptr; + // Eliminate the selection when the condition is a scalar and all operands are constant. if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) { if (cond->getAsConstantUnion()->getConstArray()[0].getBConst()) return trueBlock; @@ -906,10 +2261,19 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* true // Make a selection node. // TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType()); - node->getQualifier().makeTemporary(); node->setLoc(loc); node->getQualifier().precision = std::max(trueBlock->getQualifier().precision, falseBlock->getQualifier().precision); + if ((cond->getQualifier().isConstant() && specConstantPropagates(*trueBlock, *falseBlock)) || + (cond->getQualifier().isSpecConstant() && trueBlock->getQualifier().isConstant() && + falseBlock->getQualifier().isConstant())) + node->getQualifier().makeSpecConstant(); + else + node->getQualifier().makeTemporary(); + + if (getSource() == EShSourceHlsl) + node->setNoShortCircuit(); + return node; } @@ -929,6 +2293,37 @@ TIntermConstantUnion* TIntermediate::addConstantUnion(const TConstUnionArray& un return node; } +TIntermConstantUnion* TIntermediate::addConstantUnion(signed char i8, const TSourceLoc& loc, bool literal) const +{ + TConstUnionArray unionArray(1); + unionArray[0].setI8Const(i8); + + return addConstantUnion(unionArray, TType(EbtInt8, EvqConst), loc, literal); +} + +TIntermConstantUnion* TIntermediate::addConstantUnion(unsigned char u8, const TSourceLoc& loc, bool literal) const +{ + TConstUnionArray unionArray(1); + unionArray[0].setUConst(u8); + + return addConstantUnion(unionArray, TType(EbtUint8, EvqConst), loc, literal); +} + +TIntermConstantUnion* TIntermediate::addConstantUnion(signed short i16, const TSourceLoc& loc, bool literal) const +{ + TConstUnionArray unionArray(1); + unionArray[0].setI16Const(i16); + + return addConstantUnion(unionArray, TType(EbtInt16, EvqConst), loc, literal); +} + +TIntermConstantUnion* TIntermediate::addConstantUnion(unsigned short u16, const TSourceLoc& loc, bool literal) const +{ + TConstUnionArray unionArray(1); + unionArray[0].setU16Const(u16); + + return addConstantUnion(unionArray, TType(EbtUint16, EvqConst), loc, literal); +} TIntermConstantUnion* TIntermediate::addConstantUnion(int i, const TSourceLoc& loc, bool literal) const { @@ -972,7 +2367,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); + assert(baseType == EbtFloat || baseType == EbtDouble || baseType == EbtFloat16); TConstUnionArray unionArray(1); unionArray[0].setDConst(d); @@ -980,18 +2375,43 @@ TIntermConstantUnion* TIntermediate::addConstantUnion(double d, TBasicType baseT return addConstantUnion(unionArray, TType(baseType, EvqConst), loc, literal); } -TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc& loc) +TIntermConstantUnion* TIntermediate::addConstantUnion(const TString* s, const TSourceLoc& loc, bool literal) const +{ + TConstUnionArray unionArray(1); + unionArray[0].setSConst(s); + + return addConstantUnion(unionArray, TType(EbtString, EvqConst), loc, literal); +} + +// Put vector swizzle selectors onto the given sequence +void TIntermediate::pushSelector(TIntermSequence& sequence, const TVectorSelector& selector, const TSourceLoc& loc) +{ + TIntermConstantUnion* constIntNode = addConstantUnion(selector, loc); + sequence.push_back(constIntNode); +} + +// Put matrix swizzle selectors onto the given sequence +void TIntermediate::pushSelector(TIntermSequence& sequence, const TMatrixSelector& selector, const TSourceLoc& loc) +{ + TIntermConstantUnion* constIntNode = addConstantUnion(selector.coord1, loc); + sequence.push_back(constIntNode); + constIntNode = addConstantUnion(selector.coord2, loc); + sequence.push_back(constIntNode); +} + +// Make an aggregate node that has a sequence of all selectors. +template TIntermTyped* TIntermediate::addSwizzle(TSwizzleSelectors& selector, const TSourceLoc& loc); +template TIntermTyped* TIntermediate::addSwizzle(TSwizzleSelectors& selector, const TSourceLoc& loc); +template +TIntermTyped* TIntermediate::addSwizzle(TSwizzleSelectors& selector, const TSourceLoc& loc) { TIntermAggregate* node = new TIntermAggregate(EOpSequence); node->setLoc(loc); - TIntermConstantUnion* constIntNode; TIntermSequence &sequenceVector = node->getSequence(); - for (int i = 0; i < fields.num; i++) { - constIntNode = addConstantUnion(fields.offsets[i], loc); - sequenceVector.push_back(constIntNode); - } + for (int i = 0; i < selector.size(); i++) + pushSelector(sequenceVector, selector[i], loc); return node; } @@ -1013,10 +2433,10 @@ const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool if (binary == nullptr) return node; TOperator op = binary->getOp(); - if (op != EOpIndexDirect && op != EOpIndexIndirect && op != EOpIndexDirectStruct && op != EOpVectorSwizzle) + if (op != EOpIndexDirect && op != EOpIndexIndirect && op != EOpIndexDirectStruct && op != EOpVectorSwizzle && op != EOpMatrixSwizzle) return nullptr; if (! swizzleOkay) { - if (op == EOpVectorSwizzle) + if (op == EOpVectorSwizzle || op == EOpMatrixSwizzle) return nullptr; if ((op == EOpIndexDirect || op == EOpIndexIndirect) && (binary->getLeft()->getType().isVector() || binary->getLeft()->getType().isScalar()) && @@ -1030,7 +2450,8 @@ const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool // // Create while and do-while loop nodes. // -TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc) +TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, + const TSourceLoc& loc) { TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst); node->setLoc(loc); @@ -1041,13 +2462,19 @@ TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TInte // // Create a for-loop sequence. // -TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* initializer, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc) +TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* initializer, TIntermTyped* test, + TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc, TIntermLoop*& node) { - TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst); + node = new TIntermLoop(body, test, terminal, testFirst); node->setLoc(loc); - // make a sequence of the initializer and statement - TIntermAggregate* loopSequence = makeAggregate(initializer, loc); + // make a sequence of the initializer and statement, but try to reuse the + // aggregate already created for whatever is in the initializer, if there is one + TIntermAggregate* loopSequence = (initializer == nullptr || + initializer->getAsAggregate() == nullptr) ? makeAggregate(initializer, loc) + : initializer->getAsAggregate(); + if (loopSequence != nullptr && loopSequence->getOp() == EOpSequence) + loopSequence->setOp(EOpNull); loopSequence = growAggregate(loopSequence, node); loopSequence->setOperator(EOpSequence); @@ -1059,7 +2486,7 @@ TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* init // TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc& loc) { - return addBranch(branchOp, 0, loc); + return addBranch(branchOp, nullptr, loc); } TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, const TSourceLoc& loc) @@ -1076,7 +2503,7 @@ TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expres // bool TIntermediate::postProcess(TIntermNode* root, EShLanguage /*language*/) { - if (root == 0) + if (root == nullptr) return true; // Finish off the top-level sequence @@ -1087,6 +2514,14 @@ bool TIntermediate::postProcess(TIntermNode* root, EShLanguage /*language*/) // Propagate 'noContraction' label in backward from 'precise' variables. glslang::PropagateNoContraction(*this); + switch (textureSamplerTransformMode) { + case EShTexSampTransKeep: + break; + case EShTexSampTransUpgradeTextureRemoveSampler: + performTextureUpgradeAndSamplerRemovalTransformation(root); + break; + } + return true; } @@ -1107,7 +2542,7 @@ void TIntermediate::addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguag // - ftransform() can make gl_Vertex and gl_ModelViewProjectionMatrix active. // - //if (ftransformUsed) { + // if (ftransformUsed) { // TODO: 1.1 lowering functionality: track ftransform() usage // addSymbolLinkageNode(root, symbolTable, "gl_Vertex"); // addSymbolLinkageNode(root, symbolTable, "gl_ModelViewProjectionMatrix"); @@ -1225,6 +2660,12 @@ bool TIntermediate::isSpecializationOperation(const TIntermOperator& node) const case EOpIndexIndirect: case EOpIndexDirectStruct: case EOpVectorSwizzle: + case EOpConvFloatToDouble: + case EOpConvDoubleToFloat: + case EOpConvFloat16ToFloat: + case EOpConvFloatToFloat16: + case EOpConvFloat16ToDouble: + case EOpConvDoubleToFloat16: return true; default: return false; @@ -1248,13 +2689,97 @@ bool TIntermediate::isSpecializationOperation(const TIntermOperator& node) const case EOpIndexDirectStruct: case EOpVectorSwizzle: - // conversion constructors + // (u)int* -> bool + case EOpConvInt8ToBool: + case EOpConvInt16ToBool: case EOpConvIntToBool: + case EOpConvInt64ToBool: + case EOpConvUint8ToBool: + case EOpConvUint16ToBool: case EOpConvUintToBool: - case EOpConvUintToInt: + case EOpConvUint64ToBool: + + // bool -> (u)int* + case EOpConvBoolToInt8: + case EOpConvBoolToInt16: case EOpConvBoolToInt: - case EOpConvIntToUint: + 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: @@ -1288,6 +2813,64 @@ bool TIntermediate::isSpecializationOperation(const TIntermOperator& node) const } } +// Is the operation one that must propagate nonuniform? +bool TIntermediate::isNonuniformPropagating(TOperator op) const +{ + // "* All Operators in Section 5.1 (Operators), except for assignment, + // arithmetic assignment, and sequence + // * Component selection in Section 5.5 + // * Matrix components in Section 5.6 + // * Structure and Array Operations in Section 5.7, except for the length + // method." + switch (op) { + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + + case EOpNegative: + case EOpLogicalNot: + case EOpVectorLogicalNot: + case EOpBitwiseNot: + + case EOpAdd: + case EOpSub: + case EOpMul: + case EOpDiv: + case EOpMod: + case EOpRightShift: + case EOpLeftShift: + case EOpAnd: + case EOpInclusiveOr: + case EOpExclusiveOr: + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: + + case EOpLogicalOr: + case EOpLogicalXor: + case EOpLogicalAnd: + + case EOpIndexDirect: + case EOpIndexIndirect: + case EOpIndexDirectStruct: + case EOpVectorSwizzle: + return true; + + default: + break; + } + + return false; +} + //////////////////////////////////////////////////////////////// // // Member functions of the nodes used for building the tree. @@ -1336,25 +2919,52 @@ bool TIntermOperator::isConstructor() const } // -// Make sure the type of a unary operator is appropriate for its -// combination of operation and operand type. +// Make sure the type of an operator is appropriate for its +// combination of operation and operand type. This will invoke +// promoteUnary, promoteBinary, etc as needed. // -// Returns false in nothing makes sense. +// Returns false if nothing makes sense. // -bool TIntermUnary::promote() +bool TIntermediate::promote(TIntermOperator* node) { + if (node == nullptr) + return false; + + if (node->getAsUnaryNode()) + return promoteUnary(*node->getAsUnaryNode()); + + if (node->getAsBinaryNode()) + return promoteBinary(*node->getAsBinaryNode()); + + if (node->getAsAggregate()) + return promoteAggregate(*node->getAsAggregate()); + + return false; +} + +// +// See TIntermediate::promote +// +bool TIntermediate::promoteUnary(TIntermUnary& node) +{ + const TOperator op = node.getOp(); + TIntermTyped* operand = node.getOperand(); + switch (op) { case EOpLogicalNot: - if (operand->getBasicType() != EbtBool) + // Convert operand to a boolean type + if (operand->getBasicType() != EbtBool) { + // Add constructor to boolean type. If that fails, we can't do it, so return false. + TIntermTyped* converted = addConversion(op, TType(EbtBool), operand); + if (converted == nullptr) + return false; - return false; + // Use the result of converting the node to a bool. + node.setOperand(operand = converted); // also updates stack variable + } break; case EOpBitwiseNot: - if (operand->getBasicType() != EbtInt && - operand->getBasicType() != EbtUint && - operand->getBasicType() != EbtInt64 && - operand->getBasicType() != EbtUint64) - + if (!isTypeInt(operand->getBasicType())) return false; break; case EOpNegative: @@ -1362,11 +2972,9 @@ bool TIntermUnary::promote() case EOpPostDecrement: case EOpPreIncrement: case EOpPreDecrement: - if (operand->getBasicType() != EbtInt && - operand->getBasicType() != EbtUint && - operand->getBasicType() != EbtInt64 && - operand->getBasicType() != EbtUint64 && + if (!isTypeInt(operand->getBasicType()) && operand->getBasicType() != EbtFloat && + operand->getBasicType() != EbtFloat16 && operand->getBasicType() != EbtDouble) return false; @@ -1378,28 +2986,29 @@ bool TIntermUnary::promote() return false; } - setType(operand->getType()); - getWritableType().getQualifier().makeTemporary(); + node.setType(operand->getType()); + node.getWritableType().getQualifier().makeTemporary(); return true; } void TIntermUnary::updatePrecision() { - if (getBasicType() == EbtInt || getBasicType() == EbtUint || getBasicType() == EbtFloat) { + if (getBasicType() == EbtInt || getBasicType() == EbtUint || getBasicType() == EbtFloat || getBasicType() == EbtFloat16) { if (operand->getQualifier().precision > getQualifier().precision) getQualifier().precision = operand->getQualifier().precision; } } // -// Establishes the type of the resultant operation, as well as -// makes the operator the correct one for the operands. +// See TIntermediate::promote // -// Returns false if operator can't work on operands. -// -bool TIntermBinary::promote() +bool TIntermediate::promoteBinary(TIntermBinary& node) { + TOperator op = node.getOp(); + TIntermTyped* left = node.getLeft(); + TIntermTyped* right = node.getRight(); + // Arrays and structures have to be exact matches. if ((left->isArray() || right->isArray() || left->getBasicType() == EbtStruct || right->getBasicType() == EbtStruct) && left->getType() != right->getType()) @@ -1407,8 +3016,8 @@ bool TIntermBinary::promote() // Base assumption: just make the type the same as the left // operand. Only deviations from this will be coded. - setType(left->getType()); - type.getQualifier().clear(); + node.setType(left->getType()); + node.getWritableType().getQualifier().clear(); // Composite and opaque types don't having pending operator changes, e.g., // array, structure, and samplers. Just establish final type and correctness. @@ -1421,7 +3030,7 @@ bool TIntermBinary::promote() return false; } else { // Promote to conditional - setType(TType(EbtBool)); + node.setType(TType(EbtBool)); } return true; @@ -1440,32 +3049,94 @@ bool TIntermBinary::promote() // We now have only scalars, vectors, and matrices to worry about. // + // HLSL implicitly promotes bool -> int for numeric operations. + // (Implicit conversions to make the operands match each other's types were already done.) + if (getSource() == EShSourceHlsl && + (left->getBasicType() == EbtBool || right->getBasicType() == EbtBool)) { + switch (op) { + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + + case EOpRightShift: + case EOpLeftShift: + + case EOpMod: + + case EOpAnd: + case EOpInclusiveOr: + case EOpExclusiveOr: + + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpMul: + if (left->getBasicType() == EbtBool) + left = createConversion(EbtInt, left); + if (right->getBasicType() == EbtBool) + right = createConversion(EbtInt, right); + if (left == nullptr || right == nullptr) + return false; + node.setLeft(left); + node.setRight(right); + + // Update the original base assumption on result type.. + node.setType(left->getType()); + node.getWritableType().getQualifier().clear(); + + break; + + default: + break; + } + } + // Do general type checks against individual operands (comparing left and right is coming up, checking mixed shapes after that) switch (op) { case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: - // Relational comparisons need matching numeric types and will promote to scalar Boolean. - if (left->getBasicType() == EbtBool || left->getType().isVector() || left->getType().isMatrix()) + // Relational comparisons need numeric types and will promote to scalar Boolean. + if (left->getBasicType() == EbtBool) return false; - // Fall through + node.setType(TType(EbtBool, EvqTemporary, left->getVectorSize())); + break; case EOpEqual: case EOpNotEqual: - // All the above comparisons result in a bool (but not the vector compares) - setType(TType(EbtBool)); + if (getSource() == EShSourceHlsl) { + const int resultWidth = std::max(left->getVectorSize(), right->getVectorSize()); + + // In HLSL, == or != on vectors means component-wise comparison. + if (resultWidth > 1) { + op = (op == EOpEqual) ? EOpVectorEqual : EOpVectorNotEqual; + node.setOp(op); + } + + node.setType(TType(EbtBool, EvqTemporary, resultWidth)); + } else { + // All the above comparisons result in a bool (but not the vector compares) + node.setType(TType(EbtBool)); + } break; case EOpLogicalAnd: case EOpLogicalOr: case EOpLogicalXor: - // logical ops operate only on scalar Booleans and will promote to scalar Boolean. - if (left->getBasicType() != EbtBool || left->isVector() || left->isMatrix()) - return false; + // logical ops operate only on Booleans or vectors of Booleans. + if (left->getBasicType() != EbtBool || left->isMatrix()) + return false; - setType(TType(EbtBool)); + if (getSource() == EShSourceGlsl) { + // logical ops operate only on scalar Booleans and will promote to scalar Boolean. + if (left->isVector()) + return false; + } + + node.setType(TType(EbtBool, EvqTemporary, left->getVectorSize())); break; case EOpRightShift: @@ -1482,11 +3153,11 @@ bool TIntermBinary::promote() case EOpAndAssign: case EOpInclusiveOrAssign: case EOpExclusiveOrAssign: + if (getSource() == EShSourceHlsl) + break; + // Check for integer-only operands. - if ((left->getBasicType() != EbtInt && left->getBasicType() != EbtUint && - left->getBasicType() != EbtInt64 && left->getBasicType() != EbtUint64) || - (right->getBasicType() != EbtInt && right->getBasicType() != EbtUint && - right->getBasicType() != EbtInt64 && right->getBasicType() != EbtUint64)) + if (!isTypeInt(left->getBasicType()) && !isTypeInt(right->getBasicType())) return false; if (left->isMatrix() || right->isMatrix()) return false; @@ -1518,14 +3189,14 @@ bool TIntermBinary::promote() case EOpEqual: case EOpNotEqual: + case EOpVectorEqual: + case EOpVectorNotEqual: case EOpLogicalAnd: case EOpLogicalOr: case EOpLogicalXor: return left->getType() == right->getType(); - // no shifts: they can mix types (scalar int can shift a vector uint, etc.) - case EOpMod: case EOpModAssign: @@ -1539,6 +3210,7 @@ bool TIntermBinary::promote() case EOpAdd: case EOpSub: case EOpDiv: + case EOpAddAssign: case EOpSubAssign: case EOpDivAssign: @@ -1563,7 +3235,7 @@ bool TIntermBinary::promote() return true; // Finish handling the case, for all ops, where there are two vectors of different sizes - if (left->isVector() && right->isVector() && left->getVectorSize() != right->getVectorSize()) + if (left->isVector() && right->isVector() && left->getVectorSize() != right->getVectorSize() && right->getVectorSize() > 1) return false; // @@ -1578,33 +3250,33 @@ bool TIntermBinary::promote() if (left->isVector()) { if (left->getVectorSize() != right->getMatrixRows()) return false; - op = EOpVectorTimesMatrix; - setType(TType(basicType, EvqTemporary, right->getMatrixCols())); + node.setOp(op = EOpVectorTimesMatrix); + node.setType(TType(basicType, EvqTemporary, right->getMatrixCols())); } else { - op = EOpMatrixTimesScalar; - setType(TType(basicType, EvqTemporary, 0, right->getMatrixCols(), right->getMatrixRows())); + node.setOp(op = EOpMatrixTimesScalar); + node.setType(TType(basicType, EvqTemporary, 0, right->getMatrixCols(), right->getMatrixRows())); } } else if (left->isMatrix() && !right->isMatrix()) { if (right->isVector()) { if (left->getMatrixCols() != right->getVectorSize()) return false; - op = EOpMatrixTimesVector; - setType(TType(basicType, EvqTemporary, left->getMatrixRows())); + node.setOp(op = EOpMatrixTimesVector); + node.setType(TType(basicType, EvqTemporary, left->getMatrixRows())); } else { - op = EOpMatrixTimesScalar; + node.setOp(op = EOpMatrixTimesScalar); } } else if (left->isMatrix() && right->isMatrix()) { if (left->getMatrixCols() != right->getMatrixRows()) return false; - op = EOpMatrixTimesMatrix; - setType(TType(basicType, EvqTemporary, 0, right->getMatrixCols(), left->getMatrixRows())); + node.setOp(op = EOpMatrixTimesMatrix); + node.setType(TType(basicType, EvqTemporary, 0, right->getMatrixCols(), left->getMatrixRows())); } else if (! left->isMatrix() && ! right->isMatrix()) { if (left->isVector() && right->isVector()) { ; // leave as component product } else if (left->isVector() || right->isVector()) { - op = EOpVectorTimesScalar; + node.setOp(op = EOpVectorTimesScalar); if (right->isVector()) - setType(TType(basicType, EvqTemporary, right->getVectorSize())); + node.setType(TType(basicType, EvqTemporary, right->getVectorSize())); } } else { return false; @@ -1615,7 +3287,7 @@ bool TIntermBinary::promote() if (left->isVector()) { if (left->getVectorSize() != right->getMatrixRows() || left->getVectorSize() != right->getMatrixCols()) return false; - op = EOpVectorTimesMatrixAssign; + node.setOp(op = EOpVectorTimesMatrixAssign); } else { return false; } @@ -1623,19 +3295,19 @@ bool TIntermBinary::promote() if (right->isVector()) { return false; } else { - op = EOpMatrixTimesScalarAssign; + node.setOp(op = EOpMatrixTimesScalarAssign); } } else if (left->isMatrix() && right->isMatrix()) { - if (left->getMatrixCols() != left->getMatrixRows() || left->getMatrixCols() != right->getMatrixCols() || left->getMatrixCols() != right->getMatrixRows()) + if (left->getMatrixCols() != right->getMatrixCols() || left->getMatrixCols() != right->getMatrixRows()) return false; - op = EOpMatrixTimesMatrixAssign; + node.setOp(op = EOpMatrixTimesMatrixAssign); } else if (!left->isMatrix() && !right->isMatrix()) { if (left->isVector() && right->isVector()) { // leave as component product } else if (left->isVector() || right->isVector()) { if (! left->isVector()) return false; - op = EOpVectorTimesScalarAssign; + node.setOp(op = EOpVectorTimesScalarAssign); } } else { return false; @@ -1669,6 +3341,7 @@ bool TIntermBinary::promote() case EOpAndAssign: case EOpInclusiveOrAssign: case EOpExclusiveOrAssign: + if ((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix()) || left->getBasicType() != right->getBasicType()) @@ -1678,8 +3351,8 @@ bool TIntermBinary::promote() if (left->isVector() && right->isVector() && left->getVectorSize() != right->getVectorSize()) return false; if (right->isVector() || right->isMatrix()) { - type.shallowCopy(right->getType()); - type.getQualifier().makeTemporary(); + node.getWritableType().shallowCopy(right->getType()); + node.getWritableType().getQualifier().makeTemporary(); } break; @@ -1703,7 +3376,7 @@ bool TIntermBinary::promote() case EOpExclusiveOrAssign: case EOpLeftShiftAssign: case EOpRightShiftAssign: - if (getType() != left->getType()) + if (node.getType() != left->getType()) return false; break; default: @@ -1713,9 +3386,79 @@ bool TIntermBinary::promote() return true; } +// +// See TIntermediate::promote +// +bool TIntermediate::promoteAggregate(TIntermAggregate& node) +{ + TOperator op = node.getOp(); + TIntermSequence& args = node.getSequence(); + const int numArgs = static_cast(args.size()); + + // Presently, only hlsl does intrinsic promotions. + if (getSource() != EShSourceHlsl) + return true; + + // set of opcodes that can be promoted in this manner. + switch (op) { + case EOpAtan: + case EOpClamp: + case EOpCross: + case EOpDistance: + case EOpDot: + case EOpDst: + case EOpFaceForward: + // case EOpFindMSB: TODO: + // case EOpFindLSB: TODO: + case EOpFma: + case EOpMod: + case EOpFrexp: + case EOpLdexp: + case EOpMix: + case EOpLit: + case EOpMax: + case EOpMin: + case EOpModf: + // case EOpGenMul: TODO: + case EOpPow: + case EOpReflect: + case EOpRefract: + // case EOpSinCos: TODO: + case EOpSmoothStep: + case EOpStep: + break; + default: + return true; + } + + // TODO: array and struct behavior + + // Try converting all nodes to the given node's type + TIntermSequence convertedArgs(numArgs, nullptr); + + // Try to convert all types to the nonConvArg type. + for (int nonConvArg = 0; nonConvArg < numArgs; ++nonConvArg) { + // Try converting all args to this arg's type + for (int convArg = 0; convArg < numArgs; ++convArg) { + convertedArgs[convArg] = addConversion(op, args[nonConvArg]->getAsTyped()->getType(), + args[convArg]->getAsTyped()); + } + + // If we successfully converted all the args, use the result. + if (std::all_of(convertedArgs.begin(), convertedArgs.end(), + [](const TIntermNode* node) { return node != nullptr; })) { + + std::swap(args, convertedArgs); + return true; + } + } + + return false; +} + void TIntermBinary::updatePrecision() { - if (getBasicType() == EbtInt || getBasicType() == EbtUint || getBasicType() == EbtFloat) { + if (getBasicType() == EbtInt || getBasicType() == EbtUint || getBasicType() == EbtFloat || getBasicType() == EbtFloat16) { getQualifier().precision = std::max(right->getQualifier().precision, left->getQualifier().precision); if (getQualifier().precision != EpqNone) { left->propagatePrecision(getQualifier().precision); @@ -1726,7 +3469,7 @@ void TIntermBinary::updatePrecision() void TIntermTyped::propagatePrecision(TPrecisionQualifier newPrecision) { - if (getQualifier().precision != EpqNone || (getBasicType() != EbtInt && getBasicType() != EbtUint && getBasicType() != EbtFloat)) + if (getQualifier().precision != EpqNone || (getBasicType() != EbtInt && getBasicType() != EbtUint && getBasicType() != EbtFloat && getBasicType() != EbtFloat16)) return; getQualifier().precision = newPrecision; @@ -1800,10 +3543,9 @@ TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermC leftUnionArray[i].setDConst(static_cast(rightUnionArray[i].getBConst())); break; case EbtFloat: - leftUnionArray[i] = rightUnionArray[i]; - break; case EbtDouble: - leftUnionArray[i].setDConst(static_cast(rightUnionArray[i].getDConst())); + case EbtFloat16: + leftUnionArray[i] = rightUnionArray[i]; break; default: return node; @@ -1828,6 +3570,33 @@ TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermC break; case EbtFloat: case EbtDouble: + case EbtFloat16: + leftUnionArray[i] = rightUnionArray[i]; + break; + default: + return node; + } + break; + case EbtFloat16: + switch (node->getType().getBasicType()) { + case EbtInt: + leftUnionArray[i].setDConst(static_cast(rightUnionArray[i].getIConst())); + break; + case EbtUint: + leftUnionArray[i].setDConst(static_cast(rightUnionArray[i].getUConst())); + break; + case EbtInt64: + leftUnionArray[i].setDConst(static_cast(rightUnionArray[i].getI64Const())); + break; + case EbtUint64: + leftUnionArray[i].setDConst(static_cast(rightUnionArray[i].getU64Const())); + break; + case EbtBool: + leftUnionArray[i].setDConst(static_cast(rightUnionArray[i].getBConst())); + break; + case EbtFloat: + case EbtDouble: + case EbtFloat16: leftUnionArray[i] = rightUnionArray[i]; break; default: @@ -1853,6 +3622,7 @@ TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermC break; case EbtFloat: case EbtDouble: + case EbtFloat16: leftUnionArray[i].setIConst(static_cast(rightUnionArray[i].getDConst())); break; default: @@ -1878,6 +3648,7 @@ TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermC break; case EbtFloat: case EbtDouble: + case EbtFloat16: leftUnionArray[i].setUConst(static_cast(rightUnionArray[i].getDConst())); break; default: @@ -1903,6 +3674,7 @@ TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermC break; case EbtFloat: case EbtDouble: + case EbtFloat16: leftUnionArray[i].setBConst(rightUnionArray[i].getDConst() != 0.0); break; default: @@ -1928,6 +3700,7 @@ TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermC break; case EbtFloat: case EbtDouble: + case EbtFloat16: leftUnionArray[i].setI64Const(static_cast(rightUnionArray[i].getDConst())); break; default: @@ -1953,6 +3726,7 @@ TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermC break; case EbtFloat: case EbtDouble: + case EbtFloat16: leftUnionArray[i].setU64Const(static_cast(rightUnionArray[i].getDConst())); break; default: @@ -1970,11 +3744,88 @@ TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermC node->getLoc()); } -void TIntermAggregate::addToPragmaTable(const TPragmaTable& pTable) +void TIntermAggregate::setPragmaTable(const TPragmaTable& pTable) { - assert(!pragmaTable); - pragmaTable = new TPragmaTable(); + assert(pragmaTable == nullptr); + pragmaTable = new TPragmaTable; *pragmaTable = pTable; } +// If either node is a specialization constant, while the other is +// a constant (or specialization constant), the result is still +// a specialization constant. +bool TIntermediate::specConstantPropagates(const TIntermTyped& node1, const TIntermTyped& node2) +{ + return (node1.getType().getQualifier().isSpecConstant() && node2.getType().getQualifier().isConstant()) || + (node2.getType().getQualifier().isSpecConstant() && node1.getType().getQualifier().isConstant()); +} + +struct TextureUpgradeAndSamplerRemovalTransform : public TIntermTraverser { + void visitSymbol(TIntermSymbol* symbol) override { + if (symbol->getBasicType() == EbtSampler && symbol->getType().getSampler().isTexture()) { + symbol->getWritableType().getSampler().combined = true; + } + } + bool visitAggregate(TVisit, TIntermAggregate* ag) override { + using namespace std; + TIntermSequence& seq = ag->getSequence(); + TQualifierList& qual = ag->getQualifierList(); + + // qual and seq are indexed using the same indices, so we have to modify both in lock-step + assert(seq.size() == qual.size() || qual.empty()); + + size_t write = 0; + for (size_t i = 0; i < seq.size(); ++i) { + TIntermSymbol* symbol = seq[i]->getAsSymbolNode(); + if (symbol && symbol->getBasicType() == EbtSampler && symbol->getType().getSampler().isPureSampler()) { + // remove pure sampler variables + continue; + } + + TIntermNode* result = seq[i]; + + // replace constructors with sampler/textures + TIntermAggregate *constructor = seq[i]->getAsAggregate(); + if (constructor && constructor->getOp() == EOpConstructTextureSampler) { + if (!constructor->getSequence().empty()) + result = constructor->getSequence()[0]; + } + + // write new node & qualifier + seq[write] = result; + if (!qual.empty()) + qual[write] = qual[i]; + write++; + } + + seq.resize(write); + if (!qual.empty()) + qual.resize(write); + + return true; + } +}; + +void TIntermediate::performTextureUpgradeAndSamplerRemovalTransformation(TIntermNode* root) +{ + TextureUpgradeAndSamplerRemovalTransform transform; + root->traverse(&transform); +} + +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"; + default: + assert(0); // internal error: should only be called with valid resource types. + return nullptr; + } +} + + } // end namespace glslang diff --git a/Externals/glslang/glslang/MachineIndependent/LiveTraverser.h b/Externals/glslang/glslang/MachineIndependent/LiveTraverser.h new file mode 100644 index 0000000000..7333bc964e --- /dev/null +++ b/Externals/glslang/glslang/MachineIndependent/LiveTraverser.h @@ -0,0 +1,138 @@ +// +// Copyright (C) 2016 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. +// + +#pragma once + +#include "../Include/Common.h" +#include "reflection.h" +#include "localintermediate.h" + +#include "gl_types.h" + +#include +#include + +namespace glslang { + +// +// The traverser: mostly pass through, except +// - processing function-call nodes to push live functions onto the stack of functions to process +// - processing selection nodes to trim semantically dead code +// +// This is in the glslang namespace directly so it can be a friend of TReflection. +// This can be derived from to implement reflection database traversers or +// binding mappers: anything that wants to traverse the live subset of the tree. +// + +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), + intermediate(i), traverseAll(traverseAll) + { } + + // + // Given a function name, find its subroot in the tree, and push it onto the stack of + // functions left to process. + // + void pushFunction(const TString& name) + { + TIntermSequence& globals = intermediate.getTreeRoot()->getAsAggregate()->getSequence(); + for (unsigned int f = 0; f < globals.size(); ++f) { + TIntermAggregate* candidate = globals[f]->getAsAggregate(); + if (candidate && candidate->getOp() == EOpFunction && candidate->getName() == name) { + functions.push_back(candidate); + break; + } + } + } + + typedef std::list TFunctionStack; + TFunctionStack functions; + +protected: + // To catch which function calls are not dead, and hence which functions must be visited. + virtual bool visitAggregate(TVisit, TIntermAggregate* node) + { + if (!traverseAll) + if (node->getOp() == EOpFunctionCall) + addFunctionCall(node); + + return true; // traverse this subtree + } + + // To prune semantically dead paths. + virtual bool visitSelection(TVisit /* visit */, TIntermSelection* node) + { + if (traverseAll) + return true; // traverse all code + + TIntermConstantUnion* constant = node->getCondition()->getAsConstantUnion(); + if (constant) { + // cull the path that is dead + if (constant->getConstArray()[0].getBConst() == true && node->getTrueBlock()) + node->getTrueBlock()->traverse(this); + if (constant->getConstArray()[0].getBConst() == false && node->getFalseBlock()) + node->getFalseBlock()->traverse(this); + + return false; // don't traverse any more, we did it all above + } 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) + { + // // just use the map to ensure we process each function at most once + if (liveFunctions.find(call->getName()) == liveFunctions.end()) { + liveFunctions.insert(call->getName()); + pushFunction(call->getName()); + } + } + + const TIntermediate& intermediate; + typedef std::unordered_set TLiveFunctions; + TLiveFunctions liveFunctions; + bool traverseAll; + +private: + // prevent copy & copy construct + TLiveTraverser(TLiveTraverser&); + TLiveTraverser& operator=(TLiveTraverser&); +}; + +} // namespace glslang diff --git a/Externals/glslang/glslang/MachineIndependent/ParseContextBase.cpp b/Externals/glslang/glslang/MachineIndependent/ParseContextBase.cpp new file mode 100644 index 0000000000..bfa9de4dff --- /dev/null +++ b/Externals/glslang/glslang/MachineIndependent/ParseContextBase.cpp @@ -0,0 +1,613 @@ +// +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2016 Google, 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. +// + +// Implement the TParseContextBase class. + +#include + +#include "ParseHelper.h" + +extern int yyparse(glslang::TParseContext*); + +namespace glslang { + +// +// Used to output syntax, parsing, and semantic errors. +// + +void TParseContextBase::outputMessage(const TSourceLoc& loc, const char* szReason, + const char* szToken, + const char* szExtraInfoFormat, + TPrefixType prefix, va_list args) +{ + const int maxSize = MaxTokenLength + 200; + char szExtraInfo[maxSize]; + + safe_vsprintf(szExtraInfo, maxSize, szExtraInfoFormat, args); + + infoSink.info.prefix(prefix); + infoSink.info.location(loc); + infoSink.info << "'" << szToken << "' : " << szReason << " " << szExtraInfo << "\n"; + + if (prefix == EPrefixError) { + ++numErrors; + } +} + +void C_DECL TParseContextBase::error(const TSourceLoc& loc, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, ...) +{ + if (messages & EShMsgOnlyPreprocessor) + return; + va_list args; + va_start(args, szExtraInfoFormat); + outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args); + va_end(args); + + if ((messages & EShMsgCascadingErrors) == 0) + currentScanner->setEndOfInput(); +} + +void C_DECL TParseContextBase::warn(const TSourceLoc& loc, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, ...) +{ + if (suppressWarnings()) + return; + va_list args; + va_start(args, szExtraInfoFormat); + outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args); + va_end(args); +} + +void C_DECL TParseContextBase::ppError(const TSourceLoc& loc, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, ...) +{ + va_list args; + va_start(args, szExtraInfoFormat); + outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args); + va_end(args); + + if ((messages & EShMsgCascadingErrors) == 0) + currentScanner->setEndOfInput(); +} + +void C_DECL TParseContextBase::ppWarn(const TSourceLoc& loc, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, ...) +{ + va_list args; + va_start(args, szExtraInfoFormat); + outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args); + va_end(args); +} + +// +// Both test and if necessary, spit out an error, to see if the node is really +// an l-value that can be operated on this way. +// +// Returns true if there was an error. +// +bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node) +{ + TIntermBinary* binaryNode = node->getAsBinaryNode(); + + if (binaryNode) { + switch(binaryNode->getOp()) { + case EOpIndexDirect: + case EOpIndexIndirect: // fall through + case EOpIndexDirectStruct: // fall through + case EOpVectorSwizzle: + case EOpMatrixSwizzle: + return lValueErrorCheck(loc, op, binaryNode->getLeft()); + default: + break; + } + error(loc, " l-value required", op, "", ""); + + return true; + } + + const char* symbol = nullptr; + TIntermSymbol* symNode = node->getAsSymbolNode(); + if (symNode != nullptr) + symbol = symNode->getName().c_str(); + + const char* message = nullptr; + switch (node->getQualifier().storage) { + case EvqConst: message = "can't modify a const"; break; + case EvqConstReadOnly: message = "can't modify a const"; break; + case EvqUniform: message = "can't modify a uniform"; break; + case EvqBuffer: + if (node->getQualifier().readonly) + message = "can't modify a readonly buffer"; + break; + + default: + // + // Type that can't be written to? + // + switch (node->getBasicType()) { + case EbtSampler: + message = "can't modify a sampler"; + break; + case EbtAtomicUint: + message = "can't modify an atomic_uint"; + break; + case EbtVoid: + message = "can't modify void"; + break; + default: + break; + } + } + + if (message == nullptr && binaryNode == nullptr && symNode == nullptr) { + error(loc, " l-value required", op, "", ""); + + return true; + } + + // + // Everything else is okay, no error. + // + if (message == nullptr) + return false; + + // + // If we get here, we have an error and a message. + // + if (symNode) + error(loc, " l-value required", op, "\"%s\" (%s)", symbol, message); + else + error(loc, " l-value required", op, "(%s)", message); + + return true; +} + +// Test for and give an error if the node can't be read from. +void TParseContextBase::rValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node) +{ + if (! node) + return; + + TIntermBinary* binaryNode = node->getAsBinaryNode(); + if (binaryNode) { + switch(binaryNode->getOp()) { + case EOpIndexDirect: + case EOpIndexIndirect: + case EOpIndexDirectStruct: + case EOpVectorSwizzle: + case EOpMatrixSwizzle: + rValueErrorCheck(loc, op, binaryNode->getLeft()); + default: + break; + } + + return; + } + + TIntermSymbol* symNode = node->getAsSymbolNode(); + if (symNode && symNode->getQualifier().writeonly) + error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str()); +} + +// Add 'symbol' to the list of deferred linkage symbols, which +// are later processed in finish(), at which point the symbol +// must still be valid. +// It is okay if the symbol's type will be subsequently edited; +// the modifications will be tracked. +// Order is preserved, to avoid creating novel forward references. +void TParseContextBase::trackLinkage(TSymbol& symbol) +{ + if (!parsingBuiltins) + linkageSymbols.push_back(&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) +{ + if (index < 0) { + error(loc, "", "[", "index out of range '%d'", index); + index = 0; + } else if (type.isArray()) { + if (type.isSizedArray() && index >= type.getOuterArraySize()) { + error(loc, "", "[", "array index out of range '%d'", index); + index = type.getOuterArraySize() - 1; + } + } else if (type.isVector()) { + if (index >= type.getVectorSize()) { + error(loc, "", "[", "vector index out of range '%d'", index); + index = type.getVectorSize() - 1; + } + } else if (type.isMatrix()) { + if (index >= type.getMatrixCols()) { + error(loc, "", "[", "matrix index out of range '%d'", index); + index = type.getMatrixCols() - 1; + } + } +} + +// Make a shared symbol have a non-shared version that can be edited by the current +// compile, such that editing its type will not change the shared version and will +// effect all nodes already sharing it (non-shallow type), +// or adopting its full type after being edited (shallow type). +void TParseContextBase::makeEditable(TSymbol*& symbol) +{ + // copyUp() does a deep copy of the type. + symbol = symbolTable.copyUp(symbol); + + // Save it (deferred, so it can be edited first) in the AST for linker use. + if (symbol) + trackLinkage(*symbol); +} + +// Return a writable version of the variable 'name'. +// +// Return nullptr if 'name' is not found. This should mean +// something is seriously wrong (e.g., compiler asking self for +// built-in that doesn't exist). +TVariable* TParseContextBase::getEditableVariable(const char* name) +{ + bool builtIn; + TSymbol* symbol = symbolTable.find(name, &builtIn); + + assert(symbol != nullptr); + if (symbol == nullptr) + return nullptr; + + if (builtIn) + makeEditable(symbol); + + return symbol->getAsVariable(); +} + +// Select the best matching function for 'call' from 'candidateList'. +// +// Assumptions +// +// There is no exact match, so a selection algorithm needs to run. That is, the +// language-specific handler should check for exact match first, to +// decide what to do, before calling this selector. +// +// Input +// +// * list of candidate signatures to select from +// * the call +// * a predicate function convertible(from, to) that says whether or not type +// 'from' can implicitly convert to type 'to' (it includes the case of what +// the calling language would consider a matching type with no conversion +// needed) +// * a predicate function better(from1, from2, to1, to2) that says whether or +// not a conversion from <-> to2 is considered better than a conversion +// from <-> to1 (both in and out directions need testing, as declared by the +// formal parameter) +// +// Output +// +// * best matching candidate (or none, if no viable candidates found) +// * whether there was a tie for the best match (ambiguous overload selection, +// caller's choice for how to report) +// +const TFunction* TParseContextBase::selectFunction( + const TVector candidateList, + const TFunction& call, + std::function convertible, + std::function better, + /* output */ bool& tie) +{ +// +// Operation +// +// 1. Prune the input list of candidates down to a list of viable candidates, +// where each viable candidate has +// +// * at least as many parameters as there are calling arguments, with any +// remaining parameters being optional or having default values +// * each parameter is true under convertible(A, B), where A is the calling +// type for in and B is the formal type, and in addition, for out B is the +// calling type and A is the formal type +// +// 2. If there are no viable candidates, return with no match. +// +// 3. If there is only one viable candidate, it is the best match. +// +// 4. If there are multiple viable candidates, select the first viable candidate +// as the incumbent. Compare the incumbent to the next viable candidate, and if +// that candidate is better (bullets below), make it the incumbent. Repeat, with +// a linear walk through the viable candidate list. The final incumbent will be +// returned as the best match. A viable candidate is better than the incumbent if +// +// * it has a function argument with a better(...) conversion than the incumbent, +// for all directions needed by in and out +// * the incumbent has no argument with a better(...) conversion then the +// candidate, for either in or out (as needed) +// +// 5. Check for ambiguity by comparing the best match against all other viable +// candidates. If any other viable candidate has a function argument with a +// better(...) conversion than the best candidate (for either in or out +// directions), return that there was a tie for best. +// + + tie = false; + + // 1. prune to viable... + TVector viableCandidates; + for (auto it = candidateList.begin(); it != candidateList.end(); ++it) { + const TFunction& candidate = *(*it); + + // 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()) + continue; + + // see if arguments are convertible + bool viable = true; + + // The call can have fewer parameters than the candidate, if some have defaults. + const int paramCount = std::min(call.getParamCount(), candidate.getParamCount()); + for (int param = 0; param < paramCount; ++param) { + if (candidate[param].type->getQualifier().isParamInput()) { + if (! convertible(*call[param].type, *candidate[param].type, candidate.getBuiltInOp(), param)) { + viable = false; + break; + } + } + if (candidate[param].type->getQualifier().isParamOutput()) { + if (! convertible(*candidate[param].type, *call[param].type, candidate.getBuiltInOp(), param)) { + viable = false; + break; + } + } + } + + if (viable) + viableCandidates.push_back(&candidate); + } + + // 2. none viable... + if (viableCandidates.size() == 0) + return nullptr; + + // 3. only one viable... + if (viableCandidates.size() == 1) + return viableCandidates.front(); + + // 4. find best... + 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) { + if (better(*call[param].type, *can1[param].type, *can2[param].type)) { + hasBetterParam = true; + break; + } + } + return hasBetterParam; + }; + + 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) { + if (better(*call[param].type, *can1[param].type, *can2[param].type) || + better(*call[param].type, *can2[param].type, *can1[param].type)) + return false; + } + return true; + }; + + const TFunction* incumbent = viableCandidates.front(); + for (auto it = viableCandidates.begin() + 1; it != viableCandidates.end(); ++it) { + const TFunction& candidate = *(*it); + if (betterParam(*incumbent, candidate) && ! betterParam(candidate, *incumbent)) + incumbent = &candidate; + } + + // 5. ambiguity... + for (auto it = viableCandidates.begin(); it != viableCandidates.end(); ++it) { + if (incumbent == *it) + continue; + const TFunction& candidate = *(*it); + + // In the case of default parameters, it may have an identical initial set, which is + // also ambiguous + if (betterParam(*incumbent, candidate) || equivalentParams(*incumbent, candidate)) + tie = true; + } + + return incumbent; +} + +// +// Look at a '.' field selector string and change it into numerical selectors +// for a vector or scalar. +// +// Always return some form of swizzle, so the result is always usable. +// +void TParseContextBase::parseSwizzleSelector(const TSourceLoc& loc, const TString& compString, int vecSize, + TSwizzleSelectors& selector) +{ + // Too long? + if (compString.size() > MaxSwizzleSelectors) + error(loc, "vector swizzle too long", compString.c_str(), ""); + + // Use this to test that all swizzle characters are from the same swizzle-namespace-set + enum { + exyzw, + ergba, + estpq, + } fieldSet[MaxSwizzleSelectors]; + + // Decode the swizzle string. + int size = std::min(MaxSwizzleSelectors, (int)compString.size()); + for (int i = 0; i < size; ++i) { + switch (compString[i]) { + case 'x': + selector.push_back(0); + fieldSet[i] = exyzw; + break; + case 'r': + selector.push_back(0); + fieldSet[i] = ergba; + break; + case 's': + selector.push_back(0); + fieldSet[i] = estpq; + break; + + case 'y': + selector.push_back(1); + fieldSet[i] = exyzw; + break; + case 'g': + selector.push_back(1); + fieldSet[i] = ergba; + break; + case 't': + selector.push_back(1); + fieldSet[i] = estpq; + break; + + case 'z': + selector.push_back(2); + fieldSet[i] = exyzw; + break; + case 'b': + selector.push_back(2); + fieldSet[i] = ergba; + break; + case 'p': + selector.push_back(2); + fieldSet[i] = estpq; + break; + + case 'w': + selector.push_back(3); + fieldSet[i] = exyzw; + break; + case 'a': + selector.push_back(3); + fieldSet[i] = ergba; + break; + case 'q': + selector.push_back(3); + fieldSet[i] = estpq; + break; + + default: + error(loc, "unknown swizzle selection", compString.c_str(), ""); + break; + } + } + + // Additional error checking. + for (int i = 0; i < selector.size(); ++i) { + if (selector[i] >= vecSize) { + error(loc, "vector swizzle selection out of range", compString.c_str(), ""); + selector.resize(i); + break; + } + + if (i > 0 && fieldSet[i] != fieldSet[i-1]) { + error(loc, "vector swizzle selectors not from the same set", compString.c_str(), ""); + selector.resize(i); + break; + } + } + + // Ensure it is valid. + if (selector.size() == 0) + selector.push_back(0); +} + +// +// Make the passed-in variable information become a member of the +// global uniform block. If this doesn't exist yet, make it. +// +void TParseContextBase::growGlobalUniformBlock(const TSourceLoc& loc, TType& memberType, const TString& memberName, TTypeList* typeList) +{ + // Make the global block, if not yet made. + if (globalUniformBlock == nullptr) { + TQualifier blockQualifier; + blockQualifier.clear(); + blockQualifier.storage = EvqUniform; + TType blockType(new TTypeList, *NewPoolTString(getGlobalUniformBlockName()), blockQualifier); + setUniformBlockDefaults(blockType); + globalUniformBlock = new TVariable(NewPoolTString(""), blockType, true); + firstNewMember = 0; + } + + // Update with binding and set + globalUniformBlock->getWritableType().getQualifier().layoutBinding = globalUniformBinding; + globalUniformBlock->getWritableType().getQualifier().layoutSet = globalUniformSet; + + // Add the requested member as a member to the global block. + TType* type = new TType; + type->shallowCopy(memberType); + type->setFieldName(memberName); + if (typeList) + type->setStruct(typeList); + TTypeLoc typeLoc = {type, loc}; + globalUniformBlock->getType().getWritableStruct()->push_back(typeLoc); + + // Insert into the symbol table. + if (firstNewMember == 0) { + // This is the first request; we need a normal symbol table insert + if (symbolTable.insert(*globalUniformBlock)) + trackLinkage(*globalUniformBlock); + else + error(loc, "failed to insert the global constant buffer", "uniform", ""); + } else { + // This is a follow-on request; we need to amend the first insert + symbolTable.amend(*globalUniformBlock, firstNewMember); + } + + ++firstNewMember; +} + +void TParseContextBase::finish() +{ + if (parsingBuiltins) + return; + + // Transfer the linkage symbols to AST nodes, preserving order. + TIntermAggregate* linkage = new TIntermAggregate; + for (auto i = linkageSymbols.begin(); i != linkageSymbols.end(); ++i) + intermediate.addSymbolLinkageNode(linkage, **i); + intermediate.addSymbolLinkageNodes(linkage, getLanguage(), symbolTable); +} + +} // end namespace glslang diff --git a/Externals/glslang/glslang/MachineIndependent/ParseHelper.cpp b/Externals/glslang/glslang/MachineIndependent/ParseHelper.cpp old mode 100644 new mode 100755 index bd4b3c95b6..828e49651f --- a/Externals/glslang/glslang/MachineIndependent/ParseHelper.cpp +++ b/Externals/glslang/glslang/MachineIndependent/ParseHelper.cpp @@ -1,13 +1,14 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2012-2015 LunarG, Inc. -//Copyright (C) 2015-2016 Google, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2012-2015 LunarG, Inc. +// Copyright (C) 2015-2016 Google, Inc. +// Copyright (C) 2017 ARM Limited. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -21,25 +22,24 @@ // 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. +// 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. // #include "ParseHelper.h" #include "Scan.h" #include "../OSDependent/osinclude.h" -#include #include #include "preprocessor/PpContext.h" @@ -50,58 +50,24 @@ namespace glslang { TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins, int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, - TInfoSink& infoSink, bool forwardCompatible, EShMessages messages) : - TParseContextBase(symbolTable, interm, version, profile, spvVersion, language, infoSink, forwardCompatible, messages), - contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), statementNestingLevel(0), - inMain(false), postMainReturn(false), currentFunctionType(nullptr), blockName(nullptr), - limits(resources.limits), parsingBuiltins(parsingBuiltins), - afterEOF(false), + TInfoSink& infoSink, bool forwardCompatible, EShMessages messages, + const TString* entryPoint) : + TParseContextBase(symbolTable, interm, parsingBuiltins, version, profile, spvVersion, language, + infoSink, forwardCompatible, messages, entryPoint), + inMain(false), + blockName(nullptr), + limits(resources.limits), atomicUintOffsets(nullptr), anyIndexLimits(false) { - // ensure we always have a linkage node, even if empty, to simplify tree topology algorithms - linkage = new TIntermAggregate; - - // set all precision defaults to EpqNone, which is correct for all desktop types - // and for ES types that don't have defaults (thus getting an error on use) - for (int type = 0; type < EbtNumTypes; ++type) - defaultPrecision[type] = EpqNone; - - for (int type = 0; type < maxSamplerIndex; ++type) - defaultSamplerPrecision[type] = EpqNone; - - // replace with real precision defaults for those that have them - if (profile == EEsProfile) { - TSampler sampler; - sampler.set(EbtFloat, Esd2D); - defaultSamplerPrecision[computeSamplerTypeIndex(sampler)] = EpqLow; - sampler.set(EbtFloat, EsdCube); - defaultSamplerPrecision[computeSamplerTypeIndex(sampler)] = EpqLow; - sampler.set(EbtFloat, Esd2D); - sampler.external = true; - defaultSamplerPrecision[computeSamplerTypeIndex(sampler)] = EpqLow; - - // If we are parsing built-in computational variables/functions, it is meaningful to record - // whether the built-in has no precision qualifier, as that ambiguity - // is used to resolve the precision from the supplied arguments/operands instead. - // So, we don't actually want to replace EpqNone with a default precision for built-ins. - if (! parsingBuiltins) { - switch (language) { - case EShLangFragment: - defaultPrecision[EbtInt] = EpqMedium; - defaultPrecision[EbtUint] = EpqMedium; - break; - default: - defaultPrecision[EbtInt] = EpqHigh; - defaultPrecision[EbtUint] = EpqHigh; - defaultPrecision[EbtFloat] = EpqHigh; - break; - } - } - - defaultPrecision[EbtSampler] = EpqLow; - defaultPrecision[EbtAtomicUint] = EpqHigh; + // decide whether precision qualifiers should be ignored or respected + if (profile == EEsProfile || spvVersion.vulkan > 0) { + precisionManager.respectPrecisionQualifiers(); + if (! parsingBuiltins && language == EShLangFragment && profile != EEsProfile && spvVersion.vulkan > 0) + precisionManager.warnAboutDefaults(); } + setPrecisionDefaults(); + globalUniformDefaults.clear(); globalUniformDefaults.layoutMatrix = ElmColumnMajor; globalUniformDefaults.layoutPacking = spvVersion.spv != 0 ? ElpStd140 : ElpShared; @@ -113,7 +79,7 @@ TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, b globalInputDefaults.clear(); globalOutputDefaults.clear(); - // "Shaders in the transform + // "Shaders in the transform // feedback capturing mode have an initial global default of // layout(xfb_buffer = 0) out;" if (language == EShLangVertex || @@ -124,6 +90,9 @@ TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, b if (language == EShLangGeometry) globalOutputDefaults.layoutStream = 0; + + if (entryPoint != nullptr && entryPoint->size() > 0 && *entryPoint != "main") + infoSink.info.message(EPrefixError, "Source entry point must be \"main\""); } TParseContext::~TParseContext() @@ -131,6 +100,62 @@ TParseContext::~TParseContext() delete [] atomicUintOffsets; } +// Set up all default precisions as needed by the current environment. +// Intended just as a TParseContext constructor helper. +void TParseContext::setPrecisionDefaults() +{ + // Set all precision defaults to EpqNone, which is correct for all types + // when not obeying precision qualifiers, and correct for types that don't + // have defaults (thus getting an error on use) when obeying precision + // qualifiers. + + for (int type = 0; type < EbtNumTypes; ++type) + defaultPrecision[type] = EpqNone; + + for (int type = 0; type < maxSamplerIndex; ++type) + defaultSamplerPrecision[type] = EpqNone; + + // replace with real precision defaults for those that have them + if (obeyPrecisionQualifiers()) { + if (profile == EEsProfile) { + // Most don't have defaults, a few default to lowp. + TSampler sampler; + sampler.set(EbtFloat, Esd2D); + defaultSamplerPrecision[computeSamplerTypeIndex(sampler)] = EpqLow; + sampler.set(EbtFloat, EsdCube); + defaultSamplerPrecision[computeSamplerTypeIndex(sampler)] = EpqLow; + sampler.set(EbtFloat, Esd2D); + sampler.external = true; + defaultSamplerPrecision[computeSamplerTypeIndex(sampler)] = EpqLow; + } + + // If we are parsing built-in computational variables/functions, it is meaningful to record + // whether the built-in has no precision qualifier, as that ambiguity + // is used to resolve the precision from the supplied arguments/operands instead. + // So, we don't actually want to replace EpqNone with a default precision for built-ins. + if (! parsingBuiltins) { + if (profile == EEsProfile && language == EShLangFragment) { + defaultPrecision[EbtInt] = EpqMedium; + defaultPrecision[EbtUint] = EpqMedium; + } else { + defaultPrecision[EbtInt] = EpqHigh; + defaultPrecision[EbtUint] = EpqHigh; + defaultPrecision[EbtFloat] = EpqHigh; + } + + if (profile != EEsProfile) { + // Non-ES profile + // All sampler precisions default to highp. + for (int type = 0; type < maxSamplerIndex; ++type) + defaultSamplerPrecision[type] = EpqHigh; + } + } + + defaultPrecision[EbtSampler] = EpqLow; + defaultPrecision[EbtAtomicUint] = EpqHigh; + } +} + void TParseContext::setLimits(const TBuiltInResource& r) { resources = r; @@ -164,20 +189,22 @@ bool TParseContext::parseShaderStrings(TPpContext& ppContext, TInputScanner& inp currentScanner = &input; ppContext.setInput(input, versionWillBeError); yyparse(this); - if (! parsingBuiltins) - finalErrorCheck(); + + finish(); return numErrors == 0; } // This is called from bison when it has a parse (syntax) error +// Note though that to stop cascading errors, we set EOF, which +// will usually cause a syntax error, so be more accurate that +// compilation is terminating. void TParseContext::parserError(const char* s) { - if (afterEOF) { - if (tokensBeforeEOF == 1) - error(getCurrentLoc(), "", "premature end of input", s, ""); - } else + if (! getScanner()->atEndOfInput() || numErrors == 0) error(getCurrentLoc(), "", "", s, ""); + else + error(getCurrentLoc(), "compilation terminated", "", ""); } void TParseContext::handlePragma(const TSourceLoc& loc, const TVector& tokens) @@ -236,182 +263,14 @@ void TParseContext::handlePragma(const TSourceLoc& loc, const TVector& error(loc, "\")\" expected to end 'debug' pragma", "#pragma", ""); return; } - } -} - -/////////////////////////////////////////////////////////////////////// -// -// Sub- vector and matrix fields -// -//////////////////////////////////////////////////////////////////////// - -// -// Look at a '.' field selector string and change it into offsets -// for a vector or scalar -// -// Returns true if there is no error. -// -bool TParseContext::parseVectorFields(const TSourceLoc& loc, const TString& compString, int vecSize, TVectorFields& fields) -{ - fields.num = (int) compString.size(); - if (fields.num > 4) { - error(loc, "illegal vector field selection", compString.c_str(), ""); - return false; - } - - enum { - exyzw, - ergba, - estpq, - } fieldSet[4]; - - for (int i = 0; i < fields.num; ++i) { - switch (compString[i]) { - case 'x': - fields.offsets[i] = 0; - fieldSet[i] = exyzw; - break; - case 'r': - fields.offsets[i] = 0; - fieldSet[i] = ergba; - break; - case 's': - fields.offsets[i] = 0; - fieldSet[i] = estpq; - break; - case 'y': - fields.offsets[i] = 1; - fieldSet[i] = exyzw; - break; - case 'g': - fields.offsets[i] = 1; - fieldSet[i] = ergba; - break; - case 't': - fields.offsets[i] = 1; - fieldSet[i] = estpq; - break; - case 'z': - fields.offsets[i] = 2; - fieldSet[i] = exyzw; - break; - case 'b': - fields.offsets[i] = 2; - fieldSet[i] = ergba; - break; - case 'p': - fields.offsets[i] = 2; - fieldSet[i] = estpq; - break; - - case 'w': - fields.offsets[i] = 3; - fieldSet[i] = exyzw; - break; - case 'a': - fields.offsets[i] = 3; - fieldSet[i] = ergba; - break; - case 'q': - fields.offsets[i] = 3; - fieldSet[i] = estpq; - break; - default: - error(loc, "illegal vector field selection", compString.c_str(), ""); - return false; - } - } - - for (int i = 0; i < fields.num; ++i) { - if (fields.offsets[i] >= vecSize) { - error(loc, "vector field selection out of range", compString.c_str(), ""); - return false; - } - - if (i > 0) { - if (fieldSet[i] != fieldSet[i-1]) { - error(loc, "illegal - vector component fields not from the same set", compString.c_str(), ""); - return false; - } - } - } - - return true; -} - -/////////////////////////////////////////////////////////////////////// -// -// Errors -// -//////////////////////////////////////////////////////////////////////// - -// -// Used to output syntax, parsing, and semantic errors. -// - -void TParseContext::outputMessage(const TSourceLoc& loc, const char* szReason, - const char* szToken, - const char* szExtraInfoFormat, - TPrefixType prefix, va_list args) -{ - const int maxSize = MaxTokenLength + 200; - char szExtraInfo[maxSize]; - - safe_vsprintf(szExtraInfo, maxSize, szExtraInfoFormat, args); - - infoSink.info.prefix(prefix); - infoSink.info.location(loc); - infoSink.info << "'" << szToken << "' : " << szReason << " " << szExtraInfo << "\n"; - - if (prefix == EPrefixError) { - ++numErrors; - } -} - -void C_DECL TParseContext::error(const TSourceLoc& loc, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...) -{ - if (messages & EShMsgOnlyPreprocessor) - return; - va_list args; - va_start(args, szExtraInfoFormat); - outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args); - va_end(args); - - if ((messages & EShMsgCascadingErrors) == 0) - currentScanner->setEndOfInput(); -} - -void C_DECL TParseContext::warn(const TSourceLoc& loc, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...) -{ - if (suppressWarnings()) - return; - va_list args; - va_start(args, szExtraInfoFormat); - outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args); - va_end(args); -} - -void C_DECL TParseContext::ppError(const TSourceLoc& loc, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...) -{ - va_list args; - va_start(args, szExtraInfoFormat); - outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args); - va_end(args); - - if ((messages & EShMsgCascadingErrors) == 0) - currentScanner->setEndOfInput(); -} - -void C_DECL TParseContext::ppWarn(const TSourceLoc& loc, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...) -{ - va_list args; - va_start(args, szExtraInfoFormat); - outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args); - va_end(args); + } else if (spvVersion.spv > 0 && tokens[0].compare("use_storage_buffer") == 0) { + if (tokens.size() != 1) + error(loc, "extra tokens", "#pragma", ""); + intermediate.setUseStorageBuffer(); + } else if (tokens[0].compare("once") == 0) { + warn(loc, "not implemented", "#pragma once", ""); + } else if (tokens[0].compare("glslang_binary_double_output") == 0) + intermediate.setBinaryDoubleOutput(); } // @@ -426,15 +285,17 @@ TIntermTyped* TParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symb requireExtensions(loc, symbol->getNumExtensions(), symbol->getExtensions(), symbol->getName().c_str()); if (symbol && symbol->isReadOnly()) { - // All shared things containing an implicitly sized array must be copied up + // All shared things containing an unsized array must be copied up // on first use, so that all future references will share its array structure, // so that editing the implicit size will effect all nodes consuming it, // and so that editing the implicit size won't change the shared one. // - // If this is a variable or a block, check it and all it contains, but if this + // If this is a variable or a block, check it and all it contains, but if this // is a member of an anonymous block, check the whole block, as the whole block - // will need to be copied up if it contains an implicitly-sized array. - if (symbol->getType().containsImplicitlySizedArray() || (symbol->getAsAnonMember() && symbol->getAsAnonMember()->getAnonContainer().getType().containsImplicitlySizedArray())) + // will need to be copied up if it contains an unsized array. + if (symbol->getType().containsUnsizedArray() || + (symbol->getAsAnonMember() && + symbol->getAsAnonMember()->getAnonContainer().getType().containsUnsizedArray())) makeEditable(symbol); } @@ -496,10 +357,8 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn TIntermTyped* result = nullptr; int indexValue = 0; - if (index->getQualifier().isFrontEndConstant()) { + if (index->getQualifier().isFrontEndConstant()) indexValue = index->getAsConstantUnion()->getConstArray()[0].getIConst(); - checkIndex(loc, base->getType(), indexValue); - } variableCheck(base); if (! base->isArray() && ! base->isMatrix() && ! base->isVector()) { @@ -507,39 +366,52 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn error(loc, " left of '[' is not of type array, matrix, or vector ", base->getAsSymbolNode()->getName().c_str(), ""); else error(loc, " left of '[' is not of type array, matrix, or vector ", "expression", ""); - } else if (base->getType().getQualifier().isFrontEndConstant() && index->getQualifier().isFrontEndConstant()) + } else if (base->getType().getQualifier().isFrontEndConstant() && index->getQualifier().isFrontEndConstant()) { + // both base and index are front-end constants + checkIndex(loc, base->getType(), indexValue); return intermediate.foldDereference(base, indexValue, loc); - else { - // at least one of base and index is variable... + } else { + // at least one of base and index is not a front-end constant variable... + + if (index->getQualifier().isFrontEndConstant()) + checkIndex(loc, base->getType(), indexValue); if (base->getAsSymbolNode() && isIoResizeArray(base->getType())) handleIoResizeArrayAccess(loc, base); if (index->getQualifier().isFrontEndConstant()) { - if (base->getType().isImplicitlySizedArray()) - updateImplicitArraySize(loc, base, indexValue); + if (base->getType().isUnsizedArray()) + base->getWritableType().updateImplicitArraySize(indexValue + 1); + else + checkIndex(loc, base->getType(), indexValue); result = intermediate.addIndex(EOpIndexDirect, base, index, loc); } else { - if (base->getType().isImplicitlySizedArray()) { + if (base->getType().isUnsizedArray()) { + // we have a variable index into an unsized array, which is okay, + // depending on the situation if (base->getAsSymbolNode() && isIoResizeArray(base->getType())) error(loc, "", "[", "array must be sized by a redeclaration or layout qualifier before being indexed with a variable"); - else - error(loc, "", "[", "array must be redeclared with a size before being indexed with a variable"); + else { + // it is okay for a run-time sized array + checkRuntimeSizable(loc, *base); + } + base->getWritableType().setArrayVariablyIndexed(); } if (base->getBasicType() == EbtBlock) { if (base->getQualifier().storage == EvqBuffer) requireProfile(base->getLoc(), ~EEsProfile, "variable indexing buffer block array"); else if (base->getQualifier().storage == EvqUniform) - profileRequires(base->getLoc(), EEsProfile, 0, Num_AEP_gpu_shader5, AEP_gpu_shader5, "variable indexing uniform block array"); + profileRequires(base->getLoc(), EEsProfile, 320, Num_AEP_gpu_shader5, AEP_gpu_shader5, + "variable indexing uniform block array"); else { // input/output blocks either don't exist or can be variable indexed } } else if (language == EShLangFragment && base->getQualifier().isPipeOutput()) - requireProfile(base->getLoc(), ~EEsProfile, "variable indexing fragment shader ouput array"); + requireProfile(base->getLoc(), ~EEsProfile, "variable indexing fragment shader output array"); else if (base->getBasicType() == EbtSampler && version >= 130) { const char* explanation = "variable indexing sampler array"; requireProfile(base->getLoc(), EEsProfile | ECoreProfile | ECompatibilityProfile, explanation); - profileRequires(base->getLoc(), EEsProfile, 0, Num_AEP_gpu_shader5, AEP_gpu_shader5, explanation); + profileRequires(base->getLoc(), EEsProfile, 320, Num_AEP_gpu_shader5, AEP_gpu_shader5, explanation); profileRequires(base->getLoc(), ECoreProfile | ECompatibilityProfile, 400, nullptr, explanation); } @@ -564,6 +436,10 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn } result->setType(newType); + // Propagate nonuniform + if (base->getQualifier().isNonUniform() || index->getQualifier().isNonUniform()) + result->getWritableType().getQualifier().nonUniform = true; + if (anyIndexLimits) handleIndexLimits(loc, base, index); } @@ -571,29 +447,6 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn return result; } -void TParseContext::checkIndex(const TSourceLoc& loc, const TType& type, int& index) -{ - if (index < 0) { - error(loc, "", "[", "index out of range '%d'", index); - index = 0; - } else if (type.isArray()) { - if (type.isExplicitlySizedArray() && index >= type.getOuterArraySize()) { - error(loc, "", "[", "array index out of range '%d'", index); - index = type.getOuterArraySize() - 1; - } - } else if (type.isVector()) { - if (index >= type.getVectorSize()) { - error(loc, "", "[", "vector index out of range '%d'", index); - index = type.getVectorSize() - 1; - } - } else if (type.isMatrix()) { - if (index >= type.getMatrixCols()) { - error(loc, "", "[", "matrix index out of range '%d'", index); - index = type.getMatrixCols() - 1; - } - } -} - // for ES 2.0 (version 100) limitations for almost all index operations except vertex-shader uniforms void TParseContext::handleIndexLimits(const TSourceLoc& /*loc*/, TIntermTyped* base, TIntermTyped* index) { @@ -612,40 +465,16 @@ void TParseContext::handleIndexLimits(const TSourceLoc& /*loc*/, TIntermTyped* b } } -// Make a shared symbol have a non-shared version that can be edited by the current +// Make a shared symbol have a non-shared version that can be edited by the current // compile, such that editing its type will not change the shared version and will // effect all nodes sharing it. void TParseContext::makeEditable(TSymbol*& symbol) { - // copyUp() does a deep copy of the type. - symbol = symbolTable.copyUp(symbol); + TParseContextBase::makeEditable(symbol); - // Also, see if it's tied to IO resizing + // See if it's tied to IO resizing if (isIoResizeArray(symbol->getType())) ioArraySymbolResizeList.push_back(symbol); - - // Also, save it in the AST for linker use. - intermediate.addSymbolLinkageNode(linkage, *symbol); -} - -// Return a writable version of the variable 'name'. -// -// Return nullptr if 'name' is not found. This should mean -// something is seriously wrong (e.g., compiler asking self for -// built-in that doesn't exist). -TVariable* TParseContext::getEditableVariable(const char* name) -{ - bool builtIn; - TSymbol* symbol = symbolTable.find(name, &builtIn); - - assert(symbol != nullptr); - if (symbol == nullptr) - return nullptr; - - if (builtIn) - makeEditable(symbol); - - return symbol->getAsVariable(); } // Return true if this is a geometry shader input array or tessellation control output array. @@ -669,7 +498,7 @@ void TParseContext::fixIoArraySize(const TSourceLoc& loc, TType& type) if (language == EShLangTessControl || language == EShLangTessEvaluation) { if (type.getOuterArraySize() != resources.maxPatchVertices) { - if (type.isExplicitlySizedArray()) + if (type.isSizedArray()) error(loc, "tessellation input array size must be gl_MaxPatchVertices or implicitly sized", "[]", ""); type.changeOuterArraySize(resources.maxPatchVertices); } @@ -678,11 +507,15 @@ void TParseContext::fixIoArraySize(const TSourceLoc& loc, TType& type) // Issue any errors if the non-array object is missing arrayness WRT // shader I/O that has array requirements. -// All arrayness checking is handled in array paths, this is for +// All arrayness checking is handled in array paths, this is for void TParseContext::ioArrayCheck(const TSourceLoc& loc, const TType& type, const TString& identifier) { if (! type.isArray() && ! symbolTable.atBuiltInLevel()) { - if (type.getQualifier().isArrayedIo(language)) + if (type.getQualifier().isArrayedIo(language) +#ifdef NV_EXTENSIONS + && !type.getQualifier().layoutPassthrough +#endif + ) error(loc, "type must be an array:", type.getStorageQualifierString(), identifier.c_str()); } } @@ -698,7 +531,7 @@ void TParseContext::handleIoResizeArrayAccess(const TSourceLoc& /*loc*/, TInterm return; // fix array size, if it can be fixed and needs to be fixed (will allow variable indexing) - if (symbolNode->getType().isImplicitlySizedArray()) { + if (symbolNode->getType().isUnsizedArray()) { int newSize = getIoArrayImplicitSize(); if (newSize > 0) symbolNode->getWritableType().changeOuterArraySize(newSize); @@ -707,7 +540,7 @@ void TParseContext::handleIoResizeArrayAccess(const TSourceLoc& /*loc*/, TInterm // If there has been an input primitive declaration (geometry shader) or an output // number of vertices declaration(tessellation shader), make sure all input array types -// match it in size. Types come either from nodes in the AST or symbols in the +// match it in size. Types come either from nodes in the AST or symbols in the // symbol table. // // Types without an array size will be given one. @@ -748,7 +581,7 @@ int TParseContext::getIoArrayImplicitSize() const void TParseContext::checkIoArrayConsistency(const TSourceLoc& loc, int requiredSize, const char* feature, TType& type, const TString& name) { - if (type.isImplicitlySizedArray()) + if (type.isUnsizedArray()) type.changeOuterArraySize(requiredSize); else if (type.getOuterArraySize() != requiredSize) { if (language == EShLangGeometry) @@ -761,13 +594,32 @@ void TParseContext::checkIoArrayConsistency(const TSourceLoc& loc, int requiredS } // Handle seeing a binary node with a math operation. +// Returns nullptr if not semantically allowed. TIntermTyped* TParseContext::handleBinaryMath(const TSourceLoc& loc, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right) { rValueErrorCheck(loc, str, left->getAsTyped()); rValueErrorCheck(loc, str, right->getAsTyped()); - TIntermTyped* result = intermediate.addBinaryMath(op, left, right, loc); - if (! result) + bool allowed = true; + switch (op) { + // TODO: Bring more source language-specific checks up from intermediate.cpp + // to the specific parse helpers for that source language. + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + if (! left->isScalar() || ! right->isScalar()) + allowed = false; + break; + default: + break; + } + + TIntermTyped* result = nullptr; + if (allowed) + result = intermediate.addBinaryMath(op, left, right, loc); + + if (result == nullptr) binaryOpError(loc, str, left->getCompleteString(), right->getCompleteString()); return result; @@ -784,7 +636,7 @@ TIntermTyped* TParseContext::handleUnaryMath(const TSourceLoc& loc, const char* return result; else unaryOpError(loc, str, childNode->getCompleteString()); - + return childNode; } @@ -797,7 +649,7 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm // // .length() can't be resolved until we later see the function-calling syntax. - // Save away the name in the AST for now. Processing is completed in + // Save away the name in the AST for now. Processing is completed in // handleLengthMethod(). // if (field == "length") { @@ -829,43 +681,40 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm // leaving swizzles and struct/block dereferences. TIntermTyped* result = base; - if (base->isVector() || base->isScalar()) { + if ((base->isVector() || base->isScalar()) && + (base->isFloatingDomain() || base->isIntegerDomain() || base->getBasicType() == EbtBool)) { if (base->isScalar()) { const char* dotFeature = "scalar swizzle"; requireProfile(loc, ~EEsProfile, dotFeature); profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, dotFeature); } - TVectorFields fields; - if (! parseVectorFields(loc, field, base->getVectorSize(), fields)) { - fields.num = 1; - fields.offsets[0] = 0; - } + TSwizzleSelectors selectors; + parseSwizzleSelector(loc, field, base->getVectorSize(), selectors); if (base->isScalar()) { - if (fields.num == 1) + if (selectors.size() == 1) return result; else { - TType type(base->getBasicType(), EvqTemporary, fields.num); + TType type(base->getBasicType(), EvqTemporary, selectors.size()); // Swizzle operations propagate specialization-constantness if (base->getQualifier().isSpecConstant()) type.getQualifier().makeSpecConstant(); - return addConstructor(loc, base, type, mapTypeToConstructorOp(type)); + return addConstructor(loc, base, type); } } if (base->getType().getQualifier().isFrontEndConstant()) - result = intermediate.foldSwizzle(base, fields, loc); + result = intermediate.foldSwizzle(base, selectors, loc); else { - if (fields.num == 1) { - TIntermTyped* index = intermediate.addConstantUnion(fields.offsets[0], loc); + if (selectors.size() == 1) { + TIntermTyped* index = intermediate.addConstantUnion(selectors[0], loc); result = intermediate.addIndex(EOpIndexDirect, base, index, loc); result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision)); } else { - TString vectorString = field; - TIntermTyped* index = intermediate.addSwizzle(fields, loc); + TIntermTyped* index = intermediate.addSwizzle(selectors, loc); result = intermediate.addIndex(EOpVectorSwizzle, base, index, loc); - result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision, (int) vectorString.size())); + result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision, selectors.size())); } // Swizzle operations propagate specialization-constantness if (base->getType().getQualifier().isSpecConstant()) @@ -899,6 +748,10 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm if (base->getQualifier().noContraction) result->getWritableType().getQualifier().noContraction = true; + // Propagate nonuniform + if (base->getQualifier().isNonUniform()) + result->getWritableType().getQualifier().nonUniform = true; + return result; } @@ -943,7 +796,7 @@ TFunction* TParseContext::handleFunctionDeclarator(const TSourceLoc& loc, TFunct if (prevDec->isPrototyped() && prototype) profileRequires(loc, EEsProfile, 300, nullptr, "multiple prototypes for same function"); if (prevDec->getType() != function.getType()) - error(loc, "overloaded functions must have the same return type", function.getType().getBasicTypeString().c_str(), ""); + error(loc, "overloaded functions must have the same return type", function.getName().c_str(), ""); for (int i = 0; i < prevDec->getParamCount(); ++i) { if ((*prevDec)[i].type->getQualifier().storage != function[i].type->getQualifier().storage) error(loc, "overloaded functions must have the same parameter storage qualifiers for argument", function[i].type->getStorageQualifierString(), "%d", i+1); @@ -961,7 +814,7 @@ TFunction* TParseContext::handleFunctionDeclarator(const TSourceLoc& loc, TFunct if (symbolTable.atBuiltInLevel()) function.setDefined(); else { - if (prevDec && ! builtIn) + if (prevDec && ! builtIn) symbol->getAsFunction()->setPrototyped(); // need a writable one, but like having prevDec as a const function.setPrototyped(); } @@ -981,7 +834,7 @@ TFunction* TParseContext::handleFunctionDeclarator(const TSourceLoc& loc, TFunct } // -// Handle seeing the function prototype in front of a function definition in the grammar. +// Handle seeing the function prototype in front of a function definition in the grammar. // The body is handled after this function returns. // TIntermAggregate* TParseContext::handleFunctionDefinition(const TSourceLoc& loc, TFunction& function) @@ -994,7 +847,7 @@ TIntermAggregate* TParseContext::handleFunctionDefinition(const TSourceLoc& loc, error(loc, "can't find function", function.getName().c_str(), ""); // Note: 'prevDec' could be 'function' if this is the first time we've seen function // as it would have just been put in the symbol table. Otherwise, we're looking up - // an earlier occurance. + // an earlier occurrence. if (prevDec && prevDec->isDefined()) { // Then this function already has a body. @@ -1009,19 +862,24 @@ TIntermAggregate* TParseContext::handleFunctionDefinition(const TSourceLoc& loc, currentFunctionType = new TType(EbtVoid); functionReturnsValue = false; - // - // Raise error message if main function takes any parameters or returns anything other than void - // - if (function.getName() == intermediate.getEntryPoint().c_str()) { - if (function.getParamCount() > 0) - error(loc, "function cannot take any parameter(s)", function.getName().c_str(), ""); - if (function.getType().getBasicType() != EbtVoid) - error(loc, "", function.getType().getBasicTypeString().c_str(), "main function cannot return a value"); - intermediate.addMainCount(); + // Check for entry point + if (function.getName().compare(intermediate.getEntryPointName().c_str()) == 0) { + intermediate.setEntryPointMangledName(function.getMangledName().c_str()); + intermediate.incrementEntryPointCount(); inMain = true; } else inMain = false; + // + // Raise error message if main function takes any parameters or returns anything other than void + // + if (inMain) { + if (function.getParamCount() > 0) + error(loc, "function cannot take any parameter(s)", function.getName().c_str(), ""); + if (function.getType().getBasicType() != EbtVoid) + error(loc, "", function.getType().getBasicTypeString().c_str(), "entry point cannot return a value"); + } + // // New symbol table scope for body of function plus its arguments // @@ -1060,7 +918,7 @@ TIntermAggregate* TParseContext::handleFunctionDefinition(const TSourceLoc& loc, loopNestingLevel = 0; statementNestingLevel = 0; controlFlowNestingLevel = 0; - postMainReturn = false; + postEntryPointReturn = false; return paramNodes; } @@ -1078,21 +936,20 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction { TIntermTyped* result = nullptr; - TOperator op = function->getBuiltInOp(); - if (op == EOpArrayLength) + if (function->getBuiltInOp() == EOpArrayLength) result = handleLengthMethod(loc, function, arguments); - else if (op != EOpNull) { + else if (function->getBuiltInOp() != EOpNull) { // // Then this should be a constructor. // Don't go through the symbol table for constructors. // Their parameters will be verified algorithmically. // TType type(EbtVoid); // use this to get the type back - if (! constructorError(loc, arguments, *function, op, type)) { + if (! constructorError(loc, arguments, *function, function->getBuiltInOp(), type)) { // // It's a constructor, of type 'type'. // - result = addConstructor(loc, arguments, type, op); + result = addConstructor(loc, arguments, type); if (result == nullptr) error(loc, "cannot construct with these arguments", type.getCompleteString().c_str(), ""); } @@ -1113,7 +970,7 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction if (builtIn && fnCandidate->getNumExtensions()) requireExtensions(loc, fnCandidate->getNumExtensions(), fnCandidate->getExtensions(), fnCandidate->getName().c_str()); - if (arguments) { + if (arguments != nullptr) { // Make sure qualifications work for these arguments. TIntermAggregate* aggregate = arguments->getAsAggregate(); for (int i = 0; i < fnCandidate->getParamCount(); ++i) { @@ -1122,7 +979,7 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction // means take 'arguments' itself as the one argument. TIntermNode* arg = fnCandidate->getParamCount() == 1 ? arguments : (aggregate ? aggregate->getSequence()[i] : arguments); TQualifier& formalQualifier = (*fnCandidate)[i].type->getQualifier(); - if (formalQualifier.storage == EvqOut || formalQualifier.storage == EvqInOut) { + if (formalQualifier.isParamOutput()) { if (lValueErrorCheck(arguments->getLoc(), "assign", arg->getAsTyped())) error(arguments->getLoc(), "Non-L-value cannot be passed for 'out' or 'inout' parameters.", "out", ""); } @@ -1138,10 +995,10 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction if (argQualifier.writeonly && ! formalQualifier.writeonly) error(arguments->getLoc(), message, "writeonly", ""); } - // TODO 4.5 functionality: A shader will fail to compile + // TODO 4.5 functionality: A shader will fail to compile // if the value passed to the memargument of an atomic memory function does not correspond to a buffer or - // shared variable. It is acceptable to pass an element of an array or a single component of a vector to the - // memargument of an atomic memory function, as long as the underlying array or vector is a buffer or + // shared variable. It is acceptable to pass an element of an array or a single component of a vector to the + // memargument of an atomic memory function, as long as the underlying array or vector is a buffer or // shared variable. } @@ -1149,18 +1006,9 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction addInputArgumentConversions(*fnCandidate, arguments); // arguments may be modified if it's just a single argument node } - op = fnCandidate->getBuiltInOp(); - if (builtIn && op != EOpNull) { + if (builtIn && fnCandidate->getBuiltInOp() != EOpNull) { // A function call mapped to a built-in operation. - checkLocation(loc, op); - result = intermediate.addBuiltInFunctionCall(loc, op, fnCandidate->getParamCount() == 1, arguments, fnCandidate->getType()); - if (result == nullptr) { - error(arguments->getLoc(), " wrong operand type", "Internal Error", - "built in unary operator function. Type: %s", - static_cast(arguments)->getCompleteString().c_str()); - } else if (result->getAsOperator()) { - builtInOpCheck(loc, *fnCandidate, *result->getAsOperator()); - } + result = handleBuiltInFunctionCall(loc, arguments, *fnCandidate); } else { // This is a function call not mapped to built-in operator. // It could still be a built-in function, but only if PureOperatorBuiltins == false. @@ -1173,14 +1021,17 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction // if builtIn == true, it's definitely a built-in function with EOpNull if (! builtIn) { call->setUserDefined(); - if (symbolTable.atGlobalLevel()) - error(loc, "can't call user function from global scope", fnCandidate->getName().c_str(), ""); - else + if (symbolTable.atGlobalLevel()) { + requireProfile(loc, ~EEsProfile, "calling user function from global scope"); + intermediate.addToCallGraph(infoSink, "main(", fnCandidate->getMangledName()); + } else intermediate.addToCallGraph(infoSink, currentCaller, fnCandidate->getMangledName()); } if (builtIn) nonOpBuiltInCheck(loc, *fnCandidate, *call); + else + userFunctionCallCheck(loc, *call); } // Convert 'out' arguments. If it was a constant folded built-in, it won't be an aggregate anymore. @@ -1205,6 +1056,127 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction return result; } +TIntermTyped* TParseContext::handleBuiltInFunctionCall(TSourceLoc loc, TIntermNode* arguments, + const TFunction& function) +{ + checkLocation(loc, function.getBuiltInOp()); + TIntermTyped *result = intermediate.addBuiltInFunctionCall(loc, function.getBuiltInOp(), + function.getParamCount() == 1, + arguments, function.getType()); + if (obeyPrecisionQualifiers()) + computeBuiltinPrecisions(*result, function); + + if (result == nullptr) { + if (arguments == nullptr) + error(loc, " wrong operand type", "Internal Error", + "built in unary operator function. Type: %s", ""); + else + error(arguments->getLoc(), " wrong operand type", "Internal Error", + "built in unary operator function. Type: %s", + static_cast(arguments)->getCompleteString().c_str()); + } else if (result->getAsOperator()) + builtInOpCheck(loc, function, *result->getAsOperator()); + + return result; +} + +// "The operation of a built-in function can have a different precision +// qualification than the precision qualification of the resulting value. +// These two precision qualifications are established as follows. +// +// The precision qualification of the operation of a built-in function is +// based on the precision qualification of its input arguments and formal +// parameters: When a formal parameter specifies a precision qualifier, +// that is used, otherwise, the precision qualification of the calling +// argument is used. The highest precision of these will be the precision +// qualification of the operation of the built-in function. Generally, +// this is applied across all arguments to a built-in function, with the +// exceptions being: +// - bitfieldExtract and bitfieldInsert ignore the 'offset' and 'bits' +// arguments. +// - interpolateAt* functions only look at the 'interpolant' argument. +// +// The precision qualification of the result of a built-in function is +// determined in one of the following ways: +// +// - For the texture sampling, image load, and image store functions, +// the precision of the return type matches the precision of the +// sampler type +// +// Otherwise: +// +// - For prototypes that do not specify a resulting precision qualifier, +// the precision will be the same as the precision of the operation. +// +// - For prototypes that do specify a resulting precision qualifier, +// the specified precision qualifier is the precision qualification of +// the result." +// +void TParseContext::computeBuiltinPrecisions(TIntermTyped& node, const TFunction& function) +{ + TPrecisionQualifier operationPrecision = EpqNone; + TPrecisionQualifier resultPrecision = EpqNone; + + TIntermOperator* opNode = node.getAsOperator(); + if (opNode == nullptr) + return; + + if (TIntermUnary* unaryNode = node.getAsUnaryNode()) { + operationPrecision = std::max(function[0].type->getQualifier().precision, + unaryNode->getOperand()->getType().getQualifier().precision); + if (function.getType().getBasicType() != EbtBool) + resultPrecision = function.getType().getQualifier().precision == EpqNone ? + operationPrecision : + function.getType().getQualifier().precision; + } else if (TIntermAggregate* agg = node.getAsAggregate()) { + TIntermSequence& sequence = agg->getSequence(); + unsigned int numArgs = (unsigned int)sequence.size(); + switch (agg->getOp()) { + case EOpBitfieldExtract: + numArgs = 1; + break; + case EOpBitfieldInsert: + numArgs = 2; + break; + case EOpInterpolateAtCentroid: + case EOpInterpolateAtOffset: + case EOpInterpolateAtSample: + numArgs = 1; + break; + default: + break; + } + // find the maximum precision from the arguments and parameters + for (unsigned int arg = 0; arg < numArgs; ++arg) { + operationPrecision = std::max(operationPrecision, sequence[arg]->getAsTyped()->getQualifier().precision); + operationPrecision = std::max(operationPrecision, function[arg].type->getQualifier().precision); + } + // compute the result precision +#ifdef AMD_EXTENSIONS + if (agg->isSampling() || + agg->getOp() == EOpImageLoad || agg->getOp() == EOpImageStore || + agg->getOp() == EOpImageLoadLod || agg->getOp() == EOpImageStoreLod) +#else + if (agg->isSampling() || agg->getOp() == EOpImageLoad || agg->getOp() == EOpImageStore) +#endif + resultPrecision = sequence[0]->getAsTyped()->getQualifier().precision; + else if (function.getType().getBasicType() != EbtBool) + resultPrecision = function.getType().getQualifier().precision == EpqNone ? + operationPrecision : + function.getType().getQualifier().precision; + } + + // Propagate precision through this node and its children. That algorithm stops + // when a precision is found, so start by clearing this subroot precision + opNode->getQualifier().precision = EpqNone; + if (operationPrecision != EpqNone) { + opNode->propagatePrecision(operationPrecision); + opNode->setOperationPrecision(operationPrecision); + } + // Now, set the result precision, which might not match + opNode->getQualifier().precision = resultPrecision; +} + TIntermNode* TParseContext::handleReturnValue(const TSourceLoc& loc, TIntermTyped* value) { functionReturnsValue = true; @@ -1237,7 +1209,7 @@ void TParseContext::checkLocation(const TSourceLoc& loc, TOperator op) error(loc, "tessellation control barrier() cannot be placed within flow control", "", ""); if (! inMain) error(loc, "tessellation control barrier() must be in main()", "", ""); - else if (postMainReturn) + else if (postEntryPointReturn) error(loc, "tessellation control barrier() cannot be placed after a return from main()", "", ""); } break; @@ -1247,7 +1219,7 @@ void TParseContext::checkLocation(const TSourceLoc& loc, TOperator op) } // Finish processing object.length(). This started earlier in handleDotDereference(), where -// the ".length" part was recognized and semantically checked, and finished here where the +// the ".length" part was recognized and semantically checked, and finished here where the // function syntax "()" is recognized. // // Return resulting tree node. @@ -1260,13 +1232,10 @@ TIntermTyped* TParseContext::handleLengthMethod(const TSourceLoc& loc, TFunction else { const TType& type = intermNode->getAsTyped()->getType(); if (type.isArray()) { - if (type.isRuntimeSizedArray()) { - // Create a unary op and let the back end handle it - return intermediate.addBuiltInFunctionCall(loc, EOpArrayLength, true, intermNode, TType(EbtInt)); - } else if (type.isImplicitlySizedArray()) { + if (type.isUnsizedArray()) { if (intermNode->getAsSymbolNode() && isIoResizeArray(type)) { - // We could be between a layout declaration that gives a built-in io array implicit size and - // a user redeclaration of that array, meaning we have to substitute its implicit size here + // We could be between a layout declaration that gives a built-in io array implicit size and + // a user redeclaration of that array, meaning we have to substitute its implicit size here // without actually redeclaring the array. (It is an error to use a member before the // redeclaration, but not an error to use the array name itself.) const TString& name = intermNode->getAsSymbolNode()->getName(); @@ -1276,7 +1245,10 @@ TIntermTyped* TParseContext::handleLengthMethod(const TSourceLoc& loc, TFunction if (length == 0) { if (intermNode->getAsSymbolNode() && isIoResizeArray(type)) error(loc, "", function->getName().c_str(), "array must first be sized by a redeclaration or layout qualifier"); - else + else if (isRuntimeLength(*intermNode->getAsTyped())) { + // Create a unary op and let the back end handle it + return intermediate.addBuiltInFunctionCall(loc, EOpArrayLength, true, intermNode, TType(EbtInt)); + } else error(loc, "", function->getName().c_str(), "array must be declared with a size before using this method"); } } else if (type.getOuterArrayNode()) { @@ -1349,7 +1321,7 @@ TIntermTyped* TParseContext::addOutputArgumentConversions(const TFunction& funct // Will there be any output conversions? bool outputConversions = false; for (int i = 0; i < function.getParamCount(); ++i) { - if (*function[i].type != arguments[i]->getAsTyped()->getType() && function[i].type->getQualifier().storage == EvqOut) { + if (*function[i].type != arguments[i]->getAsTyped()->getType() && function[i].type->getQualifier().isParamOutput()) { outputConversions = true; break; } @@ -1429,13 +1401,9 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan unaryArg = callNode.getAsUnaryNode()->getOperand(); arg0 = unaryArg; } - const TIntermSequence& aggArgs = *argp; // only valid when unaryArg is nullptr - - // built-in texturing functions get their return value precision from the precision of the sampler - if (fnCandidate.getType().getQualifier().precision == EpqNone && - fnCandidate.getParamCount() > 0 && fnCandidate[0].type->getBasicType() == EbtSampler) - callNode.getQualifier().precision = arg0->getQualifier().precision; + TString featureString; + const char* feature = nullptr; switch (callNode.getOp()) { case EOpTextureGather: case EOpTextureGatherOffset: @@ -1444,8 +1412,9 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan // Figure out which variants are allowed by what extensions, // and what arguments must be constant for which situations. - TString featureString = fnCandidate.getName() + "(...)"; - const char* feature = featureString.c_str(); + featureString = fnCandidate.getName(); + featureString += "(...)"; + feature = featureString.c_str(); profileRequires(loc, EEsProfile, 310, nullptr, feature); int compArg = -1; // track which argument, if any, is the constant component argument switch (callNode.getOp()) { @@ -1465,8 +1434,9 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_texture_gather, feature); else profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature); - if (! aggArgs[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion()) - profileRequires(loc, EEsProfile, 0, Num_AEP_gpu_shader5, AEP_gpu_shader5, "non-constant offset argument"); + if (! (*argp)[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion()) + profileRequires(loc, EEsProfile, 320, Num_AEP_gpu_shader5, AEP_gpu_shader5, + "non-constant offset argument"); if (! fnCandidate[0].type->getSampler().shadow) compArg = 3; break; @@ -1475,7 +1445,7 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan if (! fnCandidate[0].type->getSampler().shadow) compArg = 3; // check for constant offsets - if (! aggArgs[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion()) + if (! (*argp)[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion()) error(loc, "must be a compile-time constant:", feature, "offsets argument"); break; default: @@ -1483,17 +1453,99 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan } if (compArg > 0 && compArg < fnCandidate.getParamCount()) { - if (aggArgs[compArg]->getAsConstantUnion()) { - int value = aggArgs[compArg]->getAsConstantUnion()->getConstArray()[0].getIConst(); + if ((*argp)[compArg]->getAsConstantUnion()) { + int value = (*argp)[compArg]->getAsConstantUnion()->getConstArray()[0].getIConst(); if (value < 0 || value > 3) error(loc, "must be 0, 1, 2, or 3:", feature, "component argument"); } else error(loc, "must be a compile-time constant:", feature, "component argument"); } +#ifdef AMD_EXTENSIONS + bool bias = false; + if (callNode.getOp() == EOpTextureGather) + bias = fnCandidate.getParamCount() > 3; + else if (callNode.getOp() == EOpTextureGatherOffset || + callNode.getOp() == EOpTextureGatherOffsets) + bias = fnCandidate.getParamCount() > 4; + + if (bias) { + featureString = fnCandidate.getName(); + featureString += "with bias argument"; + feature = featureString.c_str(); + profileRequires(loc, ~EEsProfile, 450, nullptr, feature); + requireExtensions(loc, 1, &E_GL_AMD_texture_gather_bias_lod, feature); + } +#endif + break; } +#ifdef AMD_EXTENSIONS + case EOpSparseTextureGather: + case EOpSparseTextureGatherOffset: + case EOpSparseTextureGatherOffsets: + { + bool bias = false; + if (callNode.getOp() == EOpSparseTextureGather) + bias = fnCandidate.getParamCount() > 4; + else if (callNode.getOp() == EOpSparseTextureGatherOffset || + callNode.getOp() == EOpSparseTextureGatherOffsets) + bias = fnCandidate.getParamCount() > 5; + + if (bias) { + featureString = fnCandidate.getName(); + featureString += "with bias argument"; + feature = featureString.c_str(); + profileRequires(loc, ~EEsProfile, 450, nullptr, feature); + requireExtensions(loc, 1, &E_GL_AMD_texture_gather_bias_lod, feature); + } + + break; + } + + case EOpSparseTextureGatherLod: + case EOpSparseTextureGatherLodOffset: + case EOpSparseTextureGatherLodOffsets: + { + requireExtensions(loc, 1, &E_GL_ARB_sparse_texture2, fnCandidate.getName().c_str()); + break; + } + + case EOpSwizzleInvocations: + { + if (! (*argp)[1]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "offset", ""); + else { + unsigned offset[4] = {}; + offset[0] = (*argp)[1]->getAsConstantUnion()->getConstArray()[0].getUConst(); + offset[1] = (*argp)[1]->getAsConstantUnion()->getConstArray()[1].getUConst(); + offset[2] = (*argp)[1]->getAsConstantUnion()->getConstArray()[2].getUConst(); + offset[3] = (*argp)[1]->getAsConstantUnion()->getConstArray()[3].getUConst(); + if (offset[0] > 3 || offset[1] > 3 || offset[2] > 3 || offset[3] > 3) + error(loc, "components must be in the range [0, 3]", "offset", ""); + } + + break; + } + + case EOpSwizzleInvocationsMasked: + { + if (! (*argp)[1]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "mask", ""); + else { + unsigned mask[3] = {}; + mask[0] = (*argp)[1]->getAsConstantUnion()->getConstArray()[0].getUConst(); + mask[1] = (*argp)[1]->getAsConstantUnion()->getConstArray()[1].getUConst(); + mask[2] = (*argp)[1]->getAsConstantUnion()->getConstArray()[2].getUConst(); + if (mask[0] > 31 || mask[1] > 31 || mask[2] > 31) + error(loc, "components must be in the range [0, 31]", "mask", ""); + } + + break; + } +#endif + case EOpTextureOffset: case EOpTextureFetchOffset: case EOpTextureProjOffset: @@ -1519,12 +1571,18 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan } if (arg > 0) { - if (! aggArgs[arg]->getAsConstantUnion()) + +#ifdef AMD_EXTENSIONS + bool f16ShadowCompare = (*argp)[1]->getAsTyped()->getBasicType() == EbtFloat16 && arg0->getType().getSampler().shadow; + if (f16ShadowCompare) + ++arg; +#endif + if (! (*argp)[arg]->getAsConstantUnion()) error(loc, "argument must be compile-time constant", "texel offset", ""); else { - const TType& type = aggArgs[arg]->getAsTyped()->getType(); + const TType& type = (*argp)[arg]->getAsTyped()->getType(); for (int c = 0; c < type.getVectorSize(); ++c) { - int offset = aggArgs[arg]->getAsConstantUnion()->getConstArray()[c].getIConst(); + int offset = (*argp)[arg]->getAsConstantUnion()->getConstArray()[c].getIConst(); if (offset > resources.maxProgramTexelOffset || offset < resources.minProgramTexelOffset) error(loc, "value is out of range:", "texel offset", "[gl_MinProgramTexelOffset, gl_MaxProgramTexelOffset]"); } @@ -1555,7 +1613,7 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan if (imageType.getQualifier().layoutFormat != ElfR32i && imageType.getQualifier().layoutFormat != ElfR32ui) error(loc, "only supported on image with format r32i or r32ui", fnCandidate.getName().c_str(), ""); } else { - if (fnCandidate.getName().compare(0, 19, "imageAtomicExchange") != 0) + if (fnCandidate.getName().compare(0, 19, "imageAtomicExchange") != 0) error(loc, "only supported on integer images", fnCandidate.getName().c_str(), ""); else if (imageType.getQualifier().layoutFormat != ElfR32f && profile == EEsProfile) error(loc, "only supported on image with format r32f", fnCandidate.getName().c_str(), ""); @@ -1564,14 +1622,29 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan break; } +#ifdef NV_EXTENSIONS + case EOpAtomicAdd: + case EOpAtomicMin: + case EOpAtomicMax: + case EOpAtomicAnd: + case EOpAtomicOr: + case EOpAtomicXor: + case EOpAtomicExchange: + case EOpAtomicCompSwap: + { + if (arg0->getType().getBasicType() == EbtInt64 || arg0->getType().getBasicType() == EbtUint64) + requireExtensions(loc, 1, &E_GL_NV_shader_atomic_int64, fnCandidate.getName().c_str()); + + break; + } +#endif + case EOpInterpolateAtCentroid: case EOpInterpolateAtSample: case EOpInterpolateAtOffset: - // "For the interpolateAt* functions, the call will return a precision - // qualification matching the precision of the 'interpolant' argument to - // the function call." - callNode.getQualifier().precision = arg0->getQualifier().precision; - +#ifdef AMD_EXTENSIONS + case EOpInterpolateAtVertex: +#endif // Make sure the first argument is an interpolant, or an array element of an interpolant if (arg0->getType().getQualifier().storage != EvqVaryingIn) { // It might still be an array element. @@ -1586,6 +1659,23 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan if (base == nullptr || base->getType().getQualifier().storage != EvqVaryingIn) error(loc, "first argument must be an interpolant, or interpolant-array element", fnCandidate.getName().c_str(), ""); } + +#ifdef AMD_EXTENSIONS + if (callNode.getOp() == EOpInterpolateAtVertex) { + if (!arg0->getType().getQualifier().isExplicitInterpolation()) + error(loc, "argument must be qualified as __explicitInterpAMD in", "interpolant", ""); + else { + if (! (*argp)[1]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "vertex index", ""); + else { + unsigned vertexIdx = (*argp)[1]->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (vertexIdx > 2) + error(loc, "must be in the range [0, 2]", "vertex index", ""); + } + } + } +#endif + break; case EOpEmitStreamVertex: @@ -1593,9 +1683,33 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan intermediate.setMultiStream(); break; + case EOpSubgroupClusteredAdd: + case EOpSubgroupClusteredMul: + case EOpSubgroupClusteredMin: + case EOpSubgroupClusteredMax: + case EOpSubgroupClusteredAnd: + case EOpSubgroupClusteredOr: + case EOpSubgroupClusteredXor: + if ((*argp)[1]->getAsConstantUnion() == nullptr) + error(loc, "argument must be compile-time constant", "cluster size", ""); + else { + int size = (*argp)[1]->getAsConstantUnion()->getConstArray()[0].getIConst(); + if (size < 1) + error(loc, "argument must be at least 1", "cluster size", ""); + else if (!IsPow2(size)) + error(loc, "argument must be a power of 2", "cluster size", ""); + } + break; + default: break; } + + if (callNode.getOp() > EOpSubgroupGuardStart && callNode.getOp() < EOpSubgroupGuardStop) { + // these require SPIR-V 1.3 + if (spvVersion.spv > 0 && spvVersion.spv < EShTargetSpv_1_3) + error(loc, "requires SPIR-V 1.3", "subgroup op", ""); + } } extern bool PureOperatorBuiltins; @@ -1610,7 +1724,7 @@ extern bool PureOperatorBuiltins; // void TParseContext::nonOpBuiltInCheck(const TSourceLoc& loc, const TFunction& fnCandidate, TIntermAggregate& callNode) { - // Further maintenance of this function is deprecated, because the "correct" + // Further maintenance of this function is deprecated, because the "correct" // future-oriented design is to not have to do string compares on function names. // If PureOperatorBuiltins == true, then all built-ins should be mapped @@ -1638,7 +1752,8 @@ void TParseContext::nonOpBuiltInCheck(const TSourceLoc& loc, const TFunction& fn profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature); int offsetArg = fnCandidate[0].type->getSampler().shadow ? 3 : 2; if (! callNode.getSequence()[offsetArg]->getAsConstantUnion()) - profileRequires(loc, EEsProfile, 0, Num_AEP_gpu_shader5, AEP_gpu_shader5, "non-constant offset argument"); + profileRequires(loc, EEsProfile, 320, Num_AEP_gpu_shader5, AEP_gpu_shader5, + "non-constant offset argument"); if (! fnCandidate[0].type->getSampler().shadow) compArg = 3; } else if (fnCandidate.getName().compare("textureGatherOffsets") == 0) { @@ -1715,7 +1830,7 @@ void TParseContext::nonOpBuiltInCheck(const TSourceLoc& loc, const TFunction& fn if (imageType.getQualifier().layoutFormat != ElfR32i && imageType.getQualifier().layoutFormat != ElfR32ui) error(loc, "only supported on image with format r32i or r32ui", fnCandidate.getName().c_str(), ""); } else { - if (fnCandidate.getName().compare(0, 19, "imageAtomicExchange") != 0) + if (fnCandidate.getName().compare(0, 19, "imageAtomicExchange") != 0) error(loc, "only supported on integer images", fnCandidate.getName().c_str(), ""); else if (imageType.getQualifier().layoutFormat != ElfR32f && profile == EEsProfile) error(loc, "only supported on image with format r32f", fnCandidate.getName().c_str(), ""); @@ -1723,6 +1838,26 @@ void TParseContext::nonOpBuiltInCheck(const TSourceLoc& loc, const TFunction& fn } } +// +// Do any extra checking for a user function call. +// +void TParseContext::userFunctionCallCheck(const TSourceLoc& loc, TIntermAggregate& callNode) +{ + TIntermSequence& arguments = callNode.getSequence(); + + for (int i = 0; i < (int)arguments.size(); ++i) + samplerConstructorLocationCheck(loc, "call argument", arguments[i]); +} + +// +// Emit an error if this is a sampler constructor +// +void TParseContext::samplerConstructorLocationCheck(const TSourceLoc& loc, const char* token, TIntermNode* node) +{ + if (node->getAsOperator() && node->getAsOperator()->getOp() == EOpConstructTextureSampler) + error(loc, "sampler constructor must appear at point of use", token, ""); +} + // // Handle seeing a built-in constructor in a grammar production. // @@ -1736,7 +1871,7 @@ TFunction* TParseContext::handleConstructorCall(const TSourceLoc& loc, const TPu profileRequires(loc, EEsProfile, 300, nullptr, "arrayed constructor"); } - TOperator op = mapTypeToConstructorOp(type); + TOperator op = intermediate.mapTypeToConstructorOp(type); if (op == EOpNull) { error(loc, "cannot construct this type", type.getBasicString(), ""); @@ -1750,148 +1885,22 @@ TFunction* TParseContext::handleConstructorCall(const TSourceLoc& loc, const TPu return new TFunction(&empty, type, op); } -// -// Given a type, find what operation would fully construct it. -// -TOperator TParseContext::mapTypeToConstructorOp(const TType& type) const +// Handle seeing a precision qualifier in the grammar. +void TParseContext::handlePrecisionQualifier(const TSourceLoc& /*loc*/, TQualifier& qualifier, TPrecisionQualifier precision) { - TOperator op = EOpNull; - - switch (type.getBasicType()) { - case EbtStruct: - op = EOpConstructStruct; - break; - case EbtSampler: - if (type.getSampler().combined) - op = EOpConstructTextureSampler; - break; - case EbtFloat: - if (type.isMatrix()) { - switch (type.getMatrixCols()) { - case 2: - switch (type.getMatrixRows()) { - case 2: op = EOpConstructMat2x2; break; - case 3: op = EOpConstructMat2x3; break; - case 4: op = EOpConstructMat2x4; break; - default: break; // some compilers want this - } - break; - case 3: - switch (type.getMatrixRows()) { - case 2: op = EOpConstructMat3x2; break; - case 3: op = EOpConstructMat3x3; break; - case 4: op = EOpConstructMat3x4; break; - default: break; // some compilers want this - } - break; - case 4: - switch (type.getMatrixRows()) { - case 2: op = EOpConstructMat4x2; break; - case 3: op = EOpConstructMat4x3; break; - case 4: op = EOpConstructMat4x4; break; - default: break; // some compilers want this - } - break; - default: break; // some compilers want this - } - } else { - switch(type.getVectorSize()) { - case 1: op = EOpConstructFloat; break; - case 2: op = EOpConstructVec2; break; - case 3: op = EOpConstructVec3; break; - case 4: op = EOpConstructVec4; break; - default: break; // some compilers want this - } - } - break; - case EbtDouble: - if (type.getMatrixCols()) { - switch (type.getMatrixCols()) { - case 2: - switch (type.getMatrixRows()) { - case 2: op = EOpConstructDMat2x2; break; - case 3: op = EOpConstructDMat2x3; break; - case 4: op = EOpConstructDMat2x4; break; - default: break; // some compilers want this - } - break; - case 3: - switch (type.getMatrixRows()) { - case 2: op = EOpConstructDMat3x2; break; - case 3: op = EOpConstructDMat3x3; break; - case 4: op = EOpConstructDMat3x4; break; - default: break; // some compilers want this - } - break; - case 4: - switch (type.getMatrixRows()) { - case 2: op = EOpConstructDMat4x2; break; - case 3: op = EOpConstructDMat4x3; break; - case 4: op = EOpConstructDMat4x4; break; - default: break; // some compilers want this - } - break; - } - } else { - switch(type.getVectorSize()) { - case 1: op = EOpConstructDouble; break; - case 2: op = EOpConstructDVec2; break; - case 3: op = EOpConstructDVec3; break; - case 4: op = EOpConstructDVec4; break; - default: break; // some compilers want this - } - } - break; - case EbtInt: - switch(type.getVectorSize()) { - case 1: op = EOpConstructInt; break; - case 2: op = EOpConstructIVec2; break; - case 3: op = EOpConstructIVec3; break; - case 4: op = EOpConstructIVec4; break; - default: break; // some compilers want this - } - break; - case EbtUint: - switch(type.getVectorSize()) { - case 1: op = EOpConstructUint; break; - case 2: op = EOpConstructUVec2; break; - case 3: op = EOpConstructUVec3; break; - case 4: op = EOpConstructUVec4; break; - default: break; // some compilers want this - } - break; - case EbtInt64: - switch(type.getVectorSize()) { - case 1: op = EOpConstructInt64; break; - case 2: op = EOpConstructI64Vec2; break; - case 3: op = EOpConstructI64Vec3; break; - case 4: op = EOpConstructI64Vec4; break; - default: break; // some compilers want this - } - break; - case EbtUint64: - switch(type.getVectorSize()) { - case 1: op = EOpConstructUint64; break; - case 2: op = EOpConstructU64Vec2; break; - case 3: op = EOpConstructU64Vec3; break; - case 4: op = EOpConstructU64Vec4; break; - default: break; // some compilers want this - } - break; - case EbtBool: - switch(type.getVectorSize()) { - case 1: op = EOpConstructBool; break; - case 2: op = EOpConstructBVec2; break; - case 3: op = EOpConstructBVec3; break; - case 4: op = EOpConstructBVec4; break; - default: break; // some compilers want this - } - break; - default: - break; - } + if (obeyPrecisionQualifiers()) + qualifier.precision = precision; +} - return op; +// Check for messages to give on seeing a precision qualifier used in a +// declaration in the grammar. +void TParseContext::checkPrecisionQualifier(const TSourceLoc& loc, TPrecisionQualifier) +{ + if (precisionManager.shouldWarnAboutDefaults()) { + warn(loc, "all default precisions are highp; use precision statements to quiet warning, e.g.:\n" + " \"precision mediump int; precision highp float;\"", "", ""); + precisionManager.defaultWarningGiven(); + } } // @@ -1966,14 +1975,14 @@ void TParseContext::variableCheck(TIntermTyped*& nodePtr) // Both test and if necessary, spit out an error, to see if the node is really // an l-value that can be operated on this way. // -// Returns true if the was an error. +// Returns true if there was an error. // bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node) { TIntermBinary* binaryNode = node->getAsBinaryNode(); if (binaryNode) { - bool errorReturn; + bool errorReturn = false; switch(binaryNode->getOp()) { case EOpIndexDirect: @@ -1992,9 +2001,9 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt } } - // fall through + break; // left node is checked by base class case EOpIndexDirectStruct: - return lValueErrorCheck(loc, op, binaryNode->getLeft()); + break; // left node is checked by base class case EOpVectorSwizzle: errorReturn = lValueErrorCheck(loc, op, binaryNode->getLeft()); if (!errorReturn) { @@ -2019,11 +2028,16 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt default: break; } - error(loc, " l-value required", op, "", ""); - return true; + if (errorReturn) { + error(loc, " l-value required", op, "", ""); + return true; + } } + // Let the base class check errors + if (TParseContextBase::lValueErrorCheck(loc, op, node)) + return true; const char* symbol = nullptr; TIntermSymbol* symNode = node->getAsSymbolNode(); @@ -2032,19 +2046,12 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt const char* message = nullptr; switch (node->getQualifier().storage) { - case EvqConst: message = "can't modify a const"; break; - case EvqConstReadOnly: message = "can't modify a const"; break; case EvqVaryingIn: message = "can't modify shader input"; break; case EvqInstanceId: message = "can't modify gl_InstanceID"; break; case EvqVertexId: message = "can't modify gl_VertexID"; break; case EvqFace: message = "can't modify gl_FrontFace"; break; case EvqFragCoord: message = "can't modify gl_FragCoord"; break; case EvqPointCoord: message = "can't modify gl_PointCoord"; break; - case EvqUniform: message = "can't modify a uniform"; break; - case EvqBuffer: - if (node->getQualifier().readonly) - message = "can't modify a readonly buffer"; - break; case EvqFragDepth: intermediate.setDepthReplacing(); // "In addition, it is an error to statically write to gl_FragDepth in the fragment shader." @@ -2053,22 +2060,7 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt break; default: - // - // Type that can't be written to? - // - switch (node->getBasicType()) { - case EbtSampler: - message = "can't modify a sampler"; - break; - case EbtAtomicUint: - message = "can't modify an atomic_uint"; - break; - case EbtVoid: - message = "can't modify void"; - break; - default: - break; - } + break; } if (message == nullptr && binaryNode == nullptr && symNode == nullptr) { @@ -2077,7 +2069,6 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt return true; } - // // Everything else is okay, no error. // @@ -2098,27 +2089,15 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt // Test for and give an error if the node can't be read from. void TParseContext::rValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node) { - if (! node) - return; - - TIntermBinary* binaryNode = node->getAsBinaryNode(); - if (binaryNode) { - switch(binaryNode->getOp()) { - case EOpIndexDirect: - case EOpIndexIndirect: - case EOpIndexDirectStruct: - case EOpVectorSwizzle: - rValueErrorCheck(loc, op, binaryNode->getLeft()); - default: - break; - } - - return; - } + // Let the base class check errors + TParseContextBase::rValueErrorCheck(loc, op, node); +#ifdef AMD_EXTENSIONS TIntermSymbol* symNode = node->getAsSymbolNode(); - if (symNode && symNode->getQualifier().writeonly) - error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str()); + if (!(symNode && symNode->getQualifier().writeonly)) // base class checks + if (symNode && symNode->getQualifier().explicitInterp) + error(loc, "can't read from explicitly-interpolated object: ", op, symNode->getName().c_str()); +#endif } // @@ -2292,6 +2271,15 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T case EOpConstructDMat4x2: case EOpConstructDMat4x3: case EOpConstructDMat4x4: + case EOpConstructF16Mat2x2: + case EOpConstructF16Mat2x3: + case EOpConstructF16Mat2x4: + case EOpConstructF16Mat3x2: + case EOpConstructF16Mat3x3: + case EOpConstructF16Mat3x4: + case EOpConstructF16Mat4x2: + case EOpConstructF16Mat4x3: + case EOpConstructF16Mat4x4: constructingMatrix = true; break; default: @@ -2312,7 +2300,7 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T bool floatArgument = false; for (int arg = 0; arg < function.getParamCount(); ++arg) { if (function[arg].type->isArray()) { - if (! function[arg].type->isExplicitlySizedArray()) { + if (function[arg].type->isUnsizedArray()) { // Can't construct from an unsized array. error(loc, "array argument must be sized", "constructor", ""); return true; @@ -2348,6 +2336,10 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T // Finish pinning down spec-const semantics if (specConstType) { switch (op) { + case EOpConstructInt8: + case EOpConstructUint8: + case EOpConstructInt16: + case EOpConstructUint16: case EOpConstructInt: case EOpConstructUint: case EOpConstructInt64: @@ -2356,6 +2348,18 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T case EOpConstructBVec2: case EOpConstructBVec3: case EOpConstructBVec4: + case EOpConstructI8Vec2: + case EOpConstructI8Vec3: + case EOpConstructI8Vec4: + case EOpConstructU8Vec2: + case EOpConstructU8Vec3: + case EOpConstructU8Vec4: + case EOpConstructI16Vec2: + case EOpConstructI16Vec3: + case EOpConstructI16Vec4: + case EOpConstructU16Vec2: + case EOpConstructU16Vec3: + case EOpConstructU16Vec4: case EOpConstructIVec2: case EOpConstructIVec3: case EOpConstructIVec4: @@ -2394,7 +2398,7 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T return true; } - if (type.isImplicitlySizedArray()) { + if (type.isUnsizedArray()) { // auto adapt the constructor type to the number of arguments type.changeOuterArraySize(function.getParamCount()); } else if (type.getOuterArraySize() != function.getParamCount()) { @@ -2406,20 +2410,21 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T // Types have to match, but we're still making the type. // Finish making the type, and the comparison is done later // when checking for conversion. - TArraySizes& arraySizes = type.getArraySizes(); + TArraySizes& arraySizes = *type.getArraySizes(); // At least the dimensionalities have to match. - if (! function[0].type->isArray() || arraySizes.getNumDims() != function[0].type->getArraySizes().getNumDims() + 1) { - error(loc, "array constructor argument not correct type to construct array element", "constructior", ""); + if (! function[0].type->isArray() || + arraySizes.getNumDims() != function[0].type->getArraySizes()->getNumDims() + 1) { + error(loc, "array constructor argument not correct type to construct array element", "constructor", ""); return true; } - if (arraySizes.isInnerImplicit()) { + if (arraySizes.isInnerUnsized()) { // "Arrays of arrays ..., and the size for any dimension is optional" // That means we need to adopt (from the first argument) the other array sizes into the type. for (int d = 1; d < arraySizes.getNumDims(); ++d) { if (arraySizes.getDimSize(d) == UnsizedArraySize) { - arraySizes.setDimSize(d, function[0].type->getArraySizes().getDimSize(d - 1)); + arraySizes.setDimSize(d, function[0].type->getArraySizes()->getDimSize(d - 1)); } } } @@ -2504,8 +2509,8 @@ bool TParseContext::constructorTextureSamplerError(const TSourceLoc& loc, const // of the texture type must match that of the constructed sampler type // (that is, the suffixes of the type of the first argument and the // type of the constructor will be spelled the same way) - if (function[0].type->getBasicType() != EbtSampler || - ! function[0].type->getSampler().isTexture() || + if (function[0].type->getBasicType() != EbtSampler || + ! function[0].type->getSampler().isTexture() || function[0].type->isArray()) { error(loc, "sampler-constructor first argument must be a scalar textureXXX type", token, ""); return true; @@ -2568,6 +2573,16 @@ void TParseContext::boolCheck(const TSourceLoc& loc, const TPublicType& pType) void TParseContext::samplerCheck(const TSourceLoc& loc, const TType& type, const TString& identifier, TIntermTyped* /*initializer*/) { + // Check that the appropriate extension is enabled if external sampler is used. + // There are two extensions. The correct one must be used based on GLSL version. + if (type.getBasicType() == EbtSampler && type.getSampler().external) { + if (version < 300) { + requireExtensions(loc, 1, &E_GL_OES_EGL_image_external, "samplerExternalOES"); + } else { + requireExtensions(loc, 1, &E_GL_OES_EGL_image_external_essl3, "samplerExternalOES"); + } + } + if (type.getQualifier().storage == EvqUniform) return; @@ -2592,17 +2607,35 @@ void TParseContext::atomicUintCheck(const TSourceLoc& loc, const TType& type, co error(loc, "atomic_uints can only be used in uniform variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str()); } -void TParseContext::transparentCheck(const TSourceLoc& loc, const TType& type, const TString& /*identifier*/) +void TParseContext::transparentOpaqueCheck(const TSourceLoc& loc, const TType& type, const TString& identifier) { - // double standard due to gl_NumSamples if (parsingBuiltins) return; - // Vulkan doesn't allow transparent uniforms outside of blocks - if (spvVersion.vulkan == 0 || type.getQualifier().storage != EvqUniform) + if (type.getQualifier().storage != EvqUniform) return; - if (type.containsNonOpaque()) - vulkanRemoved(loc, "non-opaque uniforms outside a block"); + + if (type.containsNonOpaque()) { + // Vulkan doesn't allow transparent uniforms outside of blocks + if (spvVersion.vulkan > 0) + vulkanRemoved(loc, "non-opaque uniforms outside a block"); + // OpenGL wants locations on these (unless they are getting automapped) + if (spvVersion.openGl > 0 && !type.getQualifier().hasLocation() && !intermediate.getAutoMapLocations()) + error(loc, "non-opaque uniform variables need a layout(location=L)", identifier.c_str(), ""); + } +} + +// +// Qualifier checks knowing the qualifier and that it is a member of a struct/block. +// +void TParseContext::memberQualifierCheck(glslang::TPublicType& publicType) +{ + globalQualifierFixCheck(publicType.loc, publicType.qualifier); + checkNoShaderLayouts(publicType.loc, publicType.shaderQualifiers); + if (publicType.qualifier.isNonUniform()) { + error(publicType.loc, "not allowed on block or structure members", "nonuniformEXT", ""); + publicType.qualifier.nonUniform = false; + } } // @@ -2610,12 +2643,15 @@ void TParseContext::transparentCheck(const TSourceLoc& loc, const TType& type, c // void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& qualifier) { + bool nonuniformOkay = false; + // move from parameter/unknown qualifiers to pipeline in/out qualifiers switch (qualifier.storage) { case EvqIn: profileRequires(loc, ENoProfile, 130, nullptr, "in for stage inputs"); profileRequires(loc, EEsProfile, 300, nullptr, "in for stage inputs"); qualifier.storage = EvqVaryingIn; + nonuniformOkay = true; break; case EvqOut: profileRequires(loc, ENoProfile, 130, nullptr, "out for stage outputs"); @@ -2626,10 +2662,17 @@ void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& q qualifier.storage = EvqVaryingIn; error(loc, "cannot use 'inout' at global scope", "", ""); break; + case EvqGlobal: + case EvqTemporary: + nonuniformOkay = true; + break; default: break; } + if (!nonuniformOkay && qualifier.nonUniform) + error(loc, "for non-parameter, can only apply to 'in' or no storage qualifier", "nonuniformEXT", ""); + invariantCheck(loc, qualifier); } @@ -2655,21 +2698,26 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali // now, knowing it is a shader in/out, do all the in/out semantic checks - if (publicType.basicType == EbtBool) { + if (publicType.basicType == EbtBool && !parsingBuiltins) { error(loc, "cannot be bool", GetStorageQualifierString(qualifier.storage), ""); return; } - if (publicType.basicType == EbtInt || publicType.basicType == EbtUint || - publicType.basicType == EbtInt64 || publicType.basicType == EbtUint64 || - publicType.basicType == EbtDouble) + if (isTypeInt(publicType.basicType) || publicType.basicType == EbtDouble) profileRequires(loc, EEsProfile, 300, nullptr, "shader input/output"); - if (! qualifier.flat) { - if (publicType.basicType == EbtInt || publicType.basicType == EbtUint || - publicType.basicType == EbtInt64 || publicType.basicType == EbtUint64 || +#ifdef AMD_EXTENSIONS + if (! qualifier.flat && ! qualifier.explicitInterp) { +#else + if (!qualifier.flat) { +#endif + if (isTypeInt(publicType.basicType) || publicType.basicType == EbtDouble || - (publicType.userDef && (publicType.userDef->containsBasicType(EbtInt) || + (publicType.userDef && (publicType.userDef->containsBasicType(EbtInt8) || + publicType.userDef->containsBasicType(EbtUint8) || + publicType.userDef->containsBasicType(EbtInt16) || + publicType.userDef->containsBasicType(EbtUint16) || + publicType.userDef->containsBasicType(EbtInt) || publicType.userDef->containsBasicType(EbtUint) || publicType.userDef->containsBasicType(EbtInt64) || publicType.userDef->containsBasicType(EbtUint64) || @@ -2771,8 +2819,8 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali error(loc, "can't use auxiliary qualifier on a fragment output", "centroid/sample/patch", ""); if (qualifier.isInterpolation()) error(loc, "can't use interpolation qualifier on a fragment output", "flat/smooth/noperspective", ""); - if (publicType.basicType == EbtDouble) - error(loc, "cannot contain a double", GetStorageQualifierString(qualifier.storage), ""); + if (publicType.basicType == EbtDouble || publicType.basicType == EbtInt64 || publicType.basicType == EbtUint64) + error(loc, "cannot contain a double, int64, or uint64", GetStorageQualifierString(qualifier.storage), ""); break; case EShLangCompute: @@ -2802,10 +2850,14 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons // Multiple interpolation qualifiers (mostly done later by 'individual qualifiers') if (src.isInterpolation() && dst.isInterpolation()) +#ifdef AMD_EXTENSIONS + error(loc, "can only have one interpolation qualifier (flat, smooth, noperspective, __explicitInterpAMD)", "", ""); +#else error(loc, "can only have one interpolation qualifier (flat, smooth, noperspective)", "", ""); +#endif // Ordering - if (! force && ((profile != EEsProfile && version < 420) || + if (! force && ((profile != EEsProfile && version < 420) || (profile == EEsProfile && version < 310)) && ! extensionTurnedOn(E_GL_ARB_shading_language_420pack)) { // non-function parameters @@ -2858,6 +2910,9 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons MERGE_SINGLETON(smooth); MERGE_SINGLETON(flat); MERGE_SINGLETON(nopersp); +#ifdef AMD_EXTENSIONS + MERGE_SINGLETON(explicitInterp); +#endif MERGE_SINGLETON(patch); MERGE_SINGLETON(sample); MERGE_SINGLETON(coherent); @@ -2866,6 +2921,7 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons MERGE_SINGLETON(readonly); MERGE_SINGLETON(writeonly); MERGE_SINGLETON(specConstant); + MERGE_SINGLETON(nonUniform); if (repeated) error(loc, "replicated qualifiers", "", ""); @@ -2884,8 +2940,11 @@ void TParseContext::setDefaultPrecision(const TSourceLoc& loc, TPublicType& publ if (basicType == EbtInt || basicType == EbtFloat) { if (publicType.isScalar()) { defaultPrecision[basicType] = qualifier; - if (basicType == EbtInt) + if (basicType == EbtInt) { defaultPrecision[EbtUint] = qualifier; + precisionManager.explicitIntDefaultSeen(); + } else + precisionManager.explicitFloatDefaultSeen(); return; // all is well } @@ -2930,7 +2989,7 @@ void TParseContext::precisionQualifierCheck(const TSourceLoc& loc, TBasicType ba { // Built-in symbols are allowed some ambiguous precisions, to be pinned down // later by context. - if (profile != EEsProfile || parsingBuiltins) + if (! obeyPrecisionQualifiers() || parsingBuiltins) return; if (baseType == EbtAtomicUint && qualifier.precision != EpqNone && qualifier.precision != EpqHigh) @@ -2951,7 +3010,7 @@ void TParseContext::precisionQualifierCheck(const TSourceLoc& loc, TBasicType ba void TParseContext::parameterTypeCheck(const TSourceLoc& loc, TStorageQualifier qualifier, const TType& type) { - if ((qualifier == EvqOut || qualifier == EvqInOut) && (type.getBasicType() == EbtSampler || type.getBasicType() == EbtAtomicUint)) + if ((qualifier == EvqOut || qualifier == EvqInOut) && type.isOpaque()) error(loc, "samplers and atomic_uints cannot be output parameters", type.getBasicTypeString().c_str(), ""); } @@ -3063,7 +3122,7 @@ bool TParseContext::arrayError(const TSourceLoc& loc, const TType& type) // void TParseContext::arraySizeRequiredCheck(const TSourceLoc& loc, const TArraySizes& arraySizes) { - if (arraySizes.isImplicit()) + if (arraySizes.hasUnsized()) error(loc, "array size required", "", ""); } @@ -3077,7 +3136,8 @@ void TParseContext::structArrayCheck(const TSourceLoc& /*loc*/, const TType& typ } } -void TParseContext::arrayUnsizedCheck(const TSourceLoc& loc, const TQualifier& qualifier, const TArraySizes* arraySizes, bool initializer, bool lastMember) +void TParseContext::arraySizesCheck(const TSourceLoc& loc, const TQualifier& qualifier, TArraySizes* arraySizes, + const TIntermTyped* initializer, bool lastMember) { assert(arraySizes); @@ -3085,13 +3145,22 @@ void TParseContext::arrayUnsizedCheck(const TSourceLoc& loc, const TQualifier& q if (parsingBuiltins) return; - // always allow an initializer to set any unknown array sizes - if (initializer) + // initializer must be a sized array, in which case + // allow the initializer to set any unknown array sizes + if (initializer != nullptr) { + if (initializer->getType().isUnsizedArray()) + error(loc, "array initializer must be sized", "[]", ""); return; + } - // No environment lets any non-outer-dimension that's to be implicitly sized - if (arraySizes->isInnerImplicit()) + // No environment allows any non-outer-dimension to be implicitly sized + if (arraySizes->isInnerUnsized()) { error(loc, "only outermost dimension of an array of arrays can be implicitly sized", "[]", ""); + arraySizes->clearInnerUnsized(); + } + + if (arraySizes->isInnerSpecialization()) + error(loc, "only outermost dimension of an array of arrays can be a specialization constant", "[]", ""); // desktop always allows outer-dimension-unsized variable arrays, if (profile != EEsProfile) @@ -3108,19 +3177,22 @@ void TParseContext::arrayUnsizedCheck(const TSourceLoc& loc, const TQualifier& q switch (language) { case EShLangGeometry: if (qualifier.storage == EvqVaryingIn) - if (extensionsTurnedOn(Num_AEP_geometry_shader, AEP_geometry_shader)) + if ((profile == EEsProfile && version >= 320) || + extensionsTurnedOn(Num_AEP_geometry_shader, AEP_geometry_shader)) return; break; case EShLangTessControl: if ( qualifier.storage == EvqVaryingIn || (qualifier.storage == EvqVaryingOut && ! qualifier.patch)) - if (extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader)) + if ((profile == EEsProfile && version >= 320) || + extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader)) return; break; case EShLangTessEvaluation: if ((qualifier.storage == EvqVaryingIn && ! qualifier.patch) || qualifier.storage == EvqVaryingOut) - if (extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader)) + if ((profile == EEsProfile && version >= 320) || + extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader)) return; break; default: @@ -3130,8 +3202,11 @@ void TParseContext::arrayUnsizedCheck(const TSourceLoc& loc, const TQualifier& q arraySizeRequiredCheck(loc, *arraySizes); } -void TParseContext::arrayOfArrayVersionCheck(const TSourceLoc& loc) +void TParseContext::arrayOfArrayVersionCheck(const TSourceLoc& loc, const TArraySizes* sizes) { + if (sizes == nullptr || sizes->getNumDims() == 1) + return; + const char* feature = "arrays of arrays"; requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, feature); @@ -3139,48 +3214,19 @@ void TParseContext::arrayOfArrayVersionCheck(const TSourceLoc& loc) profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, nullptr, feature); } -void TParseContext::arrayDimCheck(const TSourceLoc& loc, const TArraySizes* sizes1, const TArraySizes* sizes2) -{ - if ((sizes1 && sizes2) || - (sizes1 && sizes1->getNumDims() > 1) || - (sizes2 && sizes2->getNumDims() > 1)) - arrayOfArrayVersionCheck(loc); -} - -void TParseContext::arrayDimCheck(const TSourceLoc& loc, const TType* type, const TArraySizes* sizes2) -{ - // skip checking for multiple dimensions on the type; it was caught earlier - if ((type && type->isArray() && sizes2) || - (sizes2 && sizes2->getNumDims() > 1)) - arrayOfArrayVersionCheck(loc); -} - -// Merge array dimensions listed in 'sizes' onto the type's array dimensions. -// -// From the spec: "vec4[2] a[3]; // size-3 array of size-2 array of vec4" -// -// That means, the 'sizes' go in front of the 'type' as outermost sizes. -// 'type' is the type part of the declaration (to the left) -// 'sizes' is the arrayness tagged on the identifier (to the right) -// -void TParseContext::arrayDimMerge(TType& type, const TArraySizes* sizes) -{ - if (sizes) - type.addArrayOuterSizes(*sizes); -} - // // Do all the semantic checking for declaring or redeclaring an array, with and // without a size, and make the right changes to the symbol table. // -void TParseContext::declareArray(const TSourceLoc& loc, TString& identifier, const TType& type, TSymbol*& symbol, bool& newDeclaration) +void TParseContext::declareArray(const TSourceLoc& loc, const TString& identifier, const TType& type, TSymbol*& symbol) { - if (! symbol) { + if (symbol == nullptr) { bool currentScope; symbol = symbolTable.find(identifier, nullptr, ¤tScope); if (symbol && builtInName(identifier) && ! symbolTable.atBuiltInLevel()) { // bad shader (errors already reported) trying to redeclare a built-in name as an array + symbol = nullptr; return; } if (symbol == nullptr || ! currentScope) { @@ -3190,7 +3236,8 @@ void TParseContext::declareArray(const TSourceLoc& loc, TString& identifier, con // symbol = new TVariable(&identifier, type); symbolTable.insert(*symbol); - newDeclaration = true; + if (symbolTable.atGlobalLevel()) + trackLinkage(*symbol); if (! symbolTable.atBuiltInLevel()) { if (isIoResizeArray(type)) { @@ -3213,7 +3260,7 @@ void TParseContext::declareArray(const TSourceLoc& loc, TString& identifier, con // Process a redeclaration. // - if (! symbol) { + if (symbol == nullptr) { error(loc, "array variable name expected", identifier.c_str(), ""); return; } @@ -3236,7 +3283,7 @@ void TParseContext::declareArray(const TSourceLoc& loc, TString& identifier, con return; } - if (existingType.isExplicitlySizedArray()) { + if (existingType.isSizedArray()) { // be more leniant for input arrays to geometry shaders and tessellation control outputs, where the redeclaration is the same size if (! (isIoResizeArray(type) && existingType.getOuterArraySize() == type.getOuterArraySize())) error(loc, "redeclaration of array with size", identifier.c_str(), ""); @@ -3251,64 +3298,37 @@ void TParseContext::declareArray(const TSourceLoc& loc, TString& identifier, con checkIoArraysConsistency(loc); } -void TParseContext::updateImplicitArraySize(const TSourceLoc& loc, TIntermNode *node, int index) +// Policy and error check for needing a runtime sized array. +void TParseContext::checkRuntimeSizable(const TSourceLoc& loc, const TIntermTyped& base) { - // maybe there is nothing to do... - TIntermTyped* typedNode = node->getAsTyped(); - if (typedNode->getType().getImplicitArraySize() > index) + // runtime length implies runtime sizeable, so no problem + if (isRuntimeLength(base)) return; - // something to do... - - // Figure out what symbol to lookup, as we will use its type to edit for the size change, - // as that type will be shared through shallow copies for future references. - TSymbol* symbol = nullptr; - int blockIndex = -1; - const TString* lookupName = nullptr; - if (node->getAsSymbolNode()) - lookupName = &node->getAsSymbolNode()->getName(); - else if (node->getAsBinaryNode()) { - const TIntermBinary* deref = node->getAsBinaryNode(); - // This has to be the result of a block dereference, unless it's bad shader code - // If it's a uniform block, then an error will be issued elsewhere, but - // return early now to avoid crashing later in this function. - if (deref->getLeft()->getBasicType() != EbtBlock || - deref->getLeft()->getType().getQualifier().storage == EvqUniform || - deref->getRight()->getAsConstantUnion() == nullptr) - return; - - const TIntermTyped* left = deref->getLeft(); - const TIntermTyped* right = deref->getRight(); - - if (left->getAsBinaryNode()) { - left = left->getAsBinaryNode()->getLeft(); // Block array access - assert(left->isArray()); - } - - if (! left->getAsSymbolNode()) - return; - - blockIndex = right->getAsConstantUnion()->getConstArray()[0].getIConst(); - - lookupName = &left->getAsSymbolNode()->getName(); - if (IsAnonymous(*lookupName)) - lookupName = &(*left->getType().getStruct())[blockIndex].type->getFieldName(); - } - - // Lookup the symbol, should only fail if shader code is incorrect - symbol = symbolTable.find(*lookupName); - if (symbol == nullptr) - return; - - if (symbol->getAsFunction()) { - error(loc, "array variable name expected", symbol->getName().c_str(), ""); - return; - } - - if (symbol->getType().isStruct() && blockIndex != -1) - (*symbol->getWritableType().getStruct())[blockIndex].type->setImplicitArraySize(index + 1); + // check for additional things allowed by GL_EXT_nonuniform_qualifier + if (base.getBasicType() == EbtSampler || + (base.getBasicType() == EbtBlock && base.getType().getQualifier().isUniformOrBuffer())) + requireExtensions(loc, 1, &E_GL_EXT_nonuniform_qualifier, "variable index"); else - symbol->getWritableType().setImplicitArraySize(index + 1); + error(loc, "", "[", "array must be redeclared with a size before being indexed with a variable"); +} + +// Policy decision for whether a run-time .length() is allowed. +bool TParseContext::isRuntimeLength(const TIntermTyped& base) const +{ + if (base.getType().getQualifier().storage == EvqBuffer) { + // in a buffer block + const TIntermBinary* binary = base.getAsBinaryNode(); + if (binary != nullptr && binary->getOp() == EOpIndexDirectStruct) { + // is it the last member? + const int index = binary->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst(); + const int memberCount = (int)binary->getLeft()->getType().getStruct()->size(); + if (index == memberCount - 1) + return true; + } + } + + return false; } // Returns true if the first argument to the #line directive is the line number for the next line. @@ -3331,7 +3351,7 @@ bool TParseContext::lineDirectiveShouldSetNextLine() const void TParseContext::nonInitConstCheck(const TSourceLoc& loc, TString& identifier, TType& type) { // - // Make the qualifier make sense, given that there is an initializer. + // Make the qualifier make sense, given that there is not an initializer. // if (type.getQualifier().storage == EvqConst || type.getQualifier().storage == EvqConstReadOnly) { @@ -3350,13 +3370,15 @@ void TParseContext::nonInitConstCheck(const TSourceLoc& loc, TString& identifier // // Returns a redeclared and type-modified variable if a redeclarated occurred. // -TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TString& identifier, const TQualifier& qualifier, const TShaderQualifiers& publicType, bool& newDeclaration) +TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TString& identifier, + const TQualifier& qualifier, const TShaderQualifiers& publicType) { if (! builtInName(identifier) || symbolTable.atBuiltInLevel() || ! symbolTable.atGlobalLevel()) return nullptr; bool nonEsRedecls = (profile != EEsProfile && (version >= 130 || identifier == "gl_TexCoord")); - bool esRedecls = (profile == EEsProfile && extensionsTurnedOn(Num_AEP_shader_io_blocks, AEP_shader_io_blocks)); + bool esRedecls = (profile == EEsProfile && + (version >= 320 || extensionsTurnedOn(Num_AEP_shader_io_blocks, AEP_shader_io_blocks))); if (! esRedecls && ! nonEsRedecls) return nullptr; @@ -3383,6 +3405,10 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS identifier == "gl_BackSecondaryColor" || identifier == "gl_SecondaryColor" || (identifier == "gl_Color" && language == EShLangFragment) || +#ifdef NV_EXTENSIONS + identifier == "gl_SampleMask" || + identifier == "gl_Layer" || +#endif identifier == "gl_TexCoord") { // Find the existing symbol, if any. @@ -3397,16 +3423,13 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS // If it wasn't at a built-in level, then it's already been redeclared; // that is, this is a redeclaration of a redeclaration; reuse that initial // redeclaration. Otherwise, make the new one. - if (builtIn) { - // Copy the symbol up to make a writable version + if (builtIn) makeEditable(symbol); - newDeclaration = true; - } // Now, modify the type of the copy, as per the type of the current redeclaration. TQualifier& symbolQualifier = symbol->getWritableType().getQualifier(); - if (ssoPre150) { + if (ssoPre150) { if (intermediate.inIoAccessed(identifier)) error(loc, "cannot redeclare after use", identifier.c_str(), ""); if (qualifier.hasLayout()) @@ -3444,7 +3467,7 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS error(loc, "can only change layout qualification of", "redeclaration", symbol->getName().c_str()); if (qualifier.storage != EvqVaryingIn) error(loc, "cannot change input storage qualification of", "redeclaration", symbol->getName().c_str()); - if (! builtIn && (publicType.pixelCenterInteger != intermediate.getPixelCenterInteger() || + if (! builtIn && (publicType.pixelCenterInteger != intermediate.getPixelCenterInteger() || publicType.originUpperLeft != intermediate.getOriginUpperLeft())) error(loc, "cannot redeclare with different qualification:", "redeclaration", symbol->getName().c_str()); if (publicType.pixelCenterInteger) @@ -3463,8 +3486,22 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS if (! intermediate.setDepth(publicType.layoutDepth)) error(loc, "all redeclarations must use the same depth layout on", "redeclaration", symbol->getName().c_str()); } - } +#ifdef NV_EXTENSIONS + else if (identifier == "gl_SampleMask") { + if (!publicType.layoutOverrideCoverage) { + error(loc, "redeclaration only allowed for override_coverage layout", "redeclaration", symbol->getName().c_str()); + } + intermediate.setLayoutOverrideCoverage(); + } + else if (identifier == "gl_Layer") { + if (!qualifier.layoutViewportRelative && qualifier.layoutSecondaryViewportRelativeOffset == -2048) + error(loc, "redeclaration only allowed for viewport_relative or secondary_view_offset layout", "redeclaration", symbol->getName().c_str()); + symbolQualifier.layoutViewportRelative = qualifier.layoutViewportRelative; + symbolQualifier.layoutSecondaryViewportRelativeOffset = qualifier.layoutSecondaryViewportRelativeOffset; + } +#endif + // TODO: semantics quality: separate smooth from nothing declared, then use IsInterpolation for several tests above return symbol; @@ -3477,10 +3514,11 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS // Either redeclare the requested block, or give an error message why it can't be done. // // TODO: functionality: explicitly sizing members of redeclared blocks is not giving them an explicit size -void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newTypeList, const TString& blockName, const TString* instanceName, TArraySizes* arraySizes) +void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newTypeList, const TString& blockName, + const TString* instanceName, TArraySizes* arraySizes) { const char* feature = "built-in block redeclaration"; - profileRequires(loc, EEsProfile, 0, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, feature); + profileRequires(loc, EEsProfile, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, feature); profileRequires(loc, ~EEsProfile, 410, E_GL_ARB_separate_shader_objects, feature); if (blockName != "gl_PerVertex" && blockName != "gl_PerFragment") { @@ -3526,10 +3564,32 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT return; } + // Fix XFB stuff up, it applies to the order of the redeclaration, not + // the order of the original members. + if (currentBlockQualifier.storage == EvqVaryingOut && globalOutputDefaults.hasXfbBuffer()) { + if (!currentBlockQualifier.hasXfbBuffer()) + currentBlockQualifier.layoutXfbBuffer = globalOutputDefaults.layoutXfbBuffer; + fixBlockXfbOffsets(currentBlockQualifier, newTypeList); + } + // Edit and error check the container against the redeclaration // - remove unused members // - ensure remaining qualifiers/types match + TType& type = block->getWritableType(); + +#ifdef NV_EXTENSIONS + // if gl_PerVertex is redeclared for the purpose of passing through "gl_Position" + // for passthrough purpose, the redeclared block should have the same qualifers as + // the current one + if (currentBlockQualifier.layoutPassthrough) { + type.getQualifier().layoutPassthrough = currentBlockQualifier.layoutPassthrough; + type.getQualifier().storage = currentBlockQualifier.storage; + type.getQualifier().layoutStream = currentBlockQualifier.layoutStream; + type.getQualifier().layoutXfbBuffer = currentBlockQualifier.layoutXfbBuffer; + } +#endif + TTypeList::iterator member = type.getWritableStruct()->begin(); size_t numOriginalMembersFound = 0; while (member != type.getStruct()->end()) { @@ -3557,16 +3617,19 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT error(memberLoc, "cannot redeclare block member with a different type", member->type->getFieldName().c_str(), ""); if (oldType.isArray() != newType.isArray()) error(memberLoc, "cannot change arrayness of redeclared block member", member->type->getFieldName().c_str(), ""); - else if (! oldType.sameArrayness(newType) && oldType.isExplicitlySizedArray()) + else if (! oldType.sameArrayness(newType) && oldType.isSizedArray()) error(memberLoc, "cannot change array size of redeclared block member", member->type->getFieldName().c_str(), ""); else if (newType.isArray()) arrayLimitCheck(loc, member->type->getFieldName(), newType.getOuterArraySize()); if (newType.getQualifier().isMemory()) error(memberLoc, "cannot add memory qualifier to redeclared block member", member->type->getFieldName().c_str(), ""); - if (newType.getQualifier().hasLayout()) - error(memberLoc, "cannot add layout to redeclared block member", member->type->getFieldName().c_str(), ""); + if (newType.getQualifier().hasNonXfbLayout()) + error(memberLoc, "cannot add non-XFB layout to redeclared block member", member->type->getFieldName().c_str(), ""); if (newType.getQualifier().patch) error(memberLoc, "cannot add patch to redeclared block member", member->type->getFieldName().c_str(), ""); + if (newType.getQualifier().hasXfbBuffer() && + newType.getQualifier().layoutXfbBuffer != currentBlockQualifier.layoutXfbBuffer) + error(memberLoc, "member cannot contradict block (or what block inherited from global)", "xfb_buffer", ""); oldType.getQualifier().centroid = newType.getQualifier().centroid; oldType.getQualifier().sample = newType.getQualifier().sample; oldType.getQualifier().invariant = newType.getQualifier().invariant; @@ -3574,13 +3637,24 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT oldType.getQualifier().smooth = newType.getQualifier().smooth; oldType.getQualifier().flat = newType.getQualifier().flat; oldType.getQualifier().nopersp = newType.getQualifier().nopersp; - - if (oldType.isImplicitlySizedArray() && newType.isExplicitlySizedArray()) + oldType.getQualifier().layoutXfbOffset = newType.getQualifier().layoutXfbOffset; + oldType.getQualifier().layoutXfbBuffer = newType.getQualifier().layoutXfbBuffer; + oldType.getQualifier().layoutXfbStride = newType.getQualifier().layoutXfbStride; + if (oldType.getQualifier().layoutXfbOffset != TQualifier::layoutXfbBufferEnd) { + // if any member as an xfb_offset, then the block's xfb_buffer inherents current xfb_buffer, + // and for xfb processing, the member needs it as well, along with xfb_stride + type.getQualifier().layoutXfbBuffer = currentBlockQualifier.layoutXfbBuffer; + oldType.getQualifier().layoutXfbBuffer = currentBlockQualifier.layoutXfbBuffer; + } + if (oldType.isUnsizedArray() && newType.isSizedArray()) oldType.changeOuterArraySize(newType.getOuterArraySize()); + // check and process the member's type, which will include managing xfb information + layoutTypeCheck(loc, oldType); + // go to next member ++member; - } else { + } else { // For missing members of anonymous blocks that have been redeclared, // hide the original (shared) declaration. // Instance-named blocks can just have the member removed. @@ -3595,15 +3669,24 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT if (numOriginalMembersFound < newTypeList.size()) error(loc, "block redeclaration has extra members", blockName.c_str(), ""); - if (type.isArray() != (arraySizes != nullptr)) + if (type.isArray() != (arraySizes != nullptr) || + (type.isArray() && arraySizes != nullptr && type.getArraySizes()->getNumDims() != arraySizes->getNumDims())) error(loc, "cannot change arrayness of redeclared block", blockName.c_str(), ""); else if (type.isArray()) { - if (type.isExplicitlySizedArray() && arraySizes->getOuterSize() == UnsizedArraySize) - error(loc, "block already declared with size, can't redeclare as implicitly-sized", blockName.c_str(), ""); - else if (type.isExplicitlySizedArray() && type.getArraySizes() != *arraySizes) - error(loc, "cannot change array size of redeclared block", blockName.c_str(), ""); - else if (type.isImplicitlySizedArray() && arraySizes->getOuterSize() != UnsizedArraySize) + // At this point, we know both are arrays and both have the same number of dimensions. + + // It is okay for a built-in block redeclaration to be unsized, and keep the size of the + // original block declaration. + if (!arraySizes->isSized() && type.isSizedArray()) + arraySizes->changeOuterSize(type.getOuterArraySize()); + + // And, okay to be giving a size to the array, by the redeclaration + if (!type.isSizedArray() && arraySizes->isSized()) type.changeOuterArraySize(arraySizes->getOuterSize()); + + // Now, they must match in all dimensions. + if (type.isSizedArray() && *type.getArraySizes() != *arraySizes) + error(loc, "cannot change array size of redeclared block", blockName.c_str(), ""); } symbolTable.insert(*block); @@ -3619,10 +3702,10 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT fixIoArraySize(loc, block->getWritableType()); // Save it in the AST for linker use. - intermediate.addSymbolLinkageNode(linkage, *block); + trackLinkage(*block); } -void TParseContext::paramCheckFix(const TSourceLoc& loc, const TStorageQualifier& qualifier, TType& type) +void TParseContext::paramCheckFixStorage(const TSourceLoc& loc, const TStorageQualifier& qualifier, TType& type) { switch (qualifier) { case EvqConst: @@ -3663,13 +3746,15 @@ void TParseContext::paramCheckFix(const TSourceLoc& loc, const TQualifier& quali if (qualifier.invariant) error(loc, "cannot use invariant qualifier on a function parameter", "", ""); if (qualifier.noContraction) { - if (qualifier.storage == EvqOut || qualifier.storage == EvqInOut) + if (qualifier.isParamOutput()) type.getQualifier().noContraction = true; else warn(loc, "qualifier has no effect on non-output parameters", "precise", ""); } + if (qualifier.isNonUniform()) + type.getQualifier().nonUniform = qualifier.nonUniform; - paramCheckFix(loc, qualifier.storage, type); + paramCheckFixStorage(loc, qualifier.storage, type); } void TParseContext::nestedBlockCheck(const TSourceLoc& loc) @@ -3713,7 +3798,7 @@ void TParseContext::structTypeCheck(const TSourceLoc& /*loc*/, TPublicType& publ // fix and check for member storage qualifiers and types that don't belong within a structure for (unsigned int member = 0; member < typeList.size(); ++member) { - TQualifier& memberQualifier = typeList[member].type->getQualifier(); + TQualifier& memberQualifier = typeList[member].type->getQualifier(); const TSourceLoc& memberLoc = typeList[member].loc; if (memberQualifier.isAuxiliary() || memberQualifier.isInterpolation() || @@ -3873,8 +3958,13 @@ void TParseContext::limitCheck(const TSourceLoc& loc, int value, const char* lim // // Do any additional error checking, etc., once we know the parsing is done. // -void TParseContext::finalErrorCheck() +void TParseContext::finish() { + TParseContextBase::finish(); + + if (parsingBuiltins) + return; + // Check on array indexes for ES 2.0 (version 100) limitations. for (size_t i = 0; i < needsIndexLimitationChecking.size(); ++i) constantIndexExpressionCheck(needsIndexLimitationChecking[i]); @@ -3882,7 +3972,7 @@ void TParseContext::finalErrorCheck() // Check for stages that are enabled by extension. // Can't do this at the beginning, it is chicken and egg to add a stage by // extension. - // Stage-specific features were correctly tested for already, this is just + // Stage-specific features were correctly tested for already, this is just // about the stage itself. switch (language) { case EShLangGeometry: @@ -3903,6 +3993,28 @@ void TParseContext::finalErrorCheck() default: break; } + +#ifdef NV_EXTENSIONS + // Set default outputs for GL_NV_geometry_shader_passthrough + if (language == EShLangGeometry && extensionTurnedOn(E_SPV_NV_geometry_shader_passthrough)) { + if (intermediate.getOutputPrimitive() == ElgNone) { + switch (intermediate.getInputPrimitive()) { + case ElgPoints: intermediate.setOutputPrimitive(ElgPoints); break; + case ElgLines: intermediate.setOutputPrimitive(ElgLineStrip); break; + case ElgTriangles: intermediate.setOutputPrimitive(ElgTriangles); break; + default: break; + } + } + if (intermediate.getVertices() == TQualifier::layoutNotSet) { + switch (intermediate.getInputPrimitive()) { + case ElgPoints: intermediate.setVertices(1); break; + case ElgLines: intermediate.setVertices(2); break; + case ElgTriangles: intermediate.setVertices(3); break; + default: break; + } + } + } +#endif } // @@ -3994,6 +4106,14 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi publicType.shaderQualifiers.geometry = ElgTriangleStrip; return; } +#ifdef NV_EXTENSIONS + if (id == "passthrough") { + requireExtensions(loc, 1, &E_SPV_NV_geometry_shader_passthrough, "geometry shader passthrough"); + publicType.qualifier.layoutPassthrough = true; + intermediate.setGeoPassthroughEXT(); + return; + } +#endif } else { assert(language == EShLangTessEvaluation); @@ -4059,6 +4179,14 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi publicType.shaderQualifiers.earlyFragmentTests = true; return; } + if (id == "post_depth_coverage") { + requireExtensions(loc, Num_post_depth_coverageEXTs, post_depth_coverageEXTs, "post depth coverage"); + if (extensionTurnedOn(E_GL_ARB_post_depth_coverage)) { + publicType.shaderQualifiers.earlyFragmentTests = true; + } + publicType.shaderQualifiers.postDepthCoverage = true; + return; + } for (TLayoutDepth depth = (TLayoutDepth)(EldNone + 1); depth < EldCount; depth = (TLayoutDepth)(depth+1)) { if (id == TQualifier::getLayoutDepthString(depth)) { requireProfile(loc, ECoreProfile | ECompatibilityProfile, "depth layout qualifier"); @@ -4071,7 +4199,8 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi bool found = false; for (TBlendEquationShift be = (TBlendEquationShift)0; be < EBlendCount; be = (TBlendEquationShift)(be + 1)) { if (id == TQualifier::getBlendEquationString(be)) { - requireExtensions(loc, 1, &E_GL_KHR_blend_equation_advanced, "blend equation"); + profileRequires(loc, EEsProfile, 320, E_GL_KHR_blend_equation_advanced, "blend equation"); + profileRequires(loc, ~EEsProfile, 0, E_GL_KHR_blend_equation_advanced, "blend equation"); intermediate.addBlendEquation(be); publicType.shaderQualifiers.blendEquation = true; found = true; @@ -4082,7 +4211,26 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi error(loc, "unknown blend equation", "blend_support", ""); return; } +#ifdef NV_EXTENSIONS + if (id == "override_coverage") { + requireExtensions(loc, 1, &E_GL_NV_sample_mask_override_coverage, "sample mask override coverage"); + publicType.shaderQualifiers.layoutOverrideCoverage = true; + return; + } } + if (language == EShLangVertex || + language == EShLangTessControl || + language == EShLangTessEvaluation || + language == EShLangGeometry ) { + if (id == "viewport_relative") { + requireExtensions(loc, 1, &E_GL_NV_viewport_array2, "view port array2"); + publicType.qualifier.layoutViewportRelative = true; + return; + } + } +#else + } +#endif error(loc, "unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4)", id.c_str(), ""); } @@ -4113,22 +4261,26 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi } std::transform(id.begin(), id.end(), id.begin(), ::tolower); - + if (id == "offset") { // "offset" can be for either // - uniform offsets // - atomic_uint offsets const char* feature = "offset"; - requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, feature); - const char* exts[2] = { E_GL_ARB_enhanced_layouts, E_GL_ARB_shader_atomic_counters }; - profileRequires(loc, ECoreProfile | ECompatibilityProfile, 420, 2, exts, feature); - profileRequires(loc, EEsProfile, 310, nullptr, feature); + if (spvVersion.spv == 0) { + requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, feature); + const char* exts[2] = { E_GL_ARB_enhanced_layouts, E_GL_ARB_shader_atomic_counters }; + profileRequires(loc, ECoreProfile | ECompatibilityProfile, 420, 2, exts, feature); + profileRequires(loc, EEsProfile, 310, nullptr, feature); + } publicType.qualifier.layoutOffset = value; return; } else if (id == "align") { const char* feature = "uniform buffer-member align"; - requireProfile(loc, ECoreProfile | ECompatibilityProfile, feature); - profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, feature); + if (spvVersion.spv == 0) { + requireProfile(loc, ECoreProfile | ECompatibilityProfile, feature); + profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, feature); + } // "The specified alignment must be a power of 2, or a compile-time error results." if (! IsPow2(value)) error(loc, "must be a power of 2", "align", ""); @@ -4169,9 +4321,9 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi publicType.qualifier.layoutComponent = value; return; } else if (id.compare(0, 4, "xfb_") == 0) { - // "Any shader making any static use (after preprocessing) of any of these - // *xfb_* qualifiers will cause the shader to be in a transform feedback - // capturing mode and hence responsible for describing the transform feedback + // "Any shader making any static use (after preprocessing) of any of these + // *xfb_* qualifiers will cause the shader to be in a transform feedback + // capturing mode and hence responsible for describing the transform feedback // setup." intermediate.setXfbMode(); const char* feature = "transform feedback qualifier"; @@ -4182,7 +4334,7 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi // "It is a compile-time error to specify an *xfb_buffer* that is greater than // the implementation-dependent constant gl_MaxTransformFeedbackBuffers." if (value >= resources.maxTransformFeedbackBuffers) - error(loc, "buffer is too large:", id.c_str(), "gl_MaxTransformFeedbackBuffers is %d", resources.maxTransformFeedbackBuffers); + error(loc, "buffer is too large:", id.c_str(), "gl_MaxTransformFeedbackBuffers is %d", resources.maxTransformFeedbackBuffers); if (value >= (int)TQualifier::layoutXfbBufferEnd) error(loc, "buffer is too large:", id.c_str(), "internal max is %d", TQualifier::layoutXfbBufferEnd-1); else @@ -4195,7 +4347,7 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi publicType.qualifier.layoutXfbOffset = value; return; } else if (id == "xfb_stride") { - // "The resulting stride (implicit or explicit), when divided by 4, must be less than or equal to the + // "The resulting stride (implicit or explicit), when divided by 4, must be less than or equal to the // implementation-dependent constant gl_MaxTransformFeedbackInterleavedComponents." if (value > 4 * resources.maxTransformFeedbackInterleavedComponents) error(loc, "1/4 stride is too large:", id.c_str(), "gl_MaxTransformFeedbackInterleavedComponents is %d", resources.maxTransformFeedbackInterleavedComponents); @@ -4227,6 +4379,24 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi } return; } + if (id == "num_views") { + requireExtensions(loc, Num_OVR_multiview_EXTs, OVR_multiview_EXTs, "num_views"); + publicType.shaderQualifiers.numViews = value; + return; + } + +#if NV_EXTENSIONS + if (language == EShLangVertex || + language == EShLangTessControl || + language == EShLangTessEvaluation || + language == EShLangGeometry) { + if (id == "secondary_view_offset") { + requireExtensions(loc, 1, &E_GL_NV_stereo_view_rendering, "stereo view rendering"); + publicType.qualifier.layoutSecondaryViewportRelativeOffset = value; + return; + } + } +#endif switch (language) { case EShLangVertex: @@ -4290,6 +4460,10 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi if (id.compare(0, 11, "local_size_") == 0) { profileRequires(loc, EEsProfile, 310, 0, "gl_WorkGroupSize"); profileRequires(loc, ~EEsProfile, 430, E_GL_ARB_compute_shader, "gl_WorkGroupSize"); + if (id.size() == 12 && value == 0) { + error(loc, "must be at least 1", id.c_str(), ""); + return; + } if (id == "local_size_x") { publicType.shaderQualifiers.localSize[0] = value; return; @@ -4329,18 +4503,17 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi // Merge any layout qualifier information from src into dst, leaving everything else in dst alone // // "More than one layout qualifier may appear in a single declaration. -// Additionally, the same layout-qualifier-name can occur multiple times -// within a layout qualifier or across multiple layout qualifiers in the -// same declaration. When the same layout-qualifier-name occurs -// multiple times, in a single declaration, the last occurrence overrides -// the former occurrence(s). Further, if such a layout-qualifier-name -// will effect subsequent declarations or other observable behavior, it -// is only the last occurrence that will have any effect, behaving as if -// the earlier occurrence(s) within the declaration are not present. -// This is also true for overriding layout-qualifier-names, where one -// overrides the other (e.g., row_major vs. column_major); only the last -// occurrence has any effect." -// +// Additionally, the same layout-qualifier-name can occur multiple times +// within a layout qualifier or across multiple layout qualifiers in the +// same declaration. When the same layout-qualifier-name occurs +// multiple times, in a single declaration, the last occurrence overrides +// the former occurrence(s). Further, if such a layout-qualifier-name +// will effect subsequent declarations or other observable behavior, it +// is only the last occurrence that will have any effect, behaving as if +// the earlier occurrence(s) within the declaration are not present. +// This is also true for overriding layout-qualifier-names, where one +// overrides the other (e.g., row_major vs. column_major); only the last +// occurrence has any effect." void TParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifier& src, bool inheritOnly) { if (src.hasMatrix()) @@ -4387,6 +4560,15 @@ void TParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifie if (src.layoutPushConstant) dst.layoutPushConstant = true; + +#ifdef NV_EXTENSIONS + if (src.layoutPassthrough) + dst.layoutPassthrough = true; + if (src.layoutViewportRelative) + dst.layoutViewportRelative = true; + if (src.layoutSecondaryViewportRelativeOffset != -2048) + dst.layoutSecondaryViewportRelativeOffset = src.layoutSecondaryViewportRelativeOffset; +#endif } } @@ -4413,7 +4595,26 @@ void TParseContext::layoutObjectCheck(const TSourceLoc& loc, const TSymbol& symb } } - // Check packing and matrix + // user-variable location check, which are required for SPIR-V in/out: + // - variables have it directly, + // - blocks have it on each member (already enforced), so check first one + if (spvVersion.spv > 0 && !parsingBuiltins && qualifier.builtIn == EbvNone && + !qualifier.hasLocation() && !intermediate.getAutoMapLocations()) { + + switch (qualifier.storage) { + case EvqVaryingIn: + case EvqVaryingOut: + if (type.getBasicType() != EbtBlock || + (!(*type.getStruct())[0].type->getQualifier().hasLocation() && + (*type.getStruct())[0].type->getQualifier().builtIn == EbvNone)) + error(loc, "SPIR-V requires location for user input/output", "location", ""); + break; + default: + break; + } + } + + // Check packing and matrix if (qualifier.hasUniformLayout()) { switch (qualifier.storage) { case EvqUniform: @@ -4440,6 +4641,23 @@ void TParseContext::layoutObjectCheck(const TSourceLoc& loc, const TSymbol& symb } } +// "For some blocks declared as arrays, the location can only be applied at the block level: +// When a block is declared as an array where additional locations are needed for each member +// for each block array element, it is a compile-time error to specify locations on the block +// members. That is, when locations would be under specified by applying them on block members, +// they are not allowed on block members. For arrayed interfaces (those generally having an +// extra level of arrayness due to interface expansion), the outer array is stripped before +// applying this rule." +void TParseContext::layoutMemberLocationArrayCheck(const TSourceLoc& loc, bool memberWithLocation, + TArraySizes* arraySizes) +{ + if (memberWithLocation && arraySizes != nullptr) { + if (arraySizes->getNumDims() > (currentBlockQualifier.isArrayedIo(language) ? 1 : 0)) + error(loc, "cannot use in a block array where new locations are needed for each block element", + "location", ""); + } +} + // Do layout error checking with respect to a type. void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) { @@ -4459,12 +4677,17 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) } if (qualifier.hasComponent()) { // "It is a compile-time error if this sequence of components gets larger than 3." - if (qualifier.layoutComponent + type.getVectorSize() > 4) + if (qualifier.layoutComponent + type.getVectorSize() * (type.getBasicType() == EbtDouble ? 2 : 1) > 4) error(loc, "type overflows the available 4 components", "component", ""); // "It is a compile-time error to apply the component qualifier to a matrix, a structure, a block, or an array containing any of these." if (type.isMatrix() || type.getBasicType() == EbtBlock || type.getBasicType() == EbtStruct) error(loc, "cannot apply to a matrix, structure, or block", "component", ""); + + // " It is a compile-time error to use component 1 or 3 as the beginning of a double or dvec2." + if (type.getBasicType() == EbtDouble) + if (qualifier.layoutComponent & 1) + error(loc, "doubles cannot start on an odd-numbered component", "component", ""); } switch (qualifier.storage) { @@ -4475,6 +4698,8 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) break; case EvqUniform: case EvqBuffer: + if (type.getBasicType() == EbtBlock) + error(loc, "cannot apply to uniform or buffer block", "location", ""); break; default: error(loc, "can only apply to uniform, buffer, in, or out storage qualifiers", "location", ""); @@ -4496,11 +4721,14 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) if (repeated >= 0) error(loc, "overlapping offsets at", "xfb_offset", "offset %d in buffer %d", repeated, qualifier.layoutXfbBuffer); - // "The offset must be a multiple of the size of the first component of the first - // qualified variable or block member, or a compile-time error results. Further, if applied to an aggregate + // "The offset must be a multiple of the size of the first component of the first + // qualified variable or block member, or a compile-time error results. Further, if applied to an aggregate // containing a double, the offset must also be a multiple of 8..." if (type.containsBasicType(EbtDouble) && ! IsMultipleOfPow2(qualifier.layoutXfbOffset, 8)) error(loc, "type contains double; xfb_offset must be a multiple of 8", "xfb_offset", ""); + // ..., if applied to an aggregate containing a float16_t, the offset must also be a multiple of 2..." + else if (type.containsBasicType(EbtFloat16) && !IsMultipleOfPow2(qualifier.layoutXfbOffset, 2)) + error(loc, "type contains half float; xfb_offset must be a multiple of 2", "xfb_offset", ""); else if (! IsMultipleOfPow2(qualifier.layoutXfbOffset, 4)) error(loc, "must be a multiple of size of first component", "xfb_offset", ""); } @@ -4519,13 +4747,24 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) // an array of size N, all elements of the array from binding through binding + N - 1 must be within this // range." // - if (type.getBasicType() != EbtSampler && type.getBasicType() != EbtBlock && type.getBasicType() != EbtAtomicUint) + if (! type.isOpaque() && type.getBasicType() != EbtBlock) error(loc, "requires block, or sampler/image, or atomic-counter type", "binding", ""); if (type.getBasicType() == EbtSampler) { int lastBinding = qualifier.layoutBinding; - if (type.isArray()) - lastBinding += type.getCumulativeArraySize(); - if (lastBinding >= resources.maxCombinedTextureImageUnits) + if (type.isArray()) { + if (spvVersion.vulkan > 0) + lastBinding += 1; + else { + if (type.isSizedArray()) + lastBinding += type.getCumulativeArraySize(); + else { + lastBinding += 1; + if (spvVersion.vulkan == 0) + warn(loc, "assuming binding count of one for compile-time checking of binding numbers for unsized array", "[]", ""); + } + } + } + if (spvVersion.vulkan == 0 && lastBinding >= resources.maxCombinedTextureImageUnits) error(loc, "sampler binding not less than gl_MaxCombinedTextureImageUnits", "binding", type.isArray() ? "(using array)" : ""); } if (type.getBasicType() == EbtAtomicUint) { @@ -4534,12 +4773,31 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) return; } } + } else if (!intermediate.getAutoMapBindings()) { + // some types require bindings + + // atomic_uint + if (type.getBasicType() == EbtAtomicUint) + error(loc, "layout(binding=X) is required", "atomic_uint", ""); + + // SPIR-V + if (spvVersion.spv > 0) { + if (qualifier.isUniformOrBuffer()) { + if (type.getBasicType() == EbtBlock && !qualifier.layoutPushConstant && + !qualifier.layoutAttachment) + error(loc, "uniform/buffer blocks require layout(binding=X)", "binding", ""); + else if (spvVersion.vulkan > 0 && type.getBasicType() == EbtSampler) + error(loc, "sampler/texture/image requires layout(binding=X)", "binding", ""); + } + } } - // atomic_uint - if (type.getBasicType() == EbtAtomicUint) { - if (! type.getQualifier().hasBinding()) - error(loc, "layout(binding=X) is required", "atomic_uint", ""); + // some things can't have arrays of arrays + if (type.isArrayOfArrays()) { + if (spvVersion.vulkan > 0) { + if (type.isOpaque() || (type.getQualifier().isUniformOrBuffer() && type.getBasicType() == EbtBlock)) + warn(loc, "Generating SPIR-V array-of-arrays, but Vulkan only supports single array level for this resource", "[][]", ""); + } } // "The offset qualifier can only be used on block members of blocks..." @@ -4561,7 +4819,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) error(loc, "does not apply to unsigned integer images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), ""); if (profile == EEsProfile) { - // "Except for image variables qualified with the format qualifiers r32f, r32i, and r32ui, image variables must + // "Except for image variables qualified with the format qualifiers r32f, r32i, and r32ui, image variables must // specify either memory qualifier readonly or the memory qualifier writeonly." if (! (qualifier.layoutFormat == ElfR32f || qualifier.layoutFormat == ElfR32i || qualifier.layoutFormat == ElfR32ui)) { if (! qualifier.readonly && ! qualifier.writeonly) @@ -4569,8 +4827,11 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) } } } - } else if (type.isImage() && ! qualifier.writeonly) - error(loc, "image variables not declared 'writeonly' must have a format layout qualifier", "", ""); + } else if (type.isImage() && ! qualifier.writeonly) { + const char *explanation = "image variables not declared 'writeonly' and without a format layout qualifier"; + requireProfile(loc, ECoreProfile | ECompatibilityProfile, explanation); + profileRequires(loc, ECoreProfile | ECompatibilityProfile, 0, E_GL_EXT_shader_image_load_formatted, explanation); + } if (qualifier.layoutPushConstant && type.getBasicType() != EbtBlock) error(loc, "can only be used with a block", "push_constant", ""); @@ -4592,6 +4853,10 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) error(loc, "can only be applied to a scalar", "constant_id", ""); switch (type.getBasicType()) { + case EbtInt8: + case EbtUint8: + case EbtInt16: + case EbtUint16: case EbtInt: case EbtUint: case EbtInt64: @@ -4599,6 +4864,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) case EbtBool: case EbtFloat: case EbtDouble: + case EbtFloat16: break; default: error(loc, "cannot be applied to this type", "constant_id", ""); @@ -4620,8 +4886,8 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier if (qualifier.hasAnyLocation()) { - // "As with input layout qualifiers, all shaders except compute shaders - // allow *location* layout qualifiers on output variable declarations, + // "As with input layout qualifiers, all shaders except compute shaders + // allow *location* layout qualifiers on output variable declarations, // output block declarations, and output block member declarations." switch (qualifier.storage) { @@ -4684,11 +4950,11 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier error(loc, "requires uniform or buffer storage qualifier", "binding", ""); } if (qualifier.hasStream()) { - if (qualifier.storage != EvqVaryingOut) + if (!qualifier.isPipeOutput()) error(loc, "can only be used on an output", "stream", ""); } if (qualifier.hasXfb()) { - if (qualifier.storage != EvqVaryingOut) + if (!qualifier.isPipeOutput()) error(loc, "can only be used on an output", "xfb layout qualifier", ""); } if (qualifier.hasUniformLayout()) { @@ -4714,8 +4980,24 @@ void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQua if (shaderQualifiers.geometry != ElgNone) error(loc, message, TQualifier::getGeometryString(shaderQualifiers.geometry), ""); + if (shaderQualifiers.spacing != EvsNone) + error(loc, message, TQualifier::getVertexSpacingString(shaderQualifiers.spacing), ""); + if (shaderQualifiers.order != EvoNone) + error(loc, message, TQualifier::getVertexOrderString(shaderQualifiers.order), ""); + if (shaderQualifiers.pointMode) + error(loc, message, "point_mode", ""); if (shaderQualifiers.invocations != TQualifier::layoutNotSet) error(loc, message, "invocations", ""); + if (shaderQualifiers.earlyFragmentTests) + error(loc, message, "early_fragment_tests", ""); + if (shaderQualifiers.postDepthCoverage) + error(loc, message, "post_depth_coverage", ""); + for (int i = 0; i < 3; ++i) { + if (shaderQualifiers.localSize[i] > 1) + error(loc, message, "local_size", ""); + if (shaderQualifiers.localSizeSpecId[i] != TQualifier::layoutNotSet) + error(loc, message, "local_size id", ""); + } if (shaderQualifiers.vertices != TQualifier::layoutNotSet) { if (language == EShLangGeometry) error(loc, message, "max_vertices", ""); @@ -4724,15 +5006,10 @@ void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQua else assert(0); } - for (int i = 0; i < 3; ++i) { - if (shaderQualifiers.localSize[i] > 1) - error(loc, message, "local_size", ""); - if (shaderQualifiers.localSizeSpecId[i] != TQualifier::layoutNotSet) - error(loc, message, "local_size id", ""); - } if (shaderQualifiers.blendEquation) error(loc, message, "blend equation", ""); - // TBD: correctness: are any of these missing? pixelCenterInteger, originUpperLeft, spacing, order, pointmode, earlyfragment, depth + if (shaderQualifiers.numViews != TQualifier::layoutNotSet) + error(loc, message, "num_views", ""); } // Correct and/or advance an object's offset layout qualifier. @@ -4752,8 +5029,14 @@ void TParseContext::fixOffset(const TSourceLoc& loc, TSymbol& symbol) // Check for overlap int numOffsets = 4; - if (symbol.getType().isArray()) - numOffsets *= symbol.getType().getCumulativeArraySize(); + if (symbol.getType().isArray()) { + if (symbol.getType().isSizedArray() && !symbol.getType().getArraySizes()->isInnerUnsized()) + numOffsets *= symbol.getType().getCumulativeArraySize(); + else { + // "It is a compile-time error to declare an unsized array of atomic_uint." + error(loc, "array must be explicitly sized", "atomic_uint", ""); + } + } int repeated = intermediate.addUsedOffsets(qualifier.layoutBinding, offset, numOffsets); if (repeated >= 0) error(loc, "atomic counters sharing the same offset:", "offset", "%d", repeated); @@ -4778,10 +5061,21 @@ const TFunction* TParseContext::findFunction(const TSourceLoc& loc, const TFunct return nullptr; } + bool explicitTypesEnabled = extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types) || + extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types_int8) || + extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types_int16) || + extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types_int32) || + extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types_int64) || + extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types_float16) || + extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types_float32) || + extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types_float64); + if (profile == EEsProfile || version < 120) function = findFunctionExact(loc, call, builtIn); else if (version < 400) function = findFunction120(loc, call, builtIn); + else if (explicitTypesEnabled) + function = findFunctionExplicitTypes(loc, call, builtIn); else function = findFunction400(loc, call, builtIn); @@ -4819,10 +5113,10 @@ const TFunction* TParseContext::findFunction120(const TSourceLoc& loc, const TFu // more than one function." const TFunction* candidate = nullptr; - TVector candidateList; + TVector candidateList; symbolTable.findFunctionNameList(call.getMangledName(), candidateList, builtIn); - for (TVector::const_iterator it = candidateList.begin(); it != candidateList.end(); ++it) { + for (auto it = candidateList.begin(); it != candidateList.end(); ++it) { const TFunction& function = *(*it); // to even be a potential match, number of arguments has to match @@ -4870,13 +5164,182 @@ const TFunction* TParseContext::findFunction120(const TSourceLoc& loc, const TFu } // Function finding algorithm for desktop version 400 and above. +// +// "When function calls are resolved, an exact type match for all the arguments +// is sought. If an exact match is found, all other functions are ignored, and +// the exact match is used. If no exact match is found, then the implicit +// conversions in section 4.1.10 Implicit Conversions will be applied to find +// a match. Mismatched types on input parameters (in or inout or default) must +// have a conversion from the calling argument type to the formal parameter type. +// Mismatched types on output parameters (out or inout) must have a conversion +// from the formal parameter type to the calling argument type. +// +// "If implicit conversions can be used to find more than one matching function, +// a single best-matching function is sought. To determine a best match, the +// conversions between calling argument and formal parameter types are compared +// for each function argument and pair of matching functions. After these +// comparisons are performed, each pair of matching functions are compared. +// A function declaration A is considered a better match than function +// declaration B if +// +// * for at least one function argument, the conversion for that argument in A +// is better than the corresponding conversion in B; and +// * there is no function argument for which the conversion in B is better than +// the corresponding conversion in A. +// +// "If a single function declaration is considered a better match than every +// other matching function declaration, it will be used. Otherwise, a +// compile-time semantic error for an ambiguous overloaded function call occurs. +// +// "To determine whether the conversion for a single argument in one match is +// better than that for another match, the following rules are applied, in order: +// +// 1. An exact match is better than a match involving any implicit conversion. +// 2. A match involving an implicit conversion from float to double is better +// than a match involving any other implicit conversion. +// 3. A match involving an implicit conversion from either int or uint to float +// is better than a match involving an implicit conversion from either int +// or uint to double. +// +// "If none of the rules above apply to a particular pair of conversions, neither +// conversion is considered better than the other." +// const TFunction* TParseContext::findFunction400(const TSourceLoc& loc, const TFunction& call, bool& builtIn) { - // TODO: 4.00 functionality: findFunction400() - return findFunction120(loc, call, builtIn); + // first, look for an exact match + TSymbol* symbol = symbolTable.find(call.getMangledName(), &builtIn); + if (symbol) + return symbol->getAsFunction(); + + // no exact match, use the generic selector, parameterized by the GLSL rules + + // create list of candidates to send + TVector candidateList; + symbolTable.findFunctionNameList(call.getMangledName(), candidateList, builtIn); + + // can 'from' convert to 'to'? + const auto convertible = [this](const TType& from, const TType& to, TOperator, int) -> bool { + if (from == to) + return true; + if (from.isArray() || to.isArray() || ! from.sameElementShape(to)) + return false; + return intermediate.canImplicitlyPromote(from.getBasicType(), to.getBasicType()); + }; + + // Is 'to2' a better conversion than 'to1'? + // Ties should not be considered as better. + // Assumes 'convertible' already said true. + const auto better = [](const TType& from, const TType& to1, const TType& to2) -> bool { + // 1. exact match + if (from == to2) + return from != to1; + if (from == to1) + return false; + + // 2. float -> double is better + if (from.getBasicType() == EbtFloat) { + if (to2.getBasicType() == EbtDouble && to1.getBasicType() != EbtDouble) + return true; + } + + // 3. -> float is better than -> double + return to2.getBasicType() == EbtFloat && to1.getBasicType() == EbtDouble; + }; + + // for ambiguity reporting + bool tie = false; + + // send to the generic selector + const TFunction* bestMatch = selectFunction(candidateList, call, convertible, better, tie); + + if (bestMatch == nullptr) + error(loc, "no matching overloaded function found", call.getName().c_str(), ""); + else if (tie) + error(loc, "ambiguous best function under implicit type conversion", call.getName().c_str(), ""); + + return bestMatch; } -// When a declaration includes a type, but not a variable name, it can be +// "To determine whether the conversion for a single argument in one match +// is better than that for another match, the conversion is assigned of the +// three ranks ordered from best to worst: +// 1. Exact match: no conversion. +// 2. Promotion: integral or floating-point promotion. +// 3. Conversion: integral conversion, floating-point conversion, +// floating-integral conversion. +// A conversion C1 is better than a conversion C2 if the rank of C1 is +// better than the rank of C2." +const TFunction* TParseContext::findFunctionExplicitTypes(const TSourceLoc& loc, const TFunction& call, bool& builtIn) +{ + // first, look for an exact match + TSymbol* symbol = symbolTable.find(call.getMangledName(), &builtIn); + if (symbol) + return symbol->getAsFunction(); + + // no exact match, use the generic selector, parameterized by the GLSL rules + + // create list of candidates to send + TVector candidateList; + symbolTable.findFunctionNameList(call.getMangledName(), candidateList, builtIn); + + // can 'from' convert to 'to'? + const auto convertible = [this](const TType& from, const TType& to, TOperator, int) -> bool { + if (from == to) + return true; + if (from.isArray() || to.isArray() || ! from.sameElementShape(to)) + return false; + return intermediate.canImplicitlyPromote(from.getBasicType(), to.getBasicType()); + }; + + // Is 'to2' a better conversion than 'to1'? + // Ties should not be considered as better. + // Assumes 'convertible' already said true. + const auto better = [this](const TType& from, const TType& to1, const TType& to2) -> bool { + // 1. exact match + if (from == to2) + return from != to1; + if (from == to1) + return false; + + // 2. Promotion (integral, floating-point) is better + TBasicType from_type = from.getBasicType(); + TBasicType to1_type = to1.getBasicType(); + TBasicType to2_type = to2.getBasicType(); + bool isPromotion1 = (intermediate.isIntegralPromotion(from_type, to1_type) || + intermediate.isFPPromotion(from_type, to1_type)); + bool isPromotion2 = (intermediate.isIntegralPromotion(from_type, to2_type) || + intermediate.isFPPromotion(from_type, to2_type)); + if (isPromotion2) + return !isPromotion1; + if(isPromotion1) + return false; + + // 3. Conversion (integral, floating-point , floating-integral) + bool isConversion1 = (intermediate.isIntegralConversion(from_type, to1_type) || + intermediate.isFPConversion(from_type, to1_type) || + intermediate.isFPIntegralConversion(from_type, to1_type)); + bool isConversion2 = (intermediate.isIntegralConversion(from_type, to2_type) || + intermediate.isFPConversion(from_type, to2_type) || + intermediate.isFPIntegralConversion(from_type, to2_type)); + + return isConversion2 && !isConversion1; + }; + + // for ambiguity reporting + bool tie = false; + + // send to the generic selector + const TFunction* bestMatch = selectFunction(candidateList, call, convertible, better, tie); + + if (bestMatch == nullptr) + error(loc, "no matching overloaded function found", call.getName().c_str(), ""); + else if (tie) + error(loc, "ambiguous best function under implicit type conversion", call.getName().c_str(), ""); + + return bestMatch; +} + +// When a declaration includes a type, but not a variable name, it can be // to establish defaults. void TParseContext::declareTypeDefaults(const TSourceLoc& loc, const TPublicType& publicType) { @@ -4904,27 +5367,27 @@ void TParseContext::declareTypeDefaults(const TSourceLoc& loc, const TPublicType // 'publicType' is the type part of the declaration (to the left) // 'arraySizes' is the arrayness tagged on the identifier (to the right) // -TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& identifier, const TPublicType& publicType, TArraySizes* arraySizes, TIntermTyped* initializer) +TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& identifier, const TPublicType& publicType, + TArraySizes* arraySizes, TIntermTyped* initializer) { - TType type(publicType); // shallow copy; 'type' shares the arrayness and structure definition with 'publicType' - if (type.isImplicitlySizedArray()) { - // Because "int[] a = int[2](...), b = int[3](...)" makes two arrays a and b - // of different sizes, for this case sharing the shallow copy of arrayness - // with the publicType oversubscribes it, so get a deep copy of the arrayness. - type.newArraySizes(*publicType.arraySizes); - } + // Make a fresh type that combines the characteristics from the individual + // identifier syntax and the declaration-type syntax. + TType type(publicType); + type.transferArraySizes(arraySizes); + type.copyArrayInnerSizes(publicType.arraySizes); + arrayOfArrayVersionCheck(loc, type.getArraySizes()); if (voidErrorCheck(loc, identifier, type.getBasicType())) return nullptr; - if (initializer) + if (initializer) rValueErrorCheck(loc, "initializer", initializer); else nonInitConstCheck(loc, identifier, type); samplerCheck(loc, type, identifier, initializer); atomicUintCheck(loc, type, identifier); - transparentCheck(loc, type, identifier); + transparentOpaqueCheck(loc, type, identifier); if (identifier != "gl_FragCoord" && (publicType.shaderQualifiers.originUpperLeft || publicType.shaderQualifiers.pixelCenterInteger)) error(loc, "can only apply origin_upper_left and pixel_center_origin to gl_FragCoord", "layout qualifier", ""); @@ -4932,26 +5395,19 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden error(loc, "can only apply depth layout to gl_FragDepth", "layout qualifier", ""); // Check for redeclaration of built-ins and/or attempting to declare a reserved name - bool newDeclaration = false; // true if a new entry gets added to the symbol table - TSymbol* symbol = redeclareBuiltinVariable(loc, identifier, type.getQualifier(), publicType.shaderQualifiers, newDeclaration); - if (! symbol) + TSymbol* symbol = redeclareBuiltinVariable(loc, identifier, type.getQualifier(), publicType.shaderQualifiers); + if (symbol == nullptr) reservedErrorCheck(loc, identifier); inheritGlobalDefaults(type.getQualifier()); // Declare the variable - if (arraySizes || type.isArray()) { - // Arrayness is potentially coming both from the type and from the - // variable: "int[] a[];" or just one or the other. - // Merge it all to the type, so all arrayness is part of the type. - arrayDimCheck(loc, &type, arraySizes); - arrayDimMerge(type, arraySizes); - + if (type.isArray()) { // Check that implicit sizing is only where allowed. - arrayUnsizedCheck(loc, type.getQualifier(), &type.getArraySizes(), initializer != nullptr, false); + arraySizesCheck(loc, type.getQualifier(), type.getArraySizes(), initializer, false); if (! arrayQualifierError(loc, type.getQualifier()) && ! arrayError(loc, type)) - declareArray(loc, identifier, type, symbol, newDeclaration); + declareArray(loc, identifier, type, symbol); if (initializer) { profileRequires(loc, ENoProfile, 120, E_GL_3DL_array_objects, "initializer"); @@ -4959,18 +5415,18 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden } } else { // non-array case - if (! symbol) - symbol = declareNonArray(loc, identifier, type, newDeclaration); + if (symbol == nullptr) + symbol = declareNonArray(loc, identifier, type); else if (type != symbol->getType()) error(loc, "cannot change the type of", "redeclaration", symbol->getName().c_str()); } - if (! symbol) + if (symbol == nullptr) return nullptr; // Deal with initializer TIntermNode* initNode = nullptr; - if (symbol && initializer) { + if (symbol != nullptr && initializer) { TVariable* variable = symbol->getAsVariable(); if (! variable) { error(loc, "initializer requires a variable, not a member", identifier.c_str(), ""); @@ -4981,11 +5437,9 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden // look for errors in layout qualifier use layoutObjectCheck(loc, *symbol); - fixOffset(loc, *symbol); - // see if it's a linker-level object to track - if (newDeclaration && symbolTable.atGlobalLevel()) - intermediate.addSymbolLinkageNode(linkage, *symbol); + // fix up + fixOffset(loc, *symbol); return initNode; } @@ -5009,7 +5463,7 @@ void TParseContext::inheritGlobalDefaults(TQualifier& dst) const // TVariable* TParseContext::makeInternalVariable(const char* name, const TType& type) const { - TString* nameString = new TString(name); + TString* nameString = NewPoolTString(name); TVariable* variable = new TVariable(nameString, type); symbolTable.makeInternalVariable(*variable); @@ -5022,20 +5476,22 @@ TVariable* TParseContext::makeInternalVariable(const char* name, const TType& ty // // Return the successfully declared variable. // -TVariable* TParseContext::declareNonArray(const TSourceLoc& loc, TString& identifier, TType& type, bool& newDeclaration) +TVariable* TParseContext::declareNonArray(const TSourceLoc& loc, const TString& identifier, const TType& type) { // make a new variable TVariable* variable = new TVariable(&identifier, type); ioArrayCheck(loc, type, identifier); + // add variable to symbol table - if (! symbolTable.insert(*variable)) { - error(loc, "redefinition", variable->getName().c_str(), ""); - return nullptr; - } else { - newDeclaration = true; + if (symbolTable.insert(*variable)) { + if (symbolTable.atGlobalLevel()) + trackLinkage(*variable); return variable; } + + error(loc, "redefinition", variable->getName().c_str(), ""); + return nullptr; } // @@ -5079,8 +5535,7 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp } // Fix outer arrayness if variable is unsized, getting size from the initializer - if (initializer->getType().isExplicitlySizedArray() && - variable->getType().isImplicitlySizedArray()) + if (initializer->getType().isSizedArray() && variable->getType().isUnsizedArray()) variable->getWritableType().changeOuterArraySize(initializer->getType().getOuterArraySize()); // Inner arrayness can also get set by an initializer @@ -5089,8 +5544,10 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp variable->getType().getArraySizes()->getNumDims()) { // adopt unsized sizes from the initializer's sizes for (int d = 1; d < variable->getType().getArraySizes()->getNumDims(); ++d) { - if (variable->getType().getArraySizes()->getDimSize(d) == UnsizedArraySize) - variable->getWritableType().getArraySizes().setDimSize(d, initializer->getType().getArraySizes()->getDimSize(d)); + if (variable->getType().getArraySizes()->getDimSize(d) == UnsizedArraySize) { + variable->getWritableType().getArraySizes()->setDimSize(d, + initializer->getType().getArraySizes()->getDimSize(d)); + } } } @@ -5201,16 +5658,16 @@ TIntermTyped* TParseContext::convertInitializerList(const TSourceLoc& loc, const // Later on, initializer execution code will deal with array size logic. TType arrayType; arrayType.shallowCopy(type); // sharing struct stuff is fine - arrayType.newArraySizes(*type.getArraySizes()); // but get a fresh copy of the array information, to edit below + arrayType.copyArraySizes(*type.getArraySizes()); // but get a fresh copy of the array information, to edit below // edit array sizes to fill in unsized dimensions arrayType.changeOuterArraySize((int)initList->getSequence().size()); TIntermTyped* firstInit = initList->getSequence()[0]->getAsTyped(); if (arrayType.isArrayOfArrays() && firstInit->getType().isArray() && - arrayType.getArraySizes().getNumDims() == firstInit->getType().getArraySizes()->getNumDims() + 1) { - for (int d = 1; d < arrayType.getArraySizes().getNumDims(); ++d) { - if (arrayType.getArraySizes().getDimSize(d) == UnsizedArraySize) - arrayType.getArraySizes().setDimSize(d, firstInit->getType().getArraySizes()->getDimSize(d - 1)); + arrayType.getArraySizes()->getNumDims() == firstInit->getType().getArraySizes()->getNumDims() + 1) { + for (int d = 1; d < arrayType.getArraySizes()->getNumDims(); ++d) { + if (arrayType.getArraySizes()->getDimSize(d) == UnsizedArraySize) + arrayType.getArraySizes()->setDimSize(d, firstInit->getType().getArraySizes()->getDimSize(d - 1)); } } @@ -5221,7 +5678,7 @@ TIntermTyped* TParseContext::convertInitializerList(const TSourceLoc& loc, const return nullptr; } - return addConstructor(loc, initList, arrayType, mapTypeToConstructorOp(arrayType)); + return addConstructor(loc, initList, arrayType); } else if (type.isStruct()) { if (type.getStruct()->size() != initList->getSequence().size()) { error(loc, "wrong number of structure members", "initializer list", ""); @@ -5253,23 +5710,33 @@ TIntermTyped* TParseContext::convertInitializerList(const TSourceLoc& loc, const return nullptr; } - // now that the subtree is processed, process this node - return addConstructor(loc, initList, type, mapTypeToConstructorOp(type)); + // Now that the subtree is processed, process this node as if the + // initializer list is a set of arguments to a constructor. + TIntermNode* emulatedConstructorArguments; + if (initList->getSequence().size() == 1) + emulatedConstructorArguments = initList->getSequence()[0]; + else + emulatedConstructorArguments = initList; + return addConstructor(loc, emulatedConstructorArguments, type); } // // Test for the correctness of the parameters passed to various constructor functions // and also convert them to the right data type, if allowed and required. // +// 'node' is what to construct from. +// 'type' is what type to construct. +// // Returns nullptr for an error or the constructed node (aggregate or typed) for no error. // -TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode* node, const TType& type, TOperator op) +TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode* node, const TType& type) { if (node == nullptr || node->getAsTyped() == nullptr) return nullptr; rValueErrorCheck(loc, "constructor", node->getAsTyped()); TIntermAggregate* aggrNode = node->getAsAggregate(); + TOperator op = intermediate.mapTypeToConstructorOp(type); // Combined texture-sampler constructors are completely semantic checked // in constructorTextureSamplerError() @@ -5289,7 +5756,7 @@ TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode* bool singleArg; if (aggrNode) { - if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1) + if (aggrNode->getOp() != EOpNull) singleArg = true; else singleArg = false; @@ -5350,8 +5817,22 @@ TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode* // // Returns nullptr for an error or the constructed node. // -TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, TIntermTyped* node, const TSourceLoc& loc, bool subset) +TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, TIntermTyped* node, const TSourceLoc& loc, + bool subset) { + // If we are changing a matrix in both domain of basic type and to a non matrix, + // do the shape change first (by default, below, basic type is changed before shape). + // This avoids requesting a matrix of a new type that is going to be discarded anyway. + // TODO: This could be generalized to more type combinations, but that would require + // more extensive testing and full algorithm rework. For now, the need to do two changes makes + // the recursive call work, and avoids the most aggregious case of creating integer matrices. + if (node->getType().isMatrix() && (type.isScalar() || type.isVector()) && + type.isFloatingDomain() != node->getType().isFloatingDomain()) { + TType transitionType(node->getBasicType(), glslang::EvqTemporary, type.getVectorSize(), 0, 0, node->isVector()); + TOperator transitionOp = intermediate.mapTypeToConstructorOp(transitionType); + node = constructBuiltIn(transitionType, transitionOp, node, loc, false); + } + TIntermTyped* newNode; TOperator basicOp; @@ -5391,6 +5872,50 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T basicOp = EOpConstructDouble; break; + case EOpConstructF16Vec2: + case EOpConstructF16Vec3: + case EOpConstructF16Vec4: + case EOpConstructF16Mat2x2: + case EOpConstructF16Mat2x3: + case EOpConstructF16Mat2x4: + case EOpConstructF16Mat3x2: + case EOpConstructF16Mat3x3: + case EOpConstructF16Mat3x4: + case EOpConstructF16Mat4x2: + case EOpConstructF16Mat4x3: + case EOpConstructF16Mat4x4: + case EOpConstructFloat16: + basicOp = EOpConstructFloat16; + break; + + case EOpConstructI8Vec2: + case EOpConstructI8Vec3: + case EOpConstructI8Vec4: + case EOpConstructInt8: + basicOp = EOpConstructInt8; + break; + + case EOpConstructU8Vec2: + case EOpConstructU8Vec3: + case EOpConstructU8Vec4: + case EOpConstructUint8: + basicOp = EOpConstructUint8; + break; + + case EOpConstructI16Vec2: + case EOpConstructI16Vec3: + case EOpConstructI16Vec4: + case EOpConstructInt16: + basicOp = EOpConstructInt16; + break; + + case EOpConstructU16Vec2: + case EOpConstructU16Vec3: + case EOpConstructU16Vec4: + case EOpConstructUint16: + basicOp = EOpConstructUint16; + break; + case EOpConstructIVec2: case EOpConstructIVec3: case EOpConstructIVec4: @@ -5426,6 +5951,11 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T basicOp = EOpConstructBool; break; + case EOpConstructNonuniform: + node->getWritableType().getQualifier().nonUniform = true; + return node; + break; + default: error(loc, "unsupported construction", "", ""); @@ -5470,13 +6000,14 @@ TIntermTyped* TParseContext::constructAggregate(TIntermNode* node, const TType& // // Do everything needed to add an interface block. // -void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, const TString* instanceName, TArraySizes* arraySizes) +void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, const TString* instanceName, + TArraySizes* arraySizes) { blockStageIoCheck(loc, currentBlockQualifier); blockQualifierCheck(loc, currentBlockQualifier, instanceName != nullptr); - if (arraySizes) { - arrayUnsizedCheck(loc, currentBlockQualifier, arraySizes, false, false); - arrayDimCheck(loc, arraySizes, 0); + if (arraySizes != nullptr) { + arraySizesCheck(loc, currentBlockQualifier, arraySizes, nullptr, false); + arrayOfArrayVersionCheck(loc, arraySizes); if (arraySizes->getNumDims() > 1) requireProfile(loc, ~EEsProfile, "array-of-array of block"); } @@ -5493,10 +6024,12 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con if ((currentBlockQualifier.storage == EvqUniform || currentBlockQualifier.storage == EvqBuffer) && (memberQualifier.isInterpolation() || memberQualifier.isAuxiliary())) error(memberLoc, "member of uniform or buffer block cannot have an auxiliary or interpolation qualifier", memberType.getFieldName().c_str(), ""); if (memberType.isArray()) - arrayUnsizedCheck(memberLoc, currentBlockQualifier, &memberType.getArraySizes(), false, member == typeList.size() - 1); + arraySizesCheck(memberLoc, currentBlockQualifier, memberType.getArraySizes(), nullptr, member == typeList.size() - 1); if (memberQualifier.hasOffset()) { - requireProfile(memberLoc, ~EEsProfile, "offset on block member"); - profileRequires(memberLoc, ~EEsProfile, 440, E_GL_ARB_enhanced_layouts, "offset on block member"); + if (spvVersion.spv == 0) { + requireProfile(memberLoc, ~EEsProfile, "offset on block member"); + profileRequires(memberLoc, ~EEsProfile, 440, E_GL_ARB_enhanced_layouts, "offset on block member"); + } } if (memberType.containsOpaque()) @@ -5537,11 +6070,10 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con mergeObjectLayoutQualifiers(defaultQualification, currentBlockQualifier, true); - // "The offset qualifier can only be used on block members of blocks declared with std140 or std430 layouts." // "The align qualifier can only be used on blocks or block members, and only for blocks declared with std140 or std430 layouts." - if (currentBlockQualifier.hasAlign() || currentBlockQualifier.hasAlign()) { + if (currentBlockQualifier.hasAlign()) { if (defaultQualification.layoutPacking != ElpStd140 && defaultQualification.layoutPacking != ElpStd430) { - error(loc, "can only be used with std140 or std430 layout packing", "offset/align", ""); + error(loc, "can only be used with std140 or std430 layout packing", "align", ""); defaultQualification.layoutAlign = -1; } } @@ -5556,9 +6088,9 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con error(memberLoc, "member cannot contradict block", "stream", ""); } - // "This includes a block's inheritance of the - // current global default buffer, a block member's inheritance of the block's - // buffer, and the requirement that any *xfb_buffer* declared on a block + // "This includes a block's inheritance of the + // current global default buffer, a block member's inheritance of the block's + // buffer, and the requirement that any *xfb_buffer* declared on a block // member must match the buffer inherited from the block." if (memberQualifier.hasXfbBuffer()) { if (defaultQualification.layoutXfbBuffer != memberQualifier.layoutXfbBuffer) @@ -5574,7 +6106,7 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con case EvqVaryingOut: requireProfile(memberLoc, ECoreProfile | ECompatibilityProfile | EEsProfile, feature); profileRequires(memberLoc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, feature); - profileRequires(memberLoc, EEsProfile, 0, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, feature); + profileRequires(memberLoc, EEsProfile, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, feature); memberWithLocation = true; break; default: @@ -5583,9 +6115,12 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con } } else memberWithoutLocation = true; - if (memberQualifier.hasAlign()) { + + // "The offset qualifier can only be used on block members of blocks declared with std140 or std430 layouts." + // "The align qualifier can only be used on blocks or block members, and only for blocks declared with std140 or std430 layouts." + if (memberQualifier.hasAlign() || memberQualifier.hasOffset()) { if (defaultQualification.layoutPacking != ElpStd140 && defaultQualification.layoutPacking != ElpStd430) - error(memberLoc, "can only be used with std140 or std430 layout packing", "align", ""); + error(memberLoc, "can only be used with std140 or std430 layout packing", "offset/align", ""); } TQualifier newMemberQualification = defaultQualification; @@ -5593,6 +6128,8 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con memberQualifier = newMemberQualification; } + layoutMemberLocationArrayCheck(loc, memberWithLocation, arraySizes); + // Process the members fixBlockLocations(loc, currentBlockQualifier, typeList, memberWithLocation, memberWithoutLocation); fixBlockXfbOffsets(currentBlockQualifier, typeList); @@ -5609,8 +6146,8 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con // TType blockType(&typeList, *blockName, currentBlockQualifier); - if (arraySizes) - blockType.newArraySizes(*arraySizes); + if (arraySizes != nullptr) + blockType.transferArraySizes(arraySizes); else ioArrayCheck(loc, blockType, instanceName ? *instanceName : *blockName); @@ -5660,6 +6197,7 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con // Check for general layout qualifier errors layoutObjectCheck(loc, variable); + // fix up if (isIoResizeArray(blockType)) { ioArraySymbolResizeList.push_back(&variable); checkIoArraysConsistency(loc, true); @@ -5667,7 +6205,7 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con fixIoArraySize(loc, variable.getWritableType()); // Save it in the AST for linker use. - intermediate.addSymbolLinkageNode(linkage, variable); + trackLinkage(variable); } // Do all block-declaration checking regarding the combination of in/out/uniform/buffer @@ -5692,14 +6230,14 @@ void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& q // "Compute shaders do not permit user-defined input variables..." requireStage(loc, (EShLanguageMask)(EShLangTessControlMask|EShLangTessEvaluationMask|EShLangGeometryMask|EShLangFragmentMask), "input block"); if (language == EShLangFragment) - profileRequires(loc, EEsProfile, 0, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, "fragment input block"); + profileRequires(loc, EEsProfile, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, "fragment input block"); break; case EvqVaryingOut: profileRequires(loc, ~EEsProfile, 150, E_GL_ARB_separate_shader_objects, "output block"); requireStage(loc, (EShLanguageMask)(EShLangVertexMask|EShLangTessControlMask|EShLangTessEvaluationMask|EShLangGeometryMask), "output block"); // ES 310 can have a block before shader_io is turned on, so skip this test for built-ins if (language == EShLangVertex && ! parsingBuiltins) - profileRequires(loc, EEsProfile, 0, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, "vertex output block"); + profileRequires(loc, EEsProfile, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, "vertex output block"); break; default: error(loc, "only uniform, buffer, in, or out blocks are supported", blockName->c_str(), ""); @@ -5708,7 +6246,7 @@ void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& q } // Do all block-declaration checking regarding its qualifiers. -void TParseContext::blockQualifierCheck(const TSourceLoc& loc, const TQualifier& qualifier, bool instanceName) +void TParseContext::blockQualifierCheck(const TSourceLoc& loc, const TQualifier& qualifier, bool /*instanceName*/) { // The 4.5 specification says: // @@ -5735,23 +6273,20 @@ void TParseContext::blockQualifierCheck(const TSourceLoc& loc, const TQualifier& error(loc, "cannot use sample qualifier on an interface block", "sample", ""); if (qualifier.invariant) error(loc, "cannot use invariant qualifier on an interface block", "invariant", ""); - if (qualifier.layoutPushConstant) { + if (qualifier.layoutPushConstant) intermediate.addPushConstantCount(); - if (! instanceName) - error(loc, "requires an instance name", "push_constant", ""); - } } // -// "For a block, this process applies to the entire block, or until the first member -// is reached that has a location layout qualifier. When a block member is declared with a location +// "For a block, this process applies to the entire block, or until the first member +// is reached that has a location layout qualifier. When a block member is declared with a location // qualifier, its location comes from that qualifier: The member's location qualifier overrides the block-level -// declaration. Subsequent members are again assigned consecutive locations, based on the newest location, -// until the next member declared with a location qualifier. The values used for locations do not have to be +// declaration. Subsequent members are again assigned consecutive locations, based on the newest location, +// until the next member declared with a location qualifier. The values used for locations do not have to be // declared in increasing order." void TParseContext::fixBlockLocations(const TSourceLoc& loc, TQualifier& qualifier, TTypeList& typeList, bool memberWithLocation, bool memberWithoutLocation) { - // "If a block has no block-level location layout qualifier, it is required that either all or none of its members + // "If a block has no block-level location layout qualifier, it is required that either all or none of its members // have a location layout qualifier, or a compile-time error results." if (! qualifier.hasLocation() && memberWithLocation && memberWithoutLocation) error(loc, "either the block needs a location, or all members need a location, or no members have a location", "location", ""); @@ -5777,9 +6312,10 @@ void TParseContext::fixBlockLocations(const TSourceLoc& loc, TQualifier& qualifi if (nextLocation >= (int)TQualifier::layoutLocationEnd) error(memberLoc, "location is too large", "location", ""); memberQualifier.layoutLocation = nextLocation; - memberQualifier.layoutComponent = 0; + memberQualifier.layoutComponent = TQualifier::layoutComponentEnd; } - nextLocation = memberQualifier.layoutLocation + intermediate.computeTypeLocationSize(*typeList[member].type); + nextLocation = memberQualifier.layoutLocation + intermediate.computeTypeLocationSize( + *typeList[member].type, language); } } } @@ -5787,9 +6323,9 @@ void TParseContext::fixBlockLocations(const TSourceLoc& loc, TQualifier& qualifi void TParseContext::fixBlockXfbOffsets(TQualifier& qualifier, TTypeList& typeList) { - // "If a block is qualified with xfb_offset, all its - // members are assigned transform feedback buffer offsets. If a block is not qualified with xfb_offset, any - // members of that block not qualified with an xfb_offset will not be assigned transform feedback buffer + // "If a block is qualified with xfb_offset, all its + // members are assigned transform feedback buffer offsets. If a block is not qualified with xfb_offset, any + // members of that block not qualified with an xfb_offset will not be assigned transform feedback buffer // offsets." if (! qualifier.hasXfbBuffer() || ! qualifier.hasXfbOffset()) @@ -5816,10 +6352,10 @@ void TParseContext::fixBlockXfbOffsets(TQualifier& qualifier, TTypeList& typeLis qualifier.layoutXfbOffset = TQualifier::layoutXfbOffsetEnd; } -// Calculate and save the offset of each block member, using the recursively +// Calculate and save the offset of each block member, using the recursively // defined block offset rules and the user-provided offset and align. // -// Also, compute and save the total size of the block. For the block's size, arrayness +// Also, compute and save the total size of the block. For the block's size, arrayness // is not taken into account, as each element is backed by a separate buffer. // void TParseContext::fixBlockUniformOffsets(TQualifier& qualifier, TTypeList& typeList) @@ -5843,30 +6379,37 @@ void TParseContext::fixBlockUniformOffsets(TQualifier& qualifier, TTypeList& typ int memberAlignment = intermediate.getBaseAlignment(*typeList[member].type, memberSize, dummyStride, qualifier.layoutPacking == ElpStd140, subMatrixLayout != ElmNone ? subMatrixLayout == ElmRowMajor : qualifier.layoutMatrix == ElmRowMajor); if (memberQualifier.hasOffset()) { - // "The specified offset must be a multiple + // "The specified offset must be a multiple // of the base alignment of the type of the block member it qualifies, or a compile-time error results." if (! IsMultipleOfPow2(memberQualifier.layoutOffset, memberAlignment)) error(memberLoc, "must be a multiple of the member's alignment", "offset", ""); - // "It is a compile-time error to specify an offset that is smaller than the offset of the previous + // GLSL: "It is a compile-time error to specify an offset that is smaller than the offset of the previous // member in the block or that lies within the previous member of the block" - if (memberQualifier.layoutOffset < offset) - error(memberLoc, "cannot lie in previous members", "offset", ""); + if (spvVersion.spv == 0) { + if (memberQualifier.layoutOffset < offset) + error(memberLoc, "cannot lie in previous members", "offset", ""); - // "The offset qualifier forces the qualified member to start at or after the specified - // integral-constant expression, which will be its byte offset from the beginning of the buffer. - // "The actual offset of a member is computed as - // follows: If offset was declared, start with that offset, otherwise start with the next available offset." - offset = std::max(offset, memberQualifier.layoutOffset); + // "The offset qualifier forces the qualified member to start at or after the specified + // integral-constant expression, which will be its byte offset from the beginning of the buffer. + // "The actual offset of a member is computed as + // follows: If offset was declared, start with that offset, otherwise start with the next available offset." + offset = std::max(offset, memberQualifier.layoutOffset); + } else { + // TODO: Vulkan: "It is a compile-time error to have any offset, explicit or assigned, + // that lies within another member of the block." + + offset = memberQualifier.layoutOffset; + } } - // "The actual alignment of a member will be the greater of the specified align alignment and the standard + // "The actual alignment of a member will be the greater of the specified align alignment and the standard // (e.g., std140) base alignment for the member's type." if (memberQualifier.hasAlign()) memberAlignment = std::max(memberAlignment, memberQualifier.layoutAlign); // "If the resulting offset is not a multiple of the actual alignment, - // increase it to the first offset that is a multiple of + // increase it to the first offset that is a multiple of // the actual alignment." RoundToPow2(offset, memberAlignment); typeList[member].type->getQualifier().layoutOffset = offset; @@ -5956,7 +6499,7 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con error(loc, "can only apply to 'out'", id, ""); if (! intermediate.setVertices(publicType.shaderQualifiers.vertices)) error(loc, "cannot change previously set layout value", id, ""); - + if (language == EShLangTessControl) checkIoArraysConsistency(loc); } @@ -6061,6 +6604,12 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con else error(loc, "can only apply to 'in'", "early_fragment_tests", ""); } + if (publicType.shaderQualifiers.postDepthCoverage) { + if (publicType.qualifier.storage == EvqVaryingIn) + intermediate.setPostDepthCoverage(); + else + error(loc, "can only apply to 'in'", "post_coverage_coverage", ""); + } if (publicType.shaderQualifiers.blendEquation) { if (publicType.qualifier.storage != EvqVaryingOut) error(loc, "can only apply to 'out'", "blend equation", ""); diff --git a/Externals/glslang/glslang/MachineIndependent/ParseHelper.h b/Externals/glslang/glslang/MachineIndependent/ParseHelper.h index 4187de1924..dd8e30d20e 100644 --- a/Externals/glslang/glslang/MachineIndependent/ParseHelper.h +++ b/Externals/glslang/glslang/MachineIndependent/ParseHelper.h @@ -1,12 +1,12 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2012-2013 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2012-2013 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,18 +20,18 @@ // 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. +// 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. // // @@ -44,14 +44,15 @@ #ifndef _PARSER_HELPER_INCLUDED_ #define _PARSER_HELPER_INCLUDED_ +#include +#include + #include "parseVersions.h" #include "../Include/ShHandle.h" #include "SymbolTable.h" #include "localintermediate.h" #include "Scan.h" -#include - -#include +#include "attribute.h" namespace glslang { @@ -73,18 +74,41 @@ typedef std::set TIdSetType; // class TParseContextBase : public TParseVersions { public: - TParseContextBase(TSymbolTable& symbolTable, TIntermediate& interm, int version, + TParseContextBase(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins, int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, - TInfoSink& infoSink, bool forwardCompatible, EShMessages messages) + TInfoSink& infoSink, bool forwardCompatible, EShMessages messages, + const TString* entryPoint = nullptr) : TParseVersions(interm, version, profile, spvVersion, language, infoSink, forwardCompatible, messages), - symbolTable(symbolTable), tokensBeforeEOF(false), - linkage(nullptr), scanContext(nullptr), ppContext(nullptr) { } + scopeMangler("::"), + symbolTable(symbolTable), + statementNestingLevel(0), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), + postEntryPointReturn(false), + contextPragma(true, false), + parsingBuiltins(parsingBuiltins), scanContext(nullptr), ppContext(nullptr), + limits(resources.limits), + globalUniformBlock(nullptr), + globalUniformBinding(TQualifier::layoutBindingEnd), + globalUniformSet(TQualifier::layoutSetEnd) + { + if (entryPoint != nullptr) + sourceEntryPointName = *entryPoint; + } virtual ~TParseContextBase() { } - + + virtual void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, ...); + virtual void C_DECL warn(const TSourceLoc&, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, ...); + virtual void C_DECL ppError(const TSourceLoc&, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, ...); + virtual void C_DECL ppWarn(const TSourceLoc&, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, ...); + virtual void setLimits(const TBuiltInResource&) = 0; - + + void checkIndex(const TSourceLoc&, const TType&, int& index); + EShLanguage getLanguage() const { return language; } - TIntermAggregate*& getLinkage() { return linkage; } void setScanContext(TScanContext* c) { scanContext = c; } TScanContext* getScanContext() const { return scanContext; } void setPpContext(TPpContext* c) { ppContext = c; } @@ -124,16 +148,51 @@ public: extensionCallback(line, extension, behavior); } - TSymbolTable& symbolTable; // symbol table that goes with the current language, version, and profile - bool tokensBeforeEOF; + // Manage the global uniform block (default uniforms in GLSL, $Global in HLSL) + virtual void growGlobalUniformBlock(const TSourceLoc&, TType&, const TString& memberName, TTypeList* typeList = nullptr); + + // Potentially rename shader entry point function + void renameShaderFunction(TString*& name) const + { + // Replace the entry point name given in the shader with the real entry point name, + // if there is a substitution. + if (name != nullptr && *name == sourceEntryPointName && intermediate.getEntryPointName().size() > 0) + name = NewPoolTString(intermediate.getEntryPointName().c_str()); + } + + virtual bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*); + virtual void rValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*); + + const char* const scopeMangler; + + // Basic parsing state, easily accessible to the grammar + + TSymbolTable& symbolTable; // symbol table that goes with the current language, version, and profile + int statementNestingLevel; // 0 if outside all flow control or compound statements + int loopNestingLevel; // 0 if outside all loops + int structNestingLevel; // 0 if outside blocks and structures + int controlFlowNestingLevel; // 0 if outside all flow control + const TType* currentFunctionType; // the return type of the function that's currently being parsed + bool functionReturnsValue; // true if a non-void function has a return + // if inside a function, true if the function is the entry point and this is after a return statement + bool postEntryPointReturn; + // case, node, case, case, node, ...; ensure only one node between cases; stack of them for nesting + TList switchSequenceStack; + // the statementNestingLevel the current switch statement is at, which must match the level of its case statements + TList switchLevel; + struct TPragma contextPragma; protected: TParseContextBase(TParseContextBase&); TParseContextBase& operator=(TParseContextBase&); - TIntermAggregate* linkage; // aggregate node of objects the linker may need, if not referenced by the rest of the AST + const bool parsingBuiltins; // true if parsing built-in symbols/functions + TVector linkageSymbols; // will be transferred to 'linkage', after all editing is done, order preserving TScanContext* scanContext; TPpContext* ppContext; + TBuiltInResource resources; + TLimits& limits; + TString sourceEntryPointName; // These, if set, will be called when a line, pragma ... is preprocessed. // They will be called with any parameters to the original directive. @@ -142,6 +201,66 @@ protected: std::function versionCallback; std::function extensionCallback; std::function errorCallback; + + // see implementation for detail + const TFunction* selectFunction(const TVector, const TFunction&, + std::function, + std::function, + /* output */ bool& tie); + + virtual void parseSwizzleSelector(const TSourceLoc&, const TString&, int size, + TSwizzleSelectors&); + + // Manage the global uniform block (default uniforms in GLSL, $Global in HLSL) + TVariable* globalUniformBlock; // the actual block, inserted into the symbol table + unsigned int globalUniformBinding; // the block's binding number + unsigned int globalUniformSet; // the block's set number + int firstNewMember; // the index of the first member not yet inserted into the symbol table + // override this to set the language-specific name + virtual const char* getGlobalUniformBlockName() const { return ""; } + virtual void setUniformBlockDefaults(TType&) const { } + virtual void finalizeGlobalUniformBlockLayout(TVariable&) { } + virtual void outputMessage(const TSourceLoc&, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, TPrefixType prefix, + va_list args); + virtual void trackLinkage(TSymbol& symbol); + virtual void makeEditable(TSymbol*&); + virtual TVariable* getEditableVariable(const char* name); + virtual void finish(); +}; + +// +// Manage the state for when to respect precision qualifiers and when to warn about +// the defaults being different than might be expected. +// +class TPrecisionManager { +public: + TPrecisionManager() : obey(false), warn(false), explicitIntDefault(false), explicitFloatDefault(false){ } + virtual ~TPrecisionManager() {} + + void respectPrecisionQualifiers() { obey = true; } + bool respectingPrecisionQualifiers() const { return obey; } + bool shouldWarnAboutDefaults() const { return warn; } + void defaultWarningGiven() { warn = false; } + void warnAboutDefaults() { warn = true; } + void explicitIntDefaultSeen() + { + explicitIntDefault = true; + if (explicitFloatDefault) + warn = false; + } + void explicitFloatDefaultSeen() + { + explicitFloatDefault = true; + if (explicitIntDefault) + warn = false; + } + +protected: + bool obey; // respect precision qualifiers + bool warn; // need to give a warning about the defaults + bool explicitIntDefault; // user set the default for int/uint + bool explicitFloatDefault; // user set the default for float }; // @@ -152,36 +271,29 @@ protected: class TParseContext : public TParseContextBase { public: TParseContext(TSymbolTable&, TIntermediate&, bool parsingBuiltins, int version, EProfile, const SpvVersion& spvVersion, EShLanguage, TInfoSink&, - bool forwardCompatible = false, EShMessages messages = EShMsgDefault); + bool forwardCompatible = false, EShMessages messages = EShMsgDefault, + const TString* entryPoint = nullptr); virtual ~TParseContext(); - void setLimits(const TBuiltInResource&); - bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false); + bool obeyPrecisionQualifiers() const { return precisionManager.respectingPrecisionQualifiers(); }; + void setPrecisionDefaults(); + + void setLimits(const TBuiltInResource&) override; + bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false) override; void parserError(const char* s); // for bison's yyerror - void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...); - void C_DECL warn(const TSourceLoc&, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...); - void C_DECL ppError(const TSourceLoc&, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...); - void C_DECL ppWarn(const TSourceLoc&, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...); - void reservedErrorCheck(const TSourceLoc&, const TString&); - void reservedPpErrorCheck(const TSourceLoc&, const char* name, const char* op); - bool lineContinuationCheck(const TSourceLoc&, bool endOfComment); - bool lineDirectiveShouldSetNextLine() const; + void reservedPpErrorCheck(const TSourceLoc&, const char* name, const char* op) override; + bool lineContinuationCheck(const TSourceLoc&, bool endOfComment) override; + bool lineDirectiveShouldSetNextLine() const override; bool builtInName(const TString&); - void handlePragma(const TSourceLoc&, const TVector&); + void handlePragma(const TSourceLoc&, const TVector&) override; TIntermTyped* handleVariable(const TSourceLoc&, TSymbol* symbol, const TString* string); TIntermTyped* handleBracketDereference(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index); - void checkIndex(const TSourceLoc&, const TType&, int& index); void handleIndexLimits(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index); - void makeEditable(TSymbol*&); - TVariable* getEditableVariable(const char* name); + void makeEditable(TSymbol*&) override; bool isIoResizeArray(const TType&) const; void fixIoArraySize(const TSourceLoc&, TType&); void ioArrayCheck(const TSourceLoc&, const TType&, const TString& identifier); @@ -197,6 +309,8 @@ public: TFunction* handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype); TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&); TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*); + TIntermTyped* handleBuiltInFunctionCall(TSourceLoc, TIntermNode* arguments, const TFunction& function); + void computeBuiltinPrecisions(TIntermTyped&, const TFunction&); TIntermNode* handleReturnValue(const TSourceLoc&, TIntermTyped*); void checkLocation(const TSourceLoc&, TOperator); TIntermTyped* handleLengthMethod(const TSourceLoc&, TFunction*, TIntermNode*); @@ -204,15 +318,18 @@ public: TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermAggregate&) const; void builtInOpCheck(const TSourceLoc&, const TFunction&, TIntermOperator&); void nonOpBuiltInCheck(const TSourceLoc&, const TFunction&, TIntermAggregate&); + void userFunctionCallCheck(const TSourceLoc&, TIntermAggregate&); + void samplerConstructorLocationCheck(const TSourceLoc&, const char* token, TIntermNode*); TFunction* handleConstructorCall(const TSourceLoc&, const TPublicType&); + void handlePrecisionQualifier(const TSourceLoc&, TQualifier&, TPrecisionQualifier); + void checkPrecisionQualifier(const TSourceLoc&, TPrecisionQualifier); - bool parseVectorFields(const TSourceLoc&, const TString&, int vecSize, TVectorFields&); void assignError(const TSourceLoc&, const char* op, TString left, TString right); void unaryOpError(const TSourceLoc&, const char* op, TString operand); void binaryOpError(const TSourceLoc&, const char* op, TString left, TString right); void variableCheck(TIntermTyped*& nodePtr); - bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*); - void rValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*); + bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*) override; + 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 globalCheck(const TSourceLoc&, const char* token); @@ -223,17 +340,15 @@ public: bool arrayError(const TSourceLoc&, const TType&); void arraySizeRequiredCheck(const TSourceLoc&, const TArraySizes&); void structArrayCheck(const TSourceLoc&, const TType& structure); - void arrayUnsizedCheck(const TSourceLoc&, const TQualifier&, const TArraySizes*, bool initializer, bool lastMember); - void arrayOfArrayVersionCheck(const TSourceLoc&); - void arrayDimCheck(const TSourceLoc&, const TArraySizes* sizes1, const TArraySizes* sizes2); - void arrayDimCheck(const TSourceLoc&, const TType*, const TArraySizes*); - void arrayDimMerge(TType& type, const TArraySizes* sizes); + void arraySizesCheck(const TSourceLoc&, const TQualifier&, TArraySizes*, const TIntermTyped* initializer, bool lastMember); + void arrayOfArrayVersionCheck(const TSourceLoc&, const TArraySizes*); bool voidErrorCheck(const TSourceLoc&, const TString&, TBasicType); void boolCheck(const TSourceLoc&, const TIntermTyped*); void boolCheck(const TSourceLoc&, const TPublicType&); void samplerCheck(const TSourceLoc&, const TType&, const TString& identifier, TIntermTyped* initializer); void atomicUintCheck(const TSourceLoc&, const TType&, const TString& identifier); - void transparentCheck(const TSourceLoc&, const TType&, const TString& identifier); + void transparentOpaqueCheck(const TSourceLoc&, const TType&, const TString& identifier); + void memberQualifierCheck(glslang::TPublicType&); void globalQualifierFixCheck(const TSourceLoc&, TQualifier&); void globalQualifierTypeCheck(const TSourceLoc&, const TQualifier&, const TPublicType&); bool structQualifierErrorCheck(const TSourceLoc&, const TPublicType& pType); @@ -244,9 +359,9 @@ public: void precisionQualifierCheck(const TSourceLoc&, TBasicType, TQualifier&); 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&, bool& newDeclaration); + TSymbol* redeclareBuiltinVariable(const TSourceLoc&, const TString&, const TQualifier&, const TShaderQualifiers&); void redeclareBuiltinBlock(const TSourceLoc&, TTypeList& typeList, const TString& blockName, const TString* instanceName, TArraySizes* arraySizes); - void paramCheckFix(const TSourceLoc&, const TStorageQualifier&, TType& type); + void paramCheckFixStorage(const TSourceLoc&, const TStorageQualifier&, TType& type); void paramCheckFix(const TSourceLoc&, const TQualifier&, TType& type); void nestedBlockCheck(const TSourceLoc&); void nestedStructCheck(const TSourceLoc&); @@ -265,6 +380,7 @@ public: void setLayoutQualifier(const TSourceLoc&, TPublicType&, TString&, const TIntermTyped*); void mergeObjectLayoutQualifiers(TQualifier& dest, const TQualifier& src, bool inheritOnly); void layoutObjectCheck(const TSourceLoc&, const TSymbol&); + void layoutMemberLocationArrayCheck(const TSourceLoc&, bool memberWithLocation, TArraySizes* arraySizes); void layoutTypeCheck(const TSourceLoc&, const TType&); void layoutQualifierCheck(const TSourceLoc&, const TQualifier&); void checkNoShaderLayouts(const TSourceLoc&, const TShaderQualifiers&); @@ -274,9 +390,10 @@ public: const TFunction* findFunctionExact(const TSourceLoc& loc, const TFunction& call, bool& builtIn); const TFunction* findFunction120(const TSourceLoc& loc, const TFunction& call, bool& builtIn); const TFunction* findFunction400(const TSourceLoc& loc, const TFunction& call, bool& builtIn); + const TFunction* findFunctionExplicitTypes(const TSourceLoc& loc, const TFunction& call, bool& builtIn); void declareTypeDefaults(const TSourceLoc&, const TPublicType&); TIntermNode* declareVariable(const TSourceLoc&, TString& identifier, const TPublicType&, TArraySizes* typeArray = 0, TIntermTyped* initializer = 0); - TIntermTyped* addConstructor(const TSourceLoc&, TIntermNode*, const TType&, TOperator); + 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 declareBlock(const TSourceLoc&, TTypeList& typeList, const TString* instanceName = 0, TArraySizes* arraySizes = 0); @@ -292,21 +409,29 @@ public: void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode); TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body); - void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index); + TAttributeType attributeFromName(const TString& name) const; + TAttributes* makeAttributes(const TString& identifier) const; + TAttributes* makeAttributes(const TString& identifier, TIntermNode* node) const; + TAttributes* mergeAttributes(TAttributes*, TAttributes*) const; + + // Determine selection control from attributes + void handleSelectionAttributes(const TAttributes& attributes, TIntermNode*); + void handleSwitchAttributes(const TAttributes& attributes, TIntermNode*); + + // Determine loop control from attributes + void handleLoopAttributes(const TAttributes& attributes, TIntermNode*); protected: void nonInitConstCheck(const TSourceLoc&, TString& identifier, TType& type); void inheritGlobalDefaults(TQualifier& dst) const; TVariable* makeInternalVariable(const char* name, const TType&) const; - TVariable* declareNonArray(const TSourceLoc&, TString& identifier, TType&, bool& newDeclaration); - void declareArray(const TSourceLoc&, TString& identifier, const TType&, TSymbol*&, bool& newDeclaration); + TVariable* declareNonArray(const TSourceLoc&, const TString& identifier, const TType&); + void declareArray(const TSourceLoc&, const TString& identifier, const TType&, TSymbol*&); + void checkRuntimeSizable(const TSourceLoc&, const TIntermTyped&); + bool isRuntimeLength(const TIntermTyped&) const; TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable); TIntermTyped* convertInitializerList(const TSourceLoc&, const TType&, TIntermTyped* initializer); - TOperator mapTypeToConstructorOp(const TType&) const; - void finalErrorCheck(); - void outputMessage(const TSourceLoc&, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, TPrefixType prefix, - va_list args); + void finish() override; public: // @@ -314,17 +439,7 @@ public: // // Current state of parsing - struct TPragma contextPragma; - int loopNestingLevel; // 0 if outside all loops - int structNestingLevel; // 0 if outside blocks and structures - int controlFlowNestingLevel; // 0 if outside all flow control - int statementNestingLevel; // 0 if outside all flow control or compound statements - TList switchSequenceStack; // case, node, case, case, node, ...; ensure only one node between cases; stack of them for nesting - TList switchLevel; // the statementNestingLevel the current switch statement is at, which must match the level of its case statements bool inMain; // if inside a function, true if the function is main - bool postMainReturn; // if inside a function, true if the function is main and this is after a return statement - const TType* currentFunctionType; // the return type of the function that's currently being parsed - bool functionReturnsValue; // true if a non-void function has a return const TString* blockName; TQualifier currentBlockQualifier; TPrecisionQualifier defaultPrecision[EbtNumTypes]; @@ -335,10 +450,9 @@ protected: TParseContext(TParseContext&); TParseContext& operator=(TParseContext&); - const bool parsingBuiltins; // true if parsing built-in symbols/functions static const int maxSamplerIndex = EsdNumDims * (EbtNumTypes * (2 * 2 * 2 * 2 * 2)); // see computeSamplerTypeIndex() TPrecisionQualifier defaultSamplerPrecision[maxSamplerIndex]; - bool afterEOF; + TPrecisionManager precisionManager; TQualifier globalBufferDefaults; TQualifier globalUniformDefaults; TQualifier globalInputDefaults; @@ -375,7 +489,7 @@ protected: // * note, that appropriately gives an error if redeclaring a block that // was already used and hence already copied-up // - // - on seeing a layout declaration that sizes the array, fix everything in the + // - on seeing a layout declaration that sizes the array, fix everything in the // resize-list, giving errors for mismatch // // - on seeing an array size declaration, give errors on mismatch between it and previous diff --git a/Externals/glslang/glslang/MachineIndependent/PoolAlloc.cpp b/Externals/glslang/glslang/MachineIndependent/PoolAlloc.cpp index d56979b492..84c40f4e79 100644 --- a/Externals/glslang/glslang/MachineIndependent/PoolAlloc.cpp +++ b/Externals/glslang/glslang/MachineIndependent/PoolAlloc.cpp @@ -1,10 +1,10 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -18,18 +18,18 @@ // 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. +// 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. // #include "../Include/Common.h" @@ -40,35 +40,22 @@ namespace glslang { +// Process-wide TLS index OS_TLSIndex PoolIndex; -void InitializeMemoryPools() +// Return the thread-specific current pool. +TPoolAllocator& GetThreadPoolAllocator() { - TThreadMemoryPools* pools = static_cast(OS_GetTLSValue(PoolIndex)); - if (pools) - return; - - TPoolAllocator *threadPoolAllocator = new TPoolAllocator(); - - TThreadMemoryPools* threadData = new TThreadMemoryPools(); - - threadData->threadPoolAllocator = threadPoolAllocator; - - OS_SetTLSValue(PoolIndex, threadData); + return *static_cast(OS_GetTLSValue(PoolIndex)); } -void FreeGlobalPools() +// Set the thread-specific current pool. +void SetThreadPoolAllocator(TPoolAllocator* poolAllocator) { - // Release the allocated memory for this thread. - TThreadMemoryPools* globalPools = static_cast(OS_GetTLSValue(PoolIndex)); - if (! globalPools) - return; - - GetThreadPoolAllocator().popAll(); - delete &GetThreadPoolAllocator(); - delete globalPools; + OS_SetTLSValue(PoolIndex, poolAllocator); } +// Process-wide set up of the TLS pool storage. bool InitializePoolIndex() { // Allocate a TLS index. @@ -78,35 +65,15 @@ bool InitializePoolIndex() return true; } -void FreePoolIndex() -{ - // Release the TLS index. - OS_FreeTLSIndex(PoolIndex); -} - -TPoolAllocator& GetThreadPoolAllocator() -{ - TThreadMemoryPools* threadData = static_cast(OS_GetTLSValue(PoolIndex)); - - return *threadData->threadPoolAllocator; -} - -void SetThreadPoolAllocator(TPoolAllocator& poolAllocator) -{ - TThreadMemoryPools* threadData = static_cast(OS_GetTLSValue(PoolIndex)); - - threadData->threadPoolAllocator = &poolAllocator; -} - // // Implement the functionality of the TPoolAllocator class, which // is documented in PoolAlloc.h. // -TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) : +TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) : pageSize(growthIncrement), alignment(allocationAlignment), - freeList(0), - inUseList(0), + freeList(nullptr), + inUseList(nullptr), numCalls(0) { // @@ -149,12 +116,12 @@ TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) : TPoolAllocator::~TPoolAllocator() { - while (inUseList) { - tHeader* next = inUseList->nextPage; + while (inUseList) { + tHeader* next = inUseList->nextPage; inUseList->~tHeader(); delete [] reinterpret_cast(inUseList); - inUseList = next; - } + inUseList = next; + } // // Always delete the free list memory - it can't be being @@ -206,13 +173,12 @@ void TAllocation::checkGuardBlock(unsigned char*, unsigned char, const char*) co #endif } - void TPoolAllocator::push() { tAllocState state = { currentPageOffset, inUseList }; stack.push_back(state); - + // // Indicate there is no current page to allocate from. // @@ -235,13 +201,16 @@ void TPoolAllocator::pop() currentPageOffset = stack.back().offset; while (inUseList != page) { - // invoke destructor to free allocation list - inUseList->~tHeader(); - tHeader* nextInUse = inUseList->nextPage; - if (inUseList->pageCount > 1) + size_t pageCount = inUseList->pageCount; + + // This technically ends the lifetime of the header as C++ object, + // but we will still control the memory and reuse it. + inUseList->~tHeader(); // currently, just a debug allocation checker + + if (pageCount > 1) { delete [] reinterpret_cast(inUseList); - else { + } else { inUseList->nextPage = freeList; freeList = inUseList; } @@ -269,7 +238,7 @@ void* TPoolAllocator::allocate(size_t numBytes) // size including guard blocks. In release build, // guardBlockSize=0 and this all gets optimized away. size_t allocationSize = TAllocation::allocationSize(numBytes); - + // // Just keep some interesting statistics. // @@ -327,14 +296,13 @@ void* TPoolAllocator::allocate(size_t numBytes) // Use placement-new to initialize header new(memory) tHeader(inUseList, 1); inUseList = memory; - + unsigned char* ret = reinterpret_cast(inUseList) + headerSkip; currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask; return initializeAllocation(inUseList, ret, numBytes); } - // // Check all allocations in a list for damage by calling check on each. // diff --git a/Externals/glslang/glslang/MachineIndependent/RemoveTree.cpp b/Externals/glslang/glslang/MachineIndependent/RemoveTree.cpp index a4fa551cad..1d33bfd203 100644 --- a/Externals/glslang/glslang/MachineIndependent/RemoveTree.cpp +++ b/Externals/glslang/glslang/MachineIndependent/RemoveTree.cpp @@ -1,12 +1,12 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2013 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2013 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,18 +20,18 @@ // 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. +// 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. // #include "../Include/intermediate.h" diff --git a/Externals/glslang/glslang/MachineIndependent/RemoveTree.h b/Externals/glslang/glslang/MachineIndependent/RemoveTree.h index 483b25dcb5..1ed015626b 100644 --- a/Externals/glslang/glslang/MachineIndependent/RemoveTree.h +++ b/Externals/glslang/glslang/MachineIndependent/RemoveTree.h @@ -1,10 +1,10 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -18,20 +18,22 @@ // 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. +// 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 + namespace glslang { void RemoveAllTreeNodes(TIntermNode*); diff --git a/Externals/glslang/glslang/MachineIndependent/Scan.cpp b/Externals/glslang/glslang/MachineIndependent/Scan.cpp index b8cb869f32..7232baeb29 100644 --- a/Externals/glslang/glslang/MachineIndependent/Scan.cpp +++ b/Externals/glslang/glslang/MachineIndependent/Scan.cpp @@ -1,12 +1,13 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2013 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2013 LunarG, Inc. +// Copyright (C) 2017 ARM Limited. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,31 +21,32 @@ // 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. +// 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. // // // GLSL scanning, leveraging the scanning done by the preprocessor. // -#include +#include #include #include #include "../Include/Types.h" #include "SymbolTable.h" #include "ParseHelper.h" +#include "attribute.h" #include "glslang_tab.cpp.h" #include "ScanContext.h" #include "Scan.h" @@ -55,7 +57,7 @@ // Required to avoid missing prototype warnings for some compilers int yylex(YYSTYPE*, glslang::TParseContext&); - + namespace glslang { // read past any white space @@ -142,13 +144,13 @@ void TInputScanner::consumeWhitespaceComment(bool& foundNonSpaceTab) { do { consumeWhiteSpace(foundNonSpaceTab); - + // if not starting a comment now, then done int c = peek(); if (c != '/' || c == EndOfInput) return; - // skip potential comment + // skip potential comment foundNonSpaceTab = true; if (! consumeComment()) return; @@ -175,7 +177,7 @@ bool TInputScanner::scanVersion(int& version, EProfile& profile, bool& notFirstT bool versionNotFirst = false; // means not first WRT comments and white space, nothing more notFirstToken = false; // means not first WRT to real tokens - version = 0; // means not found + version = 0; // means not found profile = ENoProfile; bool foundNonSpaceTab = false; @@ -199,10 +201,10 @@ bool TInputScanner::scanVersion(int& version, EProfile& profile, bool& notFirstT } lookingInMiddle = true; - // Nominal start, skipping the desktop allowed comments and white space, but tracking if + // Nominal start, skipping the desktop allowed comments and white space, but tracking if // something else was found for ES: consumeWhitespaceComment(foundNonSpaceTab); - if (foundNonSpaceTab) + if (foundNonSpaceTab) versionNotFirst = true; // "#" @@ -339,6 +341,7 @@ void TScanContext::fillInKeywordMap() (*KeywordMap)["const"] = CONST; (*KeywordMap)["uniform"] = UNIFORM; + (*KeywordMap)["nonuniformEXT"] = NONUNIFORM; (*KeywordMap)["in"] = IN; (*KeywordMap)["out"] = OUT; (*KeywordMap)["inout"] = INOUT; @@ -463,6 +466,84 @@ void TScanContext::fillInKeywordMap() (*KeywordMap)["u64vec3"] = U64VEC3; (*KeywordMap)["u64vec4"] = U64VEC4; + // GL_KHX_shader_explicit_arithmetic_types + (*KeywordMap)["int8_t"] = INT8_T; + (*KeywordMap)["i8vec2"] = I8VEC2; + (*KeywordMap)["i8vec3"] = I8VEC3; + (*KeywordMap)["i8vec4"] = I8VEC4; + (*KeywordMap)["uint8_t"] = UINT8_T; + (*KeywordMap)["u8vec2"] = U8VEC2; + (*KeywordMap)["u8vec3"] = U8VEC3; + (*KeywordMap)["u8vec4"] = U8VEC4; + + (*KeywordMap)["int16_t"] = INT16_T; + (*KeywordMap)["i16vec2"] = I16VEC2; + (*KeywordMap)["i16vec3"] = I16VEC3; + (*KeywordMap)["i16vec4"] = I16VEC4; + (*KeywordMap)["uint16_t"] = UINT16_T; + (*KeywordMap)["u16vec2"] = U16VEC2; + (*KeywordMap)["u16vec3"] = U16VEC3; + (*KeywordMap)["u16vec4"] = U16VEC4; + + (*KeywordMap)["int32_t"] = INT32_T; + (*KeywordMap)["i32vec2"] = I32VEC2; + (*KeywordMap)["i32vec3"] = I32VEC3; + (*KeywordMap)["i32vec4"] = I32VEC4; + (*KeywordMap)["uint32_t"] = UINT32_T; + (*KeywordMap)["u32vec2"] = U32VEC2; + (*KeywordMap)["u32vec3"] = U32VEC3; + (*KeywordMap)["u32vec4"] = U32VEC4; + + (*KeywordMap)["float16_t"] = FLOAT16_T; + (*KeywordMap)["f16vec2"] = F16VEC2; + (*KeywordMap)["f16vec3"] = F16VEC3; + (*KeywordMap)["f16vec4"] = F16VEC4; + (*KeywordMap)["f16mat2"] = F16MAT2; + (*KeywordMap)["f16mat3"] = F16MAT3; + (*KeywordMap)["f16mat4"] = F16MAT4; + (*KeywordMap)["f16mat2x2"] = F16MAT2X2; + (*KeywordMap)["f16mat2x3"] = F16MAT2X3; + (*KeywordMap)["f16mat2x4"] = F16MAT2X4; + (*KeywordMap)["f16mat3x2"] = F16MAT3X2; + (*KeywordMap)["f16mat3x3"] = F16MAT3X3; + (*KeywordMap)["f16mat3x4"] = F16MAT3X4; + (*KeywordMap)["f16mat4x2"] = F16MAT4X2; + (*KeywordMap)["f16mat4x3"] = F16MAT4X3; + (*KeywordMap)["f16mat4x4"] = F16MAT4X4; + + (*KeywordMap)["float32_t"] = FLOAT32_T; + (*KeywordMap)["f32vec2"] = F32VEC2; + (*KeywordMap)["f32vec3"] = F32VEC3; + (*KeywordMap)["f32vec4"] = F32VEC4; + (*KeywordMap)["f32mat2"] = F32MAT2; + (*KeywordMap)["f32mat3"] = F32MAT3; + (*KeywordMap)["f32mat4"] = F32MAT4; + (*KeywordMap)["f32mat2x2"] = F32MAT2X2; + (*KeywordMap)["f32mat2x3"] = F32MAT2X3; + (*KeywordMap)["f32mat2x4"] = F32MAT2X4; + (*KeywordMap)["f32mat3x2"] = F32MAT3X2; + (*KeywordMap)["f32mat3x3"] = F32MAT3X3; + (*KeywordMap)["f32mat3x4"] = F32MAT3X4; + (*KeywordMap)["f32mat4x2"] = F32MAT4X2; + (*KeywordMap)["f32mat4x3"] = F32MAT4X3; + (*KeywordMap)["f32mat4x4"] = F32MAT4X4; + (*KeywordMap)["float64_t"] = FLOAT64_T; + (*KeywordMap)["f64vec2"] = F64VEC2; + (*KeywordMap)["f64vec3"] = F64VEC3; + (*KeywordMap)["f64vec4"] = F64VEC4; + (*KeywordMap)["f64mat2"] = F64MAT2; + (*KeywordMap)["f64mat3"] = F64MAT3; + (*KeywordMap)["f64mat4"] = F64MAT4; + (*KeywordMap)["f64mat2x2"] = F64MAT2X2; + (*KeywordMap)["f64mat2x3"] = F64MAT2X3; + (*KeywordMap)["f64mat2x4"] = F64MAT2X4; + (*KeywordMap)["f64mat3x2"] = F64MAT3X2; + (*KeywordMap)["f64mat3x3"] = F64MAT3X3; + (*KeywordMap)["f64mat3x4"] = F64MAT3X4; + (*KeywordMap)["f64mat4x2"] = F64MAT4X2; + (*KeywordMap)["f64mat4x3"] = F64MAT4X3; + (*KeywordMap)["f64mat4x4"] = F64MAT4X4; + (*KeywordMap)["sampler2D"] = SAMPLER2D; (*KeywordMap)["samplerCube"] = SAMPLERCUBE; (*KeywordMap)["samplerCubeArray"] = SAMPLERCUBEARRAY; @@ -550,9 +631,60 @@ void TScanContext::fillInKeywordMap() (*KeywordMap)["usubpassInput"] = USUBPASSINPUT; (*KeywordMap)["usubpassInputMS"] = USUBPASSINPUTMS; +#ifdef AMD_EXTENSIONS + (*KeywordMap)["f16sampler1D"] = F16SAMPLER1D; + (*KeywordMap)["f16sampler2D"] = F16SAMPLER2D; + (*KeywordMap)["f16sampler3D"] = F16SAMPLER3D; + (*KeywordMap)["f16sampler2DRect"] = F16SAMPLER2DRECT; + (*KeywordMap)["f16samplerCube"] = F16SAMPLERCUBE; + (*KeywordMap)["f16sampler1DArray"] = F16SAMPLER1DARRAY; + (*KeywordMap)["f16sampler2DArray"] = F16SAMPLER2DARRAY; + (*KeywordMap)["f16samplerCubeArray"] = F16SAMPLERCUBEARRAY; + (*KeywordMap)["f16samplerBuffer"] = F16SAMPLERBUFFER; + (*KeywordMap)["f16sampler2DMS"] = F16SAMPLER2DMS; + (*KeywordMap)["f16sampler2DMSArray"] = F16SAMPLER2DMSARRAY; + (*KeywordMap)["f16sampler1DShadow"] = F16SAMPLER1DSHADOW; + (*KeywordMap)["f16sampler2DShadow"] = F16SAMPLER2DSHADOW; + (*KeywordMap)["f16sampler2DRectShadow"] = F16SAMPLER2DRECTSHADOW; + (*KeywordMap)["f16samplerCubeShadow"] = F16SAMPLERCUBESHADOW; + (*KeywordMap)["f16sampler1DArrayShadow"] = F16SAMPLER1DARRAYSHADOW; + (*KeywordMap)["f16sampler2DArrayShadow"] = F16SAMPLER2DARRAYSHADOW; + (*KeywordMap)["f16samplerCubeArrayShadow"] = F16SAMPLERCUBEARRAYSHADOW; + + (*KeywordMap)["f16image1D"] = F16IMAGE1D; + (*KeywordMap)["f16image2D"] = F16IMAGE2D; + (*KeywordMap)["f16image3D"] = F16IMAGE3D; + (*KeywordMap)["f16image2DRect"] = F16IMAGE2DRECT; + (*KeywordMap)["f16imageCube"] = F16IMAGECUBE; + (*KeywordMap)["f16image1DArray"] = F16IMAGE1DARRAY; + (*KeywordMap)["f16image2DArray"] = F16IMAGE2DARRAY; + (*KeywordMap)["f16imageCubeArray"] = F16IMAGECUBEARRAY; + (*KeywordMap)["f16imageBuffer"] = F16IMAGEBUFFER; + (*KeywordMap)["f16image2DMS"] = F16IMAGE2DMS; + (*KeywordMap)["f16image2DMSArray"] = F16IMAGE2DMSARRAY; + + (*KeywordMap)["f16texture1D"] = F16TEXTURE1D; + (*KeywordMap)["f16texture2D"] = F16TEXTURE2D; + (*KeywordMap)["f16texture3D"] = F16TEXTURE3D; + (*KeywordMap)["f16texture2DRect"] = F16TEXTURE2DRECT; + (*KeywordMap)["f16textureCube"] = F16TEXTURECUBE; + (*KeywordMap)["f16texture1DArray"] = F16TEXTURE1DARRAY; + (*KeywordMap)["f16texture2DArray"] = F16TEXTURE2DARRAY; + (*KeywordMap)["f16textureCubeArray"] = F16TEXTURECUBEARRAY; + (*KeywordMap)["f16textureBuffer"] = F16TEXTUREBUFFER; + (*KeywordMap)["f16texture2DMS"] = F16TEXTURE2DMS; + (*KeywordMap)["f16texture2DMSArray"] = F16TEXTURE2DMSARRAY; + + (*KeywordMap)["f16subpassInput"] = F16SUBPASSINPUT; + (*KeywordMap)["f16subpassInputMS"] = F16SUBPASSINPUTMS; +#endif + (*KeywordMap)["noperspective"] = NOPERSPECTIVE; (*KeywordMap)["smooth"] = SMOOTH; (*KeywordMap)["flat"] = FLAT; +#ifdef AMD_EXTENSIONS + (*KeywordMap)["__explicitInterpAMD"] = __EXPLICITINTERPAMD; +#endif (*KeywordMap)["centroid"] = CENTROID; (*KeywordMap)["precise"] = PRECISE; (*KeywordMap)["invariant"] = INVARIANT; @@ -561,7 +693,7 @@ void TScanContext::fillInKeywordMap() (*KeywordMap)["superp"] = SUPERP; ReservedSet = new std::unordered_set; - + ReservedSet->insert("common"); ReservedSet->insert("partition"); ReservedSet->insert("active"); @@ -609,18 +741,21 @@ void TScanContext::deleteKeywordMap() ReservedSet = nullptr; } +// Called by yylex to get the next token. +// Returning 0 implies end of input. int TScanContext::tokenize(TPpContext* pp, TParserToken& token) { do { parserToken = &token; TPpToken ppToken; - tokenText = pp->tokenize(&ppToken); - if (tokenText == nullptr) + int token = pp->tokenize(ppToken); + if (token == EndOfInput) return 0; + tokenText = ppToken.name; loc = ppToken.loc; parserToken->sType.lex.loc = loc; - switch (ppToken.token) { + switch (token) { case ';': afterType = false; return SEMICOLON; case ',': afterType = false; return COMMA; case ':': return COLON; @@ -649,11 +784,11 @@ int TScanContext::tokenize(TPpContext* pp, TParserToken& token) parseContext.error(loc, "illegal use of escape character", "\\", ""); break; - case PpAtomAdd: return ADD_ASSIGN; - case PpAtomSub: return SUB_ASSIGN; - case PpAtomMul: return MUL_ASSIGN; - case PpAtomDiv: return DIV_ASSIGN; - case PpAtomMod: return MOD_ASSIGN; + case PPAtomAddAssign: return ADD_ASSIGN; + case PPAtomSubAssign: return SUB_ASSIGN; + case PPAtomMulAssign: return MUL_ASSIGN; + case PPAtomDivAssign: return DIV_ASSIGN; + case PPAtomModAssign: return MOD_ASSIGN; case PpAtomRight: return RIGHT_OP; case PpAtomLeft: return LEFT_OP; @@ -675,13 +810,20 @@ int TScanContext::tokenize(TPpContext* pp, TParserToken& token) case PpAtomDecrement: return DEC_OP; case PpAtomIncrement: return INC_OP; - - case PpAtomConstInt: parserToken->sType.lex.i = ppToken.ival; return INTCONSTANT; - case PpAtomConstUint: parserToken->sType.lex.i = ppToken.ival; return UINTCONSTANT; - case PpAtomConstInt64: parserToken->sType.lex.i64 = ppToken.i64val; return INT64CONSTANT; - case PpAtomConstUint64: parserToken->sType.lex.i64 = ppToken.i64val; return UINT64CONSTANT; - case PpAtomConstFloat: parserToken->sType.lex.d = ppToken.dval; return FLOATCONSTANT; - case PpAtomConstDouble: parserToken->sType.lex.d = ppToken.dval; return DOUBLECONSTANT; + + case PpAtomColonColon: + parseContext.error(loc, "not supported", "::", ""); + break; + + case PpAtomConstInt: parserToken->sType.lex.i = ppToken.ival; return INTCONSTANT; + case PpAtomConstUint: parserToken->sType.lex.i = ppToken.ival; return UINTCONSTANT; + case PpAtomConstInt16: parserToken->sType.lex.i = ppToken.ival; return INT16CONSTANT; + case PpAtomConstUint16: parserToken->sType.lex.i = ppToken.ival; return UINT16CONSTANT; + case PpAtomConstInt64: parserToken->sType.lex.i64 = ppToken.i64val; return INT64CONSTANT; + case PpAtomConstUint64: parserToken->sType.lex.i64 = ppToken.i64val; return UINT64CONSTANT; + case PpAtomConstFloat: parserToken->sType.lex.d = ppToken.dval; return FLOATCONSTANT; + case PpAtomConstDouble: parserToken->sType.lex.d = ppToken.dval; return DOUBLECONSTANT; + case PpAtomConstFloat16: parserToken->sType.lex.d = ppToken.dval; return FLOAT16CONSTANT; case PpAtomIdentifier: { int token = tokenizeIdentifier(); @@ -693,7 +835,7 @@ int TScanContext::tokenize(TPpContext* pp, TParserToken& token) default: char buf[2]; - buf[0] = (char)ppToken.token; + buf[0] = (char)token; buf[1] = 0; parseContext.error(loc, "unexpected token", buf, ""); break; @@ -732,6 +874,12 @@ int TScanContext::tokenizeIdentifier() case CASE: return keyword; + case NONUNIFORM: + if (parseContext.extensionTurnedOn(E_GL_EXT_nonuniform_qualifier)) + return keyword; + else + return identifierOrType(); + case SWITCH: case DEFAULT: if ((parseContext.profile == EEsProfile && parseContext.version < 300) || @@ -774,7 +922,7 @@ int TScanContext::tokenizeIdentifier() return keyword; case BUFFER: - if ((parseContext.profile == EEsProfile && parseContext.version < 310) || + if ((parseContext.profile == EEsProfile && parseContext.version < 310) || (parseContext.profile != EEsProfile && parseContext.version < 430)) return identifierOrType(); return keyword; @@ -796,7 +944,8 @@ int TScanContext::tokenizeIdentifier() case VOLATILE: if (parseContext.profile == EEsProfile && parseContext.version >= 310) return keyword; - if (! parseContext.symbolTable.atBuiltInLevel() && (parseContext.profile == EEsProfile || (parseContext.version < 420 && ! parseContext.extensionTurnedOn(E_GL_ARB_shader_image_load_store)))) + if (! parseContext.symbolTable.atBuiltInLevel() && (parseContext.profile == EEsProfile || + (parseContext.version < 420 && ! parseContext.extensionTurnedOn(E_GL_ARB_shader_image_load_store)))) reservedWord(); return keyword; @@ -819,14 +968,17 @@ int TScanContext::tokenizeIdentifier() case PATCH: if (parseContext.symbolTable.atBuiltInLevel() || - (parseContext.profile == EEsProfile && parseContext.extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader)) || + (parseContext.profile == EEsProfile && + (parseContext.version >= 320 || + parseContext.extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader))) || (parseContext.profile != EEsProfile && parseContext.extensionTurnedOn(E_GL_ARB_tessellation_shader))) return keyword; return es30ReservedFromGLSL(400); case SAMPLE: - if (parseContext.extensionsTurnedOn(1, &E_GL_OES_shader_multisample_interpolation)) + if ((parseContext.profile == EEsProfile && parseContext.version >= 320) || + parseContext.extensionsTurnedOn(1, &E_GL_OES_shader_multisample_interpolation)) return keyword; return es30ReservedFromGLSL(400); @@ -847,7 +999,7 @@ int TScanContext::tokenizeIdentifier() case MAT3X4: case MAT4X2: case MAT4X3: - case MAT4X4: + case MAT4X4: return matNxM(); case DMAT2: @@ -880,7 +1032,8 @@ int TScanContext::tokenizeIdentifier() case IIMAGEBUFFER: case UIMAGEBUFFER: afterType = true; - if (parseContext.extensionsTurnedOn(Num_AEP_texture_buffer, AEP_texture_buffer)) + if ((parseContext.profile == EEsProfile && parseContext.version >= 320) || + parseContext.extensionsTurnedOn(Num_AEP_texture_buffer, AEP_texture_buffer)) return keyword; return firstGenerationImage(false); @@ -903,7 +1056,8 @@ int TScanContext::tokenizeIdentifier() case IIMAGECUBEARRAY: case UIMAGECUBEARRAY: afterType = true; - if (parseContext.extensionsTurnedOn(Num_AEP_texture_cube_map_array, AEP_texture_cube_map_array)) + if ((parseContext.profile == EEsProfile && parseContext.version >= 320) || + parseContext.extensionsTurnedOn(Num_AEP_texture_cube_map_array, AEP_texture_cube_map_array)) return keyword; return secondGenerationImage(); @@ -933,16 +1087,149 @@ int TScanContext::tokenizeIdentifier() case U64VEC2: case U64VEC3: case U64VEC4: - if (parseContext.profile != EEsProfile && parseContext.version >= 450) + afterType = true; + if (parseContext.symbolTable.atBuiltInLevel() || + (parseContext.profile != EEsProfile && parseContext.version >= 450 && + (parseContext.extensionTurnedOn(E_GL_ARB_gpu_shader_int64) || + parseContext.extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types) || + parseContext.extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types_int64)))) return keyword; return identifierOrType(); + case INT8_T: + case UINT8_T: + case I8VEC2: + case I8VEC3: + case I8VEC4: + case U8VEC2: + case U8VEC3: + case U8VEC4: + afterType = true; + if (parseContext.symbolTable.atBuiltInLevel() || + ((parseContext.extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types) || + parseContext.extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types_int8)) && + parseContext.profile != EEsProfile && parseContext.version >= 450)) + return keyword; + return identifierOrType(); + + case INT16_T: + case UINT16_T: + case I16VEC2: + case I16VEC3: + case I16VEC4: + case U16VEC2: + case U16VEC3: + case U16VEC4: + afterType = true; + if (parseContext.symbolTable.atBuiltInLevel() || + (parseContext.profile != EEsProfile && parseContext.version >= 450 && + ( +#ifdef AMD_EXTENSIONS + parseContext.extensionTurnedOn(E_GL_AMD_gpu_shader_int16) || +#endif + parseContext.extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types) || + parseContext.extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types_int16)))) + return keyword; + return identifierOrType(); + case INT32_T: + case UINT32_T: + case I32VEC2: + case I32VEC3: + case I32VEC4: + case U32VEC2: + case U32VEC3: + case U32VEC4: + afterType = true; + if (parseContext.symbolTable.atBuiltInLevel() || + ((parseContext.extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types) || + parseContext.extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types_int32)) && + parseContext.profile != EEsProfile && parseContext.version >= 450)) + return keyword; + return identifierOrType(); + case FLOAT32_T: + case F32VEC2: + case F32VEC3: + case F32VEC4: + case F32MAT2: + case F32MAT3: + case F32MAT4: + case F32MAT2X2: + case F32MAT2X3: + case F32MAT2X4: + case F32MAT3X2: + case F32MAT3X3: + case F32MAT3X4: + case F32MAT4X2: + case F32MAT4X3: + case F32MAT4X4: + afterType = true; + if (parseContext.symbolTable.atBuiltInLevel() || + ((parseContext.extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types) || + parseContext.extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types_float32)) && + parseContext.profile != EEsProfile && parseContext.version >= 450)) + return keyword; + return identifierOrType(); + + case FLOAT64_T: + case F64VEC2: + case F64VEC3: + case F64VEC4: + case F64MAT2: + case F64MAT3: + case F64MAT4: + case F64MAT2X2: + case F64MAT2X3: + case F64MAT2X4: + case F64MAT3X2: + case F64MAT3X3: + case F64MAT3X4: + case F64MAT4X2: + case F64MAT4X3: + case F64MAT4X4: + afterType = true; + if (parseContext.symbolTable.atBuiltInLevel() || + ((parseContext.extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types) || + parseContext.extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types_float64)) && + parseContext.profile != EEsProfile && parseContext.version >= 450)) + return keyword; + return identifierOrType(); + + case FLOAT16_T: + case F16VEC2: + case F16VEC3: + case F16VEC4: + case F16MAT2: + case F16MAT3: + case F16MAT4: + case F16MAT2X2: + case F16MAT2X3: + case F16MAT2X4: + case F16MAT3X2: + case F16MAT3X3: + case F16MAT3X4: + case F16MAT4X2: + case F16MAT4X3: + case F16MAT4X4: + afterType = true; + if (parseContext.symbolTable.atBuiltInLevel() || + (parseContext.profile != EEsProfile && parseContext.version >= 450 && + ( +#ifdef AMD_EXTENSIONS + parseContext.extensionTurnedOn(E_GL_AMD_gpu_shader_half_float) || +#endif + parseContext.extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types) || + parseContext.extensionTurnedOn(E_GL_KHX_shader_explicit_arithmetic_types_float16)))) + return keyword; + + return identifierOrType(); + case SAMPLERCUBEARRAY: case SAMPLERCUBEARRAYSHADOW: case ISAMPLERCUBEARRAY: case USAMPLERCUBEARRAY: afterType = true; - if (parseContext.extensionsTurnedOn(Num_AEP_texture_cube_map_array, AEP_texture_cube_map_array)) + if ((parseContext.profile == EEsProfile && parseContext.version >= 320) || + parseContext.extensionsTurnedOn(Num_AEP_texture_cube_map_array, AEP_texture_cube_map_array)) return keyword; if (parseContext.profile == EEsProfile || (parseContext.version < 400 && ! parseContext.extensionTurnedOn(E_GL_ARB_texture_cube_map_array))) reservedWord(); @@ -973,7 +1260,7 @@ int TScanContext::tokenizeIdentifier() case USAMPLER2DARRAY: afterType = true; return nonreservedKeyword(300, 130); - + case ISAMPLER2DRECT: case USAMPLER2DRECT: afterType = true; @@ -981,17 +1268,19 @@ int TScanContext::tokenizeIdentifier() case SAMPLERBUFFER: afterType = true; - if (parseContext.extensionsTurnedOn(Num_AEP_texture_buffer, AEP_texture_buffer)) + if ((parseContext.profile == EEsProfile && parseContext.version >= 320) || + parseContext.extensionsTurnedOn(Num_AEP_texture_buffer, AEP_texture_buffer)) return keyword; return es30ReservedFromGLSL(130); case ISAMPLERBUFFER: case USAMPLERBUFFER: afterType = true; - if (parseContext.extensionsTurnedOn(Num_AEP_texture_buffer, AEP_texture_buffer)) + if ((parseContext.profile == EEsProfile && parseContext.version >= 320) || + parseContext.extensionsTurnedOn(Num_AEP_texture_buffer, AEP_texture_buffer)) return keyword; return es30ReservedFromGLSL(140); - + case SAMPLER2DMS: case ISAMPLER2DMS: case USAMPLER2DMS: @@ -1004,7 +1293,8 @@ int TScanContext::tokenizeIdentifier() case ISAMPLER2DMSARRAY: case USAMPLER2DMSARRAY: afterType = true; - if (parseContext.extensionsTurnedOn(1, &E_GL_OES_texture_storage_multisample_2d_array)) + if ((parseContext.profile == EEsProfile && parseContext.version >= 320) || + parseContext.extensionsTurnedOn(1, &E_GL_OES_texture_storage_multisample_2d_array)) return keyword; return es30ReservedFromGLSL(150); @@ -1018,15 +1308,17 @@ int TScanContext::tokenizeIdentifier() case SAMPLER3D: afterType = true; if (parseContext.profile == EEsProfile && parseContext.version < 300) { - if (! parseContext.extensionTurnedOn(E_GL_OES_texture_3D)) + if (!parseContext.extensionTurnedOn(E_GL_OES_texture_3D)) reservedWord(); } return keyword; case SAMPLER2DSHADOW: afterType = true; - if (parseContext.profile == EEsProfile && parseContext.version < 300) - reservedWord(); + if (parseContext.profile == EEsProfile && parseContext.version < 300) { + if (!parseContext.extensionTurnedOn(E_GL_EXT_shadow_samplers)) + reservedWord(); + } return keyword; case SAMPLER2DRECT: @@ -1053,7 +1345,9 @@ int TScanContext::tokenizeIdentifier() case SAMPLEREXTERNALOES: afterType = true; - if (parseContext.symbolTable.atBuiltInLevel() || parseContext.extensionTurnedOn(E_GL_OES_EGL_image_external)) + if (parseContext.symbolTable.atBuiltInLevel() || + parseContext.extensionTurnedOn(E_GL_OES_EGL_image_external) || + parseContext.extensionTurnedOn(E_GL_OES_EGL_image_external_essl3)) return keyword; return identifierOrType(); @@ -1092,7 +1386,7 @@ int TScanContext::tokenizeIdentifier() case TEXTURE1DARRAY: case SAMPLER: case SAMPLERSHADOW: - if (parseContext.spvVersion.vulkan >= 100) + if (parseContext.spvVersion.vulkan > 0) return keyword; else return identifierOrType(); @@ -1103,20 +1397,87 @@ int TScanContext::tokenizeIdentifier() case ISUBPASSINPUTMS: case USUBPASSINPUT: case USUBPASSINPUTMS: - if (parseContext.spvVersion.vulkan >= 100) + if (parseContext.spvVersion.vulkan > 0) return keyword; else return identifierOrType(); +#ifdef AMD_EXTENSIONS + case F16SAMPLER1D: + case F16SAMPLER2D: + case F16SAMPLER3D: + case F16SAMPLER2DRECT: + case F16SAMPLERCUBE: + case F16SAMPLER1DARRAY: + case F16SAMPLER2DARRAY: + case F16SAMPLERCUBEARRAY: + case F16SAMPLERBUFFER: + case F16SAMPLER2DMS: + case F16SAMPLER2DMSARRAY: + case F16SAMPLER1DSHADOW: + case F16SAMPLER2DSHADOW: + case F16SAMPLER1DARRAYSHADOW: + case F16SAMPLER2DARRAYSHADOW: + case F16SAMPLER2DRECTSHADOW: + case F16SAMPLERCUBESHADOW: + case F16SAMPLERCUBEARRAYSHADOW: + + case F16IMAGE1D: + case F16IMAGE2D: + case F16IMAGE3D: + case F16IMAGE2DRECT: + case F16IMAGECUBE: + case F16IMAGE1DARRAY: + case F16IMAGE2DARRAY: + case F16IMAGECUBEARRAY: + case F16IMAGEBUFFER: + case F16IMAGE2DMS: + case F16IMAGE2DMSARRAY: + + case F16TEXTURE1D: + case F16TEXTURE2D: + case F16TEXTURE3D: + case F16TEXTURE2DRECT: + case F16TEXTURECUBE: + case F16TEXTURE1DARRAY: + case F16TEXTURE2DARRAY: + case F16TEXTURECUBEARRAY: + case F16TEXTUREBUFFER: + case F16TEXTURE2DMS: + case F16TEXTURE2DMSARRAY: + + case F16SUBPASSINPUT: + case F16SUBPASSINPUTMS: + afterType = true; + if (parseContext.symbolTable.atBuiltInLevel() || + (parseContext.extensionTurnedOn(E_GL_AMD_gpu_shader_half_float_fetch) && + parseContext.profile != EEsProfile && parseContext.version >= 450)) + return keyword; + return identifierOrType(); +#endif + case NOPERSPECTIVE: +#ifdef NV_EXTENSIONS + if (parseContext.profile == EEsProfile && parseContext.version >= 300 && + parseContext.extensionTurnedOn(E_GL_NV_shader_noperspective_interpolation)) + return keyword; +#endif return es30ReservedFromGLSL(130); - + case SMOOTH: if ((parseContext.profile == EEsProfile && parseContext.version < 300) || (parseContext.profile != EEsProfile && parseContext.version < 130)) return identifierOrType(); return keyword; +#ifdef AMD_EXTENSIONS + case __EXPLICITINTERPAMD: + if (parseContext.profile != EEsProfile && parseContext.version >= 450 && + parseContext.extensionTurnedOn(E_GL_AMD_shader_explicit_vertex_parameter)) + return keyword; + return identifierOrType(); +#endif + case FLAT: if (parseContext.profile == EEsProfile && parseContext.version < 300) reservedWord(); @@ -1130,7 +1491,8 @@ int TScanContext::tokenizeIdentifier() return keyword; case PRECISE: - if ((parseContext.profile == EEsProfile && parseContext.extensionsTurnedOn(Num_AEP_gpu_shader5, AEP_gpu_shader5)) || + if ((parseContext.profile == EEsProfile && + (parseContext.version >= 320 || parseContext.extensionsTurnedOn(Num_AEP_gpu_shader5, AEP_gpu_shader5))) || (parseContext.profile != EEsProfile && parseContext.version >= 400)) return keyword; if (parseContext.profile == EEsProfile && parseContext.version == 310) { @@ -1161,7 +1523,7 @@ int TScanContext::tokenizeIdentifier() bool reserved = parseContext.profile == EEsProfile || parseContext.version >= 130; return identifierOrReserved(reserved); } - + default: parseContext.infoSink.info.message(EPrefixInternalError, "Unknown glslang keyword", loc); return 0; @@ -1292,8 +1654,9 @@ int TScanContext::dMat() int TScanContext::firstGenerationImage(bool inEs310) { - if (parseContext.symbolTable.atBuiltInLevel() || - (parseContext.profile != EEsProfile && (parseContext.version >= 420 || parseContext.extensionTurnedOn(E_GL_ARB_shader_image_load_store))) || + if (parseContext.symbolTable.atBuiltInLevel() || + (parseContext.profile != EEsProfile && (parseContext.version >= 420 || + parseContext.extensionTurnedOn(E_GL_ARB_shader_image_load_store))) || (inEs310 && parseContext.profile == EEsProfile && parseContext.version >= 310)) return keyword; @@ -1317,8 +1680,8 @@ int TScanContext::secondGenerationImage() return keyword; } - if (parseContext.symbolTable.atBuiltInLevel() || - (parseContext.profile != EEsProfile && + if (parseContext.symbolTable.atBuiltInLevel() || + (parseContext.profile != EEsProfile && (parseContext.version >= 420 || parseContext.extensionTurnedOn(E_GL_ARB_shader_image_load_store)))) return keyword; diff --git a/Externals/glslang/glslang/MachineIndependent/Scan.h b/Externals/glslang/glslang/MachineIndependent/Scan.h index 4282cd599e..2c26c2efd4 100644 --- a/Externals/glslang/glslang/MachineIndependent/Scan.h +++ b/Externals/glslang/glslang/MachineIndependent/Scan.h @@ -1,12 +1,12 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2013 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2013 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,18 +20,18 @@ // 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. +// 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 _GLSLANG_SCAN_INCLUDED_ #define _GLSLANG_SCAN_INCLUDED_ @@ -51,25 +51,24 @@ const int EndOfInput = -1; // class TInputScanner { public: - TInputScanner(int n, const char* const s[], size_t L[], const char* const* names = nullptr, int b = 0, int f = 0, bool single = false) : + TInputScanner(int n, const char* const s[], size_t L[], const char* const* names = nullptr, + int b = 0, int f = 0, bool single = false) : numSources(n), - sources(reinterpret_cast(s)), // up to this point, common usage is "char*", but now we need positive 8-bit characters - lengths(L), currentSource(0), currentChar(0), stringBias(b), finale(f), singleLogical(single), endOfFileReached(false) + // up to this point, common usage is "char*", but now we need positive 8-bit characters + sources(reinterpret_cast(s)), + lengths(L), currentSource(0), currentChar(0), stringBias(b), finale(f), singleLogical(single), + endOfFileReached(false) { loc = new TSourceLoc[numSources]; for (int i = 0; i < numSources; ++i) { - loc[i].init(); + loc[i].init(i - stringBias); } if (names != nullptr) { for (int i = 0; i < numSources; ++i) loc[i].name = names[i]; } - loc[currentSource].string = -stringBias; loc[currentSource].line = 1; - loc[currentSource].column = 0; - logicalSourceLoc.string = 0; - logicalSourceLoc.line = 1; - logicalSourceLoc.column = 0; + logicalSourceLoc.init(1); logicalSourceLoc.name = loc[0].name; } @@ -204,6 +203,8 @@ public: currentSource = numSources; } + bool atEndOfInput() const { return endOfFileReached; } + const TSourceLoc& getSourceLoc() const { if (singleLogical) { @@ -252,7 +253,7 @@ protected: size_t currentChar; // This is for reporting what string/line an error occurred on, and can be overridden by #line. - // It remembers the last state of each source string as it is left for the next one, so unget() + // It remembers the last state of each source string as it is left for the next one, so unget() // can restore that state. TSourceLoc* loc; // an array diff --git a/Externals/glslang/glslang/MachineIndependent/ScanContext.h b/Externals/glslang/glslang/MachineIndependent/ScanContext.h index f237bee9f2..608ae067e0 100644 --- a/Externals/glslang/glslang/MachineIndependent/ScanContext.h +++ b/Externals/glslang/glslang/MachineIndependent/ScanContext.h @@ -1,11 +1,11 @@ // -//Copyright (C) 2013 LunarG, Inc. +// Copyright (C) 2013 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,18 +19,18 @@ // 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. +// 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. // // @@ -38,6 +38,8 @@ // sits between the preprocessor scanner and parser. // +#pragma once + #include "ParseHelper.h" namespace glslang { diff --git a/Externals/glslang/glslang/MachineIndependent/ShaderLang.cpp b/Externals/glslang/glslang/MachineIndependent/ShaderLang.cpp index dccc1f0b78..4f39f3453e 100644 --- a/Externals/glslang/glslang/MachineIndependent/ShaderLang.cpp +++ b/Externals/glslang/glslang/MachineIndependent/ShaderLang.cpp @@ -1,13 +1,13 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2013-2016 LunarG, Inc. -//Copyright (C) 2015-2016 Google, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2013-2016 LunarG, Inc. +// Copyright (C) 2015-2017 Google, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -21,18 +21,18 @@ // 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. +// 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. // // @@ -41,17 +41,21 @@ // This is the platform independent interface between an OGL driver // and the shading language compiler/linker. // -#include +#include #include #include #include #include "SymbolTable.h" #include "ParseHelper.h" -#include "../../hlsl/hlslParseHelper.h" -#include "../../hlsl/hlslParseables.h" #include "Scan.h" #include "ScanContext.h" +#ifdef ENABLE_HLSL +#include "../../hlsl/hlslParseHelper.h" +#include "../../hlsl/hlslParseables.h" +#include "../../hlsl/hlslScanContext.h" +#endif + #include "../Include/ShHandle.h" #include "../../OGLCompilersDLL/InitializeDll.h" @@ -60,10 +64,15 @@ #define SH_EXPORTING #include "../Public/ShaderLang.h" #include "reflection.h" +#include "iomapper.h" #include "Initialize.h" namespace { // anonymous namespace for file-local functions and symbols +// Total number of successful initializers of glslang: a refcount +// Shared global; access should be protected by a global mutex/critical section. +int NumberOfClients = 0; + using namespace glslang; // Create a language specific version of parseables. @@ -71,7 +80,9 @@ TBuiltInParseables* CreateBuiltInParseables(TInfoSink& infoSink, EShSource sourc { switch (source) { case EShSourceGlsl: return new TBuiltIns(); // GLSL builtIns +#ifdef ENABLE_HLSL case EShSourceHlsl: return new TBuiltInParseablesHlsl(); // HLSL intrinsics +#endif default: infoSink.info.message(EPrefixInternalError, "Unable to determine source language"); @@ -79,9 +90,35 @@ TBuiltInParseables* CreateBuiltInParseables(TInfoSink& infoSink, EShSource sourc } } +// Create a language specific version of a parse context. +TParseContextBase* CreateParseContext(TSymbolTable& symbolTable, TIntermediate& intermediate, + int version, EProfile profile, EShSource source, + EShLanguage language, TInfoSink& infoSink, + SpvVersion spvVersion, bool forwardCompatible, EShMessages messages, + bool parsingBuiltIns, std::string sourceEntryPointName = "") +{ + switch (source) { + case EShSourceGlsl: { + if (sourceEntryPointName.size() == 0) + intermediate.setEntryPointName("main"); + TString entryPoint = sourceEntryPointName.c_str(); + return new TParseContext(symbolTable, intermediate, parsingBuiltIns, version, profile, spvVersion, + language, infoSink, forwardCompatible, messages, &entryPoint); + } +#ifdef ENABLE_HLSL + case EShSourceHlsl: + return new HlslParseContext(symbolTable, intermediate, parsingBuiltIns, version, profile, spvVersion, + language, infoSink, sourceEntryPointName.c_str(), forwardCompatible, messages); +#endif + default: + infoSink.info.message(EPrefixInternalError, "Unable to determine source language"); + return nullptr; + } +} + // Local mapping functions for making arrays of symbol tables.... -const int VersionCount = 15; // index range in MapVersionToIndex +const int VersionCount = 17; // index range in MapVersionToIndex int MapVersionToIndex(int version) { @@ -103,7 +140,10 @@ int MapVersionToIndex(int version) case 440: index = 12; break; case 310: index = 13; break; case 450: index = 14; break; - default: break; + case 500: index = 0; break; // HLSL + case 320: index = 15; break; + case 460: index = 16; break; + default: assert(0); break; } assert(index < VersionCount); @@ -146,6 +186,23 @@ int MapProfileToIndex(EProfile profile) return index; } +const int SourceCount = 2; + +int MapSourceToIndex(EShSource source) +{ + int index = 0; + + switch (source) { + case EShSourceGlsl: index = 0; break; + case EShSourceHlsl: index = 1; break; + default: break; + } + + assert(index < SourceCount); + + return index; +} + // only one of these needed for non-ES; ES needs 2 for different precision defaults of built-ins enum EPrecisionClass { EPcGeneral, @@ -153,34 +210,39 @@ enum EPrecisionClass { EPcCount }; -// A process-global symbol table per version per profile for built-ins common -// to multiple stages (languages), and a process-global symbol table per version +// A process-global symbol table per version per profile for built-ins common +// to multiple stages (languages), and a process-global symbol table per version // per profile per stage for built-ins unique to each stage. They will be sparsely // populated, so they will only be generated as needed. -// +// // Each has a different set of built-ins, and we want to preserve that from // compile to compile. // -TSymbolTable* CommonSymbolTable[VersionCount][SpvVersionCount][ProfileCount][EPcCount] = {}; -TSymbolTable* SharedSymbolTables[VersionCount][SpvVersionCount][ProfileCount][EShLangCount] = {}; +TSymbolTable* CommonSymbolTable[VersionCount][SpvVersionCount][ProfileCount][SourceCount][EPcCount] = {}; +TSymbolTable* SharedSymbolTables[VersionCount][SpvVersionCount][ProfileCount][SourceCount][EShLangCount] = {}; -TPoolAllocator* PerProcessGPA = 0; +TPoolAllocator* PerProcessGPA = nullptr; // // Parse and add to the given symbol table the content of the given shader string. // -bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TInfoSink& infoSink, - TSymbolTable& symbolTable) +bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, + EShSource source, TInfoSink& infoSink, TSymbolTable& symbolTable) { TIntermediate intermediate(language, version, profile); - - TParseContext parseContext(symbolTable, intermediate, true, version, profile, spvVersion, language, infoSink); - TShader::ForbidInclude includer; - TPpContext ppContext(parseContext, "", includer); - TScanContext scanContext(parseContext); - parseContext.setScanContext(&scanContext); - parseContext.setPpContext(&ppContext); - + + intermediate.setSource(source); + + std::unique_ptr parseContext(CreateParseContext(symbolTable, intermediate, version, profile, source, + language, infoSink, spvVersion, true, EShMsgDefault, + true)); + + TShader::ForbidIncluder includer; + TPpContext ppContext(*parseContext, "", includer); + TScanContext scanContext(*parseContext); + parseContext->setScanContext(&scanContext); + parseContext->setPpContext(&ppContext); + // // Push the symbol table to give it an initial scope. This // push should not have a corresponding pop, so that built-ins @@ -196,9 +258,9 @@ bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profil if (builtInLengths[0] == 0) return true; - + TInputScanner input(1, builtInShaders, builtInLengths); - if (! parseContext.parseShaderStrings(ppContext, input) != 0) { + if (! parseContext->parseShaderStrings(ppContext, input) != 0) { infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins"); printf("Unable to parse built-ins\n%s\n", infoSink.info.c_str()); printf("%s\n", builtInShaders[0]); @@ -218,10 +280,12 @@ 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, - EShLanguage language, TInfoSink& infoSink, TSymbolTable** commonTable, TSymbolTable** symbolTables) + 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, infoSink, *symbolTables[language]); + InitializeSymbolTable(builtInParseables.getStageString(language), version, profile, spvVersion, language, source, + infoSink, *symbolTables[language]); builtInParseables.identifyBuiltIns(version, profile, spvVersion, language, *symbolTables[language]); if (profile == EEsProfile && version >= 300) (*symbolTables[language]).setNoBuiltInRedeclarations(); @@ -237,35 +301,46 @@ bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable, TS { std::unique_ptr builtInParseables(CreateBuiltInParseables(infoSink, source)); + if (builtInParseables == nullptr) + return false; + builtInParseables->initialize(version, profile, spvVersion); // do the common tables - InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangVertex, infoSink, *commonTable[EPcGeneral]); + InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangVertex, source, + infoSink, *commonTable[EPcGeneral]); if (profile == EEsProfile) - InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangFragment, infoSink, *commonTable[EPcFragment]); + 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, infoSink, commonTable, symbolTables); - InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangFragment, infoSink, commonTable, symbolTables); + InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangVertex, source, + infoSink, commonTable, symbolTables); + 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, infoSink, commonTable, symbolTables); - InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTessEvaluation, infoSink, commonTable, symbolTables); + InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTessControl, source, + infoSink, commonTable, symbolTables); + 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, infoSink, commonTable, symbolTables); + 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, infoSink, commonTable, symbolTables); + InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangCompute, source, + infoSink, commonTable, symbolTables); return true; } @@ -274,20 +349,23 @@ bool AddContextSpecificSymbols(const TBuiltInResource* resources, TInfoSink& inf EProfile profile, const SpvVersion& spvVersion, EShLanguage language, EShSource source) { std::unique_ptr builtInParseables(CreateBuiltInParseables(infoSink, source)); - + + if (builtInParseables == nullptr) + return false; + builtInParseables->initialize(*resources, version, profile, spvVersion, language); - InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, language, infoSink, symbolTable); + InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, language, source, infoSink, symbolTable); builtInParseables->identifyBuiltIns(version, profile, spvVersion, language, symbolTable, *resources); return true; } // -// To do this on the fly, we want to leave the current state of our thread's +// To do this on the fly, we want to leave the current state of our thread's // pool allocator intact, so: // - Switch to a new pool for parsing the built-ins // - Do the parsing, which builds the symbol table, using the new pool -// - Switch to the process-global pool to save a copy the resulting symbol table +// - Switch to the process-global pool to save a copy of the resulting symbol table // - Free up the new pool used to parse the built-ins // - Switch back to the original thread's pool // @@ -305,7 +383,8 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp int versionIndex = MapVersionToIndex(version); int spvVersionIndex = MapSpvVersionToIndex(spvVersion); int profileIndex = MapProfileToIndex(profile); - if (CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][EPcGeneral]) { + int sourceIndex = MapSourceToIndex(source); + if (CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][EPcGeneral]) { glslang::ReleaseGlobalLock(); return; @@ -313,8 +392,8 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp // Switch to a new pool TPoolAllocator& previousAllocator = GetThreadPoolAllocator(); - TPoolAllocator* builtInPoolAllocator = new TPoolAllocator(); - SetThreadPoolAllocator(*builtInPoolAllocator); + TPoolAllocator* builtInPoolAllocator = new TPoolAllocator; + SetThreadPoolAllocator(builtInPoolAllocator); // Dynamically allocate the local symbol tables so we can control when they are deallocated WRT when the pool is popped. TSymbolTable* commonTable[EPcCount]; @@ -328,24 +407,24 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp InitializeSymbolTables(infoSink, commonTable, stageTables, version, profile, spvVersion, source); // Switch to the process-global pool - SetThreadPoolAllocator(*PerProcessGPA); + SetThreadPoolAllocator(PerProcessGPA); // Copy the local symbol tables from the new pool to the global tables using the process-global pool for (int precClass = 0; precClass < EPcCount; ++precClass) { if (! commonTable[precClass]->isEmpty()) { - CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][precClass] = new TSymbolTable; - CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][precClass]->copyTable(*commonTable[precClass]); - CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][precClass]->readOnly(); + CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][precClass] = new TSymbolTable; + CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][precClass]->copyTable(*commonTable[precClass]); + CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][precClass]->readOnly(); } } for (int stage = 0; stage < EShLangCount; ++stage) { if (! stageTables[stage]->isEmpty()) { - SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][stage] = new TSymbolTable; - SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][stage]->adoptLevels(*CommonSymbolTable - [versionIndex][spvVersionIndex][profileIndex][CommonIndex(profile, (EShLanguage)stage)]); - SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][stage]->copyTable(*stageTables[stage]); - SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][stage]->readOnly(); - } + SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage] = new TSymbolTable; + SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->adoptLevels(*CommonSymbolTable + [versionIndex][spvVersionIndex][profileIndex][sourceIndex][CommonIndex(profile, (EShLanguage)stage)]); + SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->copyTable(*stageTables[stage]); + SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->readOnly(); + } } // Clean up the local tables before deleting the pool they used. @@ -355,7 +434,7 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp delete stageTables[stage]; delete builtInPoolAllocator; - SetThreadPoolAllocator(previousAllocator); + SetThreadPoolAllocator(&previousAllocator); glslang::ReleaseGlobalLock(); } @@ -368,12 +447,12 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo bool correct = true; if (source == EShSourceHlsl) { - version = 450; // TODO: GLSL parser is still used for builtins. + version = 500; // shader model; currently a characteristic of glslang, not the input profile = ECoreProfile; // allow doubles in prototype parsing return correct; } - // Get a good version... + // Get a version... if (version == 0) { version = defaultVersion; // infoSink.info.message(EPrefixWarning, "#version: statement missing; use #version on first line of shader"); @@ -381,9 +460,9 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo // Get a good profile... if (profile == ENoProfile) { - if (version == 300 || version == 310) { + if (version == 300 || version == 310 || version == 320) { correct = false; - infoSink.info.message(EPrefixError, "#version: versions 300 and 310 require specifying the 'es' profile"); + infoSink.info.message(EPrefixError, "#version: versions 300, 310, and 320 require specifying the 'es' profile"); profile = EEsProfile; } else if (version == 100) profile = EEsProfile; @@ -400,25 +479,61 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo profile = EEsProfile; else profile = ENoProfile; - } else if (version == 300 || version == 310) { + } else if (version == 300 || version == 310 || version == 320) { if (profile != EEsProfile) { correct = false; - infoSink.info.message(EPrefixError, "#version: versions 300 and 310 support only the es profile"); + infoSink.info.message(EPrefixError, "#version: versions 300, 310, and 320 support only the es profile"); } profile = EEsProfile; } else { if (profile == EEsProfile) { correct = false; - infoSink.info.message(EPrefixError, "#version: only version 300 and 310 support the es profile"); + infoSink.info.message(EPrefixError, "#version: only version 300, 310, and 320 support the es profile"); if (version >= FirstProfileVersion) profile = ECoreProfile; else profile = ENoProfile; - } + } // else: typical desktop case... e.g., "#version 410 core" } } + // Fix version... + switch (version) { + // ES versions + case 100: break; + case 300: break; + case 310: break; + case 320: break; + + // desktop versions + case 110: break; + case 120: break; + case 130: break; + case 140: break; + case 150: break; + case 330: break; + case 400: break; + case 410: break; + case 420: break; + case 430: break; + case 440: break; + case 450: break; + case 460: break; + + // unknown version + default: + correct = false; + infoSink.info.message(EPrefixError, "version not supported"); + if (profile == EEsProfile) + version = 310; + else { + version = 450; + profile = ECoreProfile; + } + break; + } + // Correct for stage type... switch (stage) { case EShLangGeometry: @@ -463,7 +578,7 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo if (spvVersion.spv != 0) { switch (profile) { case EEsProfile: - if (spvVersion.vulkan >= 100 && version < 310) { + if (spvVersion.vulkan > 0 && version < 310) { correct = false; infoSink.info.message(EPrefixError, "#version: ES shaders for Vulkan SPIR-V require version 310 or higher"); version = 310; @@ -478,7 +593,7 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo infoSink.info.message(EPrefixError, "#version: compilation for SPIR-V does not support the compatibility profile"); break; default: - if (spvVersion.vulkan >= 100 && version < 140) { + if (spvVersion.vulkan > 0 && version < 140) { correct = false; infoSink.info.message(EPrefixError, "#version: Desktop shaders for Vulkan SPIR-V require version 140 or higher"); version = 140; @@ -492,44 +607,92 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo } } - // A meta check on the condition of the compiler itself... - switch (version) { - - // ES versions - case 100: - case 300: - // versions are complete - break; - - // Desktop versions - case 110: - case 120: - case 130: - case 140: - case 150: - case 330: - // versions are complete - break; - - case 310: - case 400: - case 410: - case 420: - case 430: - case 440: - case 450: - infoSink.info << "Warning, version " << version << " is not yet complete; most version-specific features are present, but some are missing.\n"; - break; - - default: - infoSink.info << "Warning, version " << version << " is unknown.\n"; - break; - - } - return correct; } +// There are multiple paths in for setting environment stuff. +// TEnvironment takes precedence, for what it sets, so sort all this out. +// Ideally, the internal code could be made to use TEnvironment, but for +// now, translate it to the historically used parameters. +void TranslateEnvironment(const TEnvironment* environment, EShMessages& messages, EShSource& source, + EShLanguage& stage, SpvVersion& spvVersion) +{ + // Set up environmental defaults, first ignoring 'environment'. + if (messages & EShMsgSpvRules) + spvVersion.spv = EShTargetSpv_1_0; + if (messages & EShMsgVulkanRules) { + spvVersion.vulkan = EShTargetVulkan_1_0; + spvVersion.vulkanGlsl = 100; + } else if (spvVersion.spv != 0) + spvVersion.openGl = 100; + + // Now, override, based on any content set in 'environment'. + // 'environment' must be cleared to ESh*None settings when items + // are not being set. + if (environment != nullptr) { + // input language + if (environment->input.languageFamily != EShSourceNone) { + stage = environment->input.stage; + switch (environment->input.dialect) { + case EShClientNone: + break; + case EShClientVulkan: + spvVersion.vulkanGlsl = environment->input.dialectVersion; + break; + case EShClientOpenGL: + spvVersion.openGl = environment->input.dialectVersion; + break; + } + switch (environment->input.languageFamily) { + case EShSourceNone: + break; + case EShSourceGlsl: + source = EShSourceGlsl; + messages = static_cast(messages & ~EShMsgReadHlsl); + break; + case EShSourceHlsl: + source = EShSourceHlsl; + messages = static_cast(messages | EShMsgReadHlsl); + break; + } + } + + // client + switch (environment->client.client) { + case EShClientVulkan: + spvVersion.vulkan = environment->client.version; + break; + default: + break; + } + + // generated code + switch (environment->target.language) { + case EshTargetSpv: + spvVersion.spv = environment->target.version; + break; + default: + break; + } + } +} + +// Most processes are recorded when set in the intermediate representation, +// These are the few that are not. +void RecordProcesses(TIntermediate& intermediate, EShMessages messages, const std::string& sourceEntryPointName) +{ + if ((messages & EShMsgRelaxedErrors) != 0) + intermediate.addProcess("relaxed-errors"); + if ((messages & EShMsgSuppressWarnings) != 0) + intermediate.addProcess("suppress-warnings"); + if ((messages & EShMsgKeepUncalled) != 0) + intermediate.addProcess("keep-uncalled"); + if (sourceEntryPointName.size() > 0) { + intermediate.addProcess("source-entrypoint"); + intermediate.addProcessArgument(sourceEntryPointName); + } +} + // This is the common setup and cleanup code for PreprocessDeferred and // CompileDeferred. // It takes any callable with a signature of @@ -549,7 +712,7 @@ bool ProcessDeferred( const char* customPreamble, const EShOptimizationLevel optLevel, const TBuiltInResource* resources, - int defaultVersion, // use 100 for ES environment, 110 for desktop; this is the GLSL version, not SPIR-V or Vulkan + int defaultVersion, // use 100 for ES environment, 110 for desktop; this is the GLSL version, not SPIR-V or Vulkan EProfile defaultProfile, // set version/profile to defaultVersion/defaultProfile regardless of the #version // directive in the source code @@ -559,18 +722,16 @@ bool ProcessDeferred( TIntermediate& intermediate, // returned tree, etc. ProcessingContext& processingContext, bool requireNonempty, - TShader::Includer& includer - ) + TShader::Includer& includer, + const std::string sourceEntryPointName = "", + const TEnvironment* environment = nullptr) // optional way of fully setting all versions, overriding the above { - if (! InitThread()) - return false; - // This must be undone (.pop()) by the caller, after it finishes consuming the created tree. GetThreadPoolAllocator().push(); if (numStrings == 0) return true; - + // Move to length-based strings, rather than null-terminated strings. // Also, add strings to include the preamble and to ensure the shader is not null, // which lets the grammar accept what was a null (post preprocessing) shader. @@ -583,12 +744,12 @@ bool ProcessDeferred( const int numPre = 2; const int numPost = requireNonempty? 1 : 0; const int numTotal = numPre + numStrings + numPost; - size_t* lengths = new size_t[numTotal]; - const char** strings = new const char*[numTotal]; - const char** names = new const char*[numTotal]; + std::unique_ptr lengths(new size_t[numTotal]); + std::unique_ptr strings(new const char*[numTotal]); + std::unique_ptr names(new const char*[numTotal]); for (int s = 0; s < numStrings; ++s) { strings[s + numPre] = shaderStrings[s]; - if (inputLengths == 0 || inputLengths[s] < 0) + if (inputLengths == nullptr || inputLengths[s] < 0) lengths[s + numPre] = strlen(shaderStrings[s]); else lengths[s + numPre] = inputLengths[s]; @@ -601,16 +762,27 @@ bool ProcessDeferred( names[s + numPre] = nullptr; } + // Get all the stages, languages, clients, and other environment + // stuff sorted out. + EShSource source = (messages & EShMsgReadHlsl) != 0 ? EShSourceHlsl : EShSourceGlsl; + SpvVersion spvVersion; + EShLanguage stage = compiler->getLanguage(); + TranslateEnvironment(environment, messages, source, stage, spvVersion); + if (environment != nullptr && environment->target.hlslFunctionality1) + intermediate.setHlslFunctionality1(); + // First, without using the preprocessor or parser, find the #version, so we know what // symbol tables, processing rules, etc. to set up. This does not need the extra strings - // outlined above, just the user shader. - int version; - EProfile profile; - glslang::TInputScanner userInput(numStrings, &strings[numPre], &lengths[numPre]); // no preamble - bool versionNotFirstToken; - bool versionNotFirst = userInput.scanVersion(version, profile, versionNotFirstToken); + // outlined above, just the user shader, after the system and user preambles. + glslang::TInputScanner userInput(numStrings, &strings[numPre], &lengths[numPre]); + int version = 0; + EProfile profile = ENoProfile; + bool versionNotFirstToken = false; + bool versionNotFirst = (source == EShSourceHlsl) + ? true + : userInput.scanVersion(version, profile, versionNotFirstToken); bool versionNotFound = version == 0; - if (forceDefaultVersionAndProfile) { + if (forceDefaultVersionAndProfile && source == EShSourceGlsl) { if (! (messages & EShMsgSuppressWarnings) && ! versionNotFound && (version != defaultVersion || profile != defaultProfile)) { compiler->infoSink.info << "Warning, (version, profile) forced to be (" @@ -627,15 +799,9 @@ bool ProcessDeferred( version = defaultVersion; profile = defaultProfile; } - SpvVersion spvVersion; - if (messages & EShMsgSpvRules) - spvVersion.spv = 0x00010000; // TODO: eventually have this come from the outside - EShSource source = (messages & EShMsgReadHlsl) ? EShSourceHlsl : EShSourceGlsl; - if (messages & EShMsgVulkanRules) - spvVersion.vulkan = 100; // TODO: eventually have this come from the outside - else if (spvVersion.spv != 0) - spvVersion.openGl = 100; // TODO: eventually have this come from the outside - bool goodVersion = DeduceVersionProfile(compiler->infoSink, compiler->getLanguage(), versionNotFirst, defaultVersion, source, version, profile, spvVersion); + + bool goodVersion = DeduceVersionProfile(compiler->infoSink, stage, + versionNotFirst, defaultVersion, source, version, profile, spvVersion); bool versionWillBeError = (versionNotFound || (profile == EEsProfile && version >= 300 && versionNotFirst)); bool warnVersionNotFirst = false; if (! versionWillBeError && versionNotFirstToken) { @@ -649,45 +815,48 @@ bool ProcessDeferred( intermediate.setVersion(version); intermediate.setProfile(profile); intermediate.setSpv(spvVersion); - if (spvVersion.vulkan >= 100) + RecordProcesses(intermediate, messages, sourceEntryPointName); + if (spvVersion.vulkan > 0) intermediate.setOriginUpperLeft(); + if ((messages & EShMsgHlslOffsets) || source == EShSourceHlsl) + intermediate.setHlslOffsets(); + if (messages & EShMsgDebugInfo) { + intermediate.setSourceFile(names[numPre]); + for (int s = 0; s < numStrings; ++s) + intermediate.addSourceText(strings[numPre + s]); + } SetupBuiltinSymbolTable(version, profile, spvVersion, source); - + TSymbolTable* cachedTable = SharedSymbolTables[MapVersionToIndex(version)] [MapSpvVersionToIndex(spvVersion)] [MapProfileToIndex(profile)] - [compiler->getLanguage()]; - + [MapSourceToIndex(source)] + [stage]; + // Dynamically allocate the symbol table so we can control when it is deallocated WRT the pool. - TSymbolTable* symbolTableMemory = new TSymbolTable; - TSymbolTable& symbolTable = *symbolTableMemory; + std::unique_ptr symbolTable(new TSymbolTable); if (cachedTable) - symbolTable.adoptLevels(*cachedTable); - + symbolTable->adoptLevels(*cachedTable); + // Add built-in symbols that are potentially context dependent; // they get popped again further down. - AddContextSpecificSymbols(resources, compiler->infoSink, symbolTable, version, profile, spvVersion, - compiler->getLanguage(), source); - + if (! AddContextSpecificSymbols(resources, compiler->infoSink, *symbolTable, version, profile, spvVersion, + stage, source)) { + return false; + } + // // Now we can process the full shader under proper symbols and rules. // - TParseContextBase* parseContext; - if (source == EShSourceHlsl) { - parseContext = new HlslParseContext(symbolTable, intermediate, false, version, profile, spvVersion, - compiler->getLanguage(), compiler->infoSink, forwardCompatible, messages); - } - else { - intermediate.setEntryPoint("main"); - parseContext = new TParseContext(symbolTable, intermediate, false, version, profile, spvVersion, - compiler->getLanguage(), compiler->infoSink, forwardCompatible, messages); - } - TPpContext ppContext(*parseContext, names[numPre]? names[numPre]: "", includer); + std::unique_ptr parseContext(CreateParseContext(*symbolTable, intermediate, version, profile, source, + stage, compiler->infoSink, + spvVersion, forwardCompatible, messages, false, sourceEntryPointName)); + TPpContext ppContext(*parseContext, names[numPre] ? names[numPre] : "", includer); // only GLSL (bison triggered, really) needs an externally set scan context glslang::TScanContext scanContext(*parseContext); - if ((messages & EShMsgReadHlsl) == 0) + if (source == EShSourceGlsl) parseContext->setScanContext(&scanContext); parseContext->setPpContext(&ppContext); @@ -701,7 +870,7 @@ bool ProcessDeferred( } parseContext->initializeExtensionBehavior(); - + // Fill in the strings as outlined above. std::string preamble; parseContext->getPreamble(preamble); @@ -718,23 +887,14 @@ bool ProcessDeferred( lengths[postIndex] = strlen(strings[numStrings + numPre]); names[postIndex] = nullptr; } - TInputScanner fullInput(numStrings + numPre + numPost, strings, lengths, names, numPre, numPost); + TInputScanner fullInput(numStrings + numPre + numPost, strings.get(), lengths.get(), names.get(), numPre, numPost); // Push a new symbol allocation scope that will get used for the shader's globals. - symbolTable.push(); + symbolTable->push(); bool success = processingContext(*parseContext, ppContext, fullInput, - versionWillBeError, symbolTable, + versionWillBeError, *symbolTable, intermediate, optLevel, messages); - - // Clean up the symbol table. The AST is self-sufficient now. - delete symbolTableMemory; - - delete parseContext; - delete [] lengths; - delete [] strings; - delete [] names; - return success; } @@ -744,7 +904,7 @@ bool ProcessDeferred( class SourceLineSynchronizer { public: SourceLineSynchronizer(const std::function& lastSourceIndex, - std::stringstream* output) + std::string* output) : getLastSourceIndex(lastSourceIndex), output(output), lastSource(-1), lastLine(0) {} // SourceLineSynchronizer(const SourceLineSynchronizer&) = delete; // SourceLineSynchronizer& operator=(const SourceLineSynchronizer&) = delete; @@ -759,7 +919,7 @@ public: // used. We also need to output a newline to separate the output // from the previous source string (if there is one). if (lastSource != -1 || lastLine != 0) - *output << std::endl; + *output += '\n'; lastSource = getLastSourceIndex(); lastLine = -1; return true; @@ -774,7 +934,7 @@ public: syncToMostRecentString(); const bool newLineStarted = lastLine < tokenLine; for (; lastLine < tokenLine; ++lastLine) { - if (lastLine > 0) *output << std::endl; + if (lastLine > 0) *output += '\n'; } return newLineStarted; } @@ -788,8 +948,8 @@ private: // A function for getting the index of the last valid source string we've // read tokens from. const std::function getLastSourceIndex; - // output stream for newlines. - std::stringstream* output; + // output string for newlines. + std::string* output; // lastSource is the source string index (starting from 0) of the last token // processed. It is tracked in order for newlines to be inserted when a new // source string starts. -1 means we haven't started processing any source @@ -815,32 +975,38 @@ struct DoPreprocessing { // This is a list of tokens that do not require a space before or after. static const std::string unNeededSpaceTokens = ";()[]"; static const std::string noSpaceBeforeTokens = ","; - glslang::TPpToken token; + glslang::TPpToken ppToken; parseContext.setScanner(&input); ppContext.setInput(input, versionWillBeError); - std::stringstream outputStream; + std::string outputBuffer; SourceLineSynchronizer lineSync( - std::bind(&TInputScanner::getLastValidSourceIndex, &input), &outputStream); + std::bind(&TInputScanner::getLastValidSourceIndex, &input), &outputBuffer); - parseContext.setExtensionCallback([&lineSync, &outputStream]( + parseContext.setExtensionCallback([&lineSync, &outputBuffer]( int line, const char* extension, const char* behavior) { lineSync.syncToLine(line); - outputStream << "#extension " << extension << " : " << behavior; + outputBuffer += "#extension "; + outputBuffer += extension; + outputBuffer += " : "; + outputBuffer += behavior; }); - parseContext.setLineCallback([&lineSync, &outputStream, &parseContext]( + parseContext.setLineCallback([&lineSync, &outputBuffer, &parseContext]( int curLineNum, int newLineNum, bool hasSource, int sourceNum, const char* sourceName) { // SourceNum is the number of the source-string that is being parsed. lineSync.syncToLine(curLineNum); - outputStream << "#line " << newLineNum; + outputBuffer += "#line "; + outputBuffer += std::to_string(newLineNum); if (hasSource) { - outputStream << " "; + outputBuffer += ' '; if (sourceName != nullptr) { - outputStream << "\"" << sourceName << "\""; + outputBuffer += '\"'; + outputBuffer += sourceName; + outputBuffer += '\"'; } else { - outputStream << sourceNum; + outputBuffer += std::to_string(sourceNum); } } if (parseContext.lineDirectiveShouldSetNextLine()) { @@ -848,61 +1014,68 @@ struct DoPreprocessing { // directive. So the new line number for the current line is newLineNum -= 1; } - outputStream << std::endl; + outputBuffer += '\n'; // And we are at the next line of the #line directive now. lineSync.setLineNum(newLineNum + 1); }); parseContext.setVersionCallback( - [&lineSync, &outputStream](int line, int version, const char* str) { + [&lineSync, &outputBuffer](int line, int version, const char* str) { lineSync.syncToLine(line); - outputStream << "#version " << version; + outputBuffer += "#version "; + outputBuffer += std::to_string(version); if (str) { - outputStream << " " << str; + outputBuffer += ' '; + outputBuffer += str; } }); - parseContext.setPragmaCallback([&lineSync, &outputStream]( + parseContext.setPragmaCallback([&lineSync, &outputBuffer]( int line, const glslang::TVector& ops) { lineSync.syncToLine(line); - outputStream << "#pragma "; + outputBuffer += "#pragma "; for(size_t i = 0; i < ops.size(); ++i) { - outputStream << ops[i]; + outputBuffer += ops[i].c_str(); } }); - parseContext.setErrorCallback([&lineSync, &outputStream]( + parseContext.setErrorCallback([&lineSync, &outputBuffer]( int line, const char* errorMessage) { lineSync.syncToLine(line); - outputStream << "#error " << errorMessage; + outputBuffer += "#error "; + outputBuffer += errorMessage; }); int lastToken = EndOfInput; // lastToken records the last token processed. - while (const char* tok = ppContext.tokenize(&token)) { + do { + int token = ppContext.tokenize(ppToken); + if (token == EndOfInput) + break; + bool isNewString = lineSync.syncToMostRecentString(); - bool isNewLine = lineSync.syncToLine(token.loc.line); + bool isNewLine = lineSync.syncToLine(ppToken.loc.line); if (isNewLine) { // Don't emit whitespace onto empty lines. // Copy any whitespace characters at the start of a line // from the input to the output. - outputStream << std::string(token.loc.column - 1, ' '); + outputBuffer += std::string(ppToken.loc.column - 1, ' '); } // Output a space in between tokens, but not at the start of a line, // and also not around special tokens. This helps with readability // and consistency. if (!isNewString && !isNewLine && lastToken != EndOfInput && - (unNeededSpaceTokens.find((char)token.token) == std::string::npos) && + (unNeededSpaceTokens.find((char)token) == std::string::npos) && (unNeededSpaceTokens.find((char)lastToken) == std::string::npos) && - (noSpaceBeforeTokens.find((char)token.token) == std::string::npos)) { - outputStream << " "; + (noSpaceBeforeTokens.find((char)token) == std::string::npos)) { + outputBuffer += ' '; } - lastToken = token.token; - outputStream << tok; - } - outputStream << std::endl; - *outputString = outputStream.str(); + lastToken = token; + outputBuffer += ppToken.name; + } while (true); + outputBuffer += '\n'; + *outputString = std::move(outputBuffer); bool success = true; if (parseContext.getNumErrors() > 0) { @@ -920,14 +1093,13 @@ struct DoPreprocessing { struct DoFullParse{ bool operator()(TParseContextBase& parseContext, TPpContext& ppContext, TInputScanner& fullInput, bool versionWillBeError, - TSymbolTable& symbolTable, TIntermediate& intermediate, - EShOptimizationLevel optLevel, EShMessages messages) + TSymbolTable&, TIntermediate& intermediate, + EShOptimizationLevel optLevel, EShMessages messages) { bool success = true; // Parse the full shader. if (! parseContext.parseShaderStrings(ppContext, fullInput, versionWillBeError)) success = false; - intermediate.addSymbolLinkageNodes(parseContext.getLinkage(), parseContext.getLanguage(), symbolTable); if (success && intermediate.getTreeRoot()) { if (optLevel == EShOptNoGeneration) @@ -976,7 +1148,6 @@ bool PreprocessDeferred( false, includer); } - // // do a partial compile on the given strings for a single compilation unit // for a potential deferred link into a single stage (and deferred full compile of that @@ -985,7 +1156,7 @@ bool PreprocessDeferred( // all preprocessing, parsing, semantic checks, etc. for a single compilation unit // are done here. // -// return: the tree and other information is filled into the intermediate argument, +// return: the tree and other information is filled into the intermediate argument, // and true is returned by the function for success. // bool CompileDeferred( @@ -1003,19 +1174,20 @@ bool CompileDeferred( bool forwardCompatible, // give errors for use of deprecated features EShMessages messages, // warnings/errors/AST; things to print out TIntermediate& intermediate,// returned tree, etc. - TShader::Includer& includer) + TShader::Includer& includer, + const std::string sourceEntryPointName = "", + TEnvironment* environment = nullptr) { DoFullParse parser; return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames, preamble, optLevel, resources, defaultVersion, defaultProfile, forceDefaultVersionAndProfile, forwardCompatible, messages, intermediate, parser, - true, includer); + true, includer, sourceEntryPointName, environment); } } // end anonymous namespace for local functions - // // ShInitialize() should be called exactly once per process, not per thread. // @@ -1026,10 +1198,17 @@ int ShInitialize() if (! InitProcess()) return 0; - if (! PerProcessGPA) + glslang::GetGlobalLock(); + ++NumberOfClients; + glslang::ReleaseGlobalLock(); + + if (PerProcessGPA == nullptr) PerProcessGPA = new TPoolAllocator(); glslang::TScanContext::fillInKeywordMap(); +#ifdef ENABLE_HLSL + glslang::HlslScanContext::fillInKeywordMap(); +#endif return 1; } @@ -1045,7 +1224,7 @@ ShHandle ShConstructCompiler(const EShLanguage language, int debugOptions) return 0; TShHandleBase* base = static_cast(ConstructCompiler(language, debugOptions)); - + return reinterpret_cast(base); } @@ -1089,12 +1268,22 @@ void ShDestruct(ShHandle handle) // int __fastcall ShFinalize() { + glslang::GetGlobalLock(); + --NumberOfClients; + assert(NumberOfClients >= 0); + bool finalize = NumberOfClients == 0; + glslang::ReleaseGlobalLock(); + if (! finalize) + return 1; + for (int version = 0; version < VersionCount; ++version) { for (int spvVersion = 0; spvVersion < SpvVersionCount; ++spvVersion) { for (int p = 0; p < ProfileCount; ++p) { - for (int lang = 0; lang < EShLangCount; ++lang) { - delete SharedSymbolTables[version][spvVersion][p][lang]; - SharedSymbolTables[version][spvVersion][p][lang] = 0; + for (int source = 0; source < SourceCount; ++source) { + for (int stage = 0; stage < EShLangCount; ++stage) { + delete SharedSymbolTables[version][spvVersion][p][source][stage]; + SharedSymbolTables[version][spvVersion][p][source][stage] = 0; + } } } } @@ -1103,21 +1292,25 @@ int __fastcall ShFinalize() for (int version = 0; version < VersionCount; ++version) { for (int spvVersion = 0; spvVersion < SpvVersionCount; ++spvVersion) { for (int p = 0; p < ProfileCount; ++p) { - for (int pc = 0; pc < EPcCount; ++pc) { - delete CommonSymbolTable[version][spvVersion][p][pc]; - CommonSymbolTable[version][spvVersion][p][pc] = 0; + for (int source = 0; source < SourceCount; ++source) { + for (int pc = 0; pc < EPcCount; ++pc) { + delete CommonSymbolTable[version][spvVersion][p][source][pc]; + CommonSymbolTable[version][spvVersion][p][source][pc] = 0; + } } } } } - if (PerProcessGPA) { - PerProcessGPA->popAll(); + if (PerProcessGPA != nullptr) { delete PerProcessGPA; - PerProcessGPA = 0; + PerProcessGPA = nullptr; } glslang::TScanContext::deleteKeywordMap(); +#ifdef ENABLE_HLSL + glslang::HlslScanContext::deleteKeywordMap(); +#endif return 1; } @@ -1152,11 +1345,13 @@ int ShCompile( if (compiler == 0) return 0; + SetThreadPoolAllocator(compiler->getPool()); + compiler->infoSink.info.erase(); compiler->infoSink.debug.erase(); TIntermediate intermediate(compiler->getLanguage()); - TShader::ForbidInclude includer; + TShader::ForbidIncluder includer; bool success = CompileDeferred(compiler, shaderStrings, numStrings, inputLengths, nullptr, "", optLevel, resources, defaultVersion, ENoProfile, false, forwardCompatible, messages, intermediate, includer); @@ -1201,8 +1396,7 @@ int ShLinkExt( } if (base->getAsCompiler()) cObjects.push_back(base->getAsCompiler()); - - + if (cObjects[i] == 0) return 0; } @@ -1210,6 +1404,8 @@ int ShLinkExt( TShHandleBase* base = reinterpret_cast(linkHandle); TLinker* linker = static_cast(base->getAsLinker()); + SetThreadPoolAllocator(linker->getPool()); + if (linker == 0) return 0; @@ -1218,7 +1414,7 @@ int ShLinkExt( for (int i = 0; i < numHandles; ++i) { if (cObjects[i]->getAsCompiler()) { if (! cObjects[i]->getAsCompiler()->linkable()) { - linker->infoSink.info.message(EPrefixError, "Not all shaders have valid object code."); + linker->infoSink.info.message(EPrefixError, "Not all shaders have valid object code."); return 0; } } @@ -1244,9 +1440,6 @@ void ShSetEncryptionMethod(ShHandle handle) // const char* ShGetInfoLog(const ShHandle handle) { - if (!InitThread()) - return 0; - if (handle == 0) return 0; @@ -1270,14 +1463,11 @@ const char* ShGetInfoLog(const ShHandle handle) // const void* ShGetExecutable(const ShHandle handle) { - if (!InitThread()) - return 0; - if (handle == 0) return 0; TShHandleBase* base = reinterpret_cast(handle); - + TLinker* linker = static_cast(base->getAsLinker()); if (linker == 0) return 0; @@ -1294,10 +1484,7 @@ const void* ShGetExecutable(const ShHandle handle) // success or failure. // int ShSetVirtualAttributeBindings(const ShHandle handle, const ShBindingTable* table) -{ - if (!InitThread()) - return 0; - +{ if (handle == 0) return 0; @@ -1306,7 +1493,7 @@ int ShSetVirtualAttributeBindings(const ShHandle handle, const ShBindingTable* t if (linker == 0) return 0; - + linker->setAppAttributeBindings(table); return 1; @@ -1317,9 +1504,6 @@ int ShSetVirtualAttributeBindings(const ShHandle handle, const ShBindingTable* t // int ShSetFixedAttributeBindings(const ShHandle handle, const ShBindingTable* table) { - if (!InitThread()) - return 0; - if (handle == 0) return 0; @@ -1338,9 +1522,6 @@ int ShSetFixedAttributeBindings(const ShHandle handle, const ShBindingTable* tab // int ShExcludeAttributes(const ShHandle handle, int *attributes, int count) { - if (!InitThread()) - return 0; - if (handle == 0) return 0; @@ -1362,9 +1543,6 @@ int ShExcludeAttributes(const ShHandle handle, int *attributes, int count) // int ShGetUniformLocation(const ShHandle handle, const char* name) { - if (!InitThread()) - return 0; - if (handle == 0) return -1; @@ -1383,7 +1561,7 @@ int ShGetUniformLocation(const ShHandle handle, const char* name) // // Below is a new alternate C++ interface that might potentially replace the above // opaque handle-based interface. -// +// // See more detailed comment in ShaderLang.h // @@ -1391,14 +1569,17 @@ namespace glslang { #include "../Include/revision.h" +#define QUOTE(s) #s +#define STR(n) QUOTE(n) + const char* GetEsslVersionString() { - return "OpenGL ES GLSL 3.00 glslang LunarG Khronos." GLSLANG_REVISION " " GLSLANG_DATE; + return "OpenGL ES GLSL 3.20 glslang Khronos. " STR(GLSLANG_MINOR_VERSION) "." STR(GLSLANG_PATCH_LEVEL); } const char* GetGlslVersionString() { - return "4.20 glslang LunarG Khronos." GLSLANG_REVISION " " GLSLANG_DATE; + return "4.60 glslang Khronos. " STR(GLSLANG_MINOR_VERSION) "." STR(GLSLANG_PATCH_LEVEL); } int GetKhronosToolId() @@ -1422,12 +1603,20 @@ public: virtual bool compile(TIntermNode*, int = 0, EProfile = ENoProfile) { return true; } }; -TShader::TShader(EShLanguage s) - : pool(0), stage(s), lengths(nullptr), stringNames(nullptr), preamble("") +TShader::TShader(EShLanguage s) + : stage(s), lengths(nullptr), stringNames(nullptr), preamble("") { + pool = new TPoolAllocator; infoSink = new TInfoSink; compiler = new TDeferredCompiler(stage, *infoSink); intermediate = new TIntermediate(s); + + // clear environment (avoid constructors in them for use in a C interface) + environment.input.languageFamily = EShSourceNone; + environment.input.dialect = EShClientNone; + environment.client.client = EShClientNone; + environment.target.language = EShTargetNone; + environment.target.hlslFunctionality1 = false; } TShader::~TShader() @@ -1463,9 +1652,56 @@ void TShader::setStringsWithLengthsAndNames( void TShader::setEntryPoint(const char* entryPoint) { - intermediate->setEntryPoint(entryPoint); + intermediate->setEntryPointName(entryPoint); } +void TShader::setSourceEntryPoint(const char* name) +{ + sourceEntryPointName = name; +} + +void TShader::addProcesses(const std::vector& p) +{ + intermediate->addProcesses(p); +} + +// Set binding base for given resource type +void TShader::setShiftBinding(TResourceType res, unsigned int base) { + intermediate->setShiftBinding(res, base); +} + +// Set binding base for given resource type for a given binding set. +void TShader::setShiftBindingForSet(TResourceType res, unsigned int base, unsigned int set) { + intermediate->setShiftBindingForSet(res, base, set); +} + +// Set binding base for sampler types +void TShader::setShiftSamplerBinding(unsigned int base) { setShiftBinding(EResSampler, base); } +// Set binding base for texture types (SRV) +void TShader::setShiftTextureBinding(unsigned int base) { setShiftBinding(EResTexture, base); } +// Set binding base for image types +void TShader::setShiftImageBinding(unsigned int base) { setShiftBinding(EResImage, base); } +// Set binding base for uniform buffer objects (CBV) +void TShader::setShiftUboBinding(unsigned int base) { setShiftBinding(EResUbo, base); } +// Synonym for setShiftUboBinding, to match HLSL language. +void TShader::setShiftCbufferBinding(unsigned int base) { setShiftBinding(EResUbo, base); } +// Set binding base for UAV (unordered access view) +void TShader::setShiftUavBinding(unsigned int base) { setShiftBinding(EResUav, base); } +// Set binding base for SSBOs +void TShader::setShiftSsboBinding(unsigned int base) { setShiftBinding(EResSsbo, base); } +// Enables binding automapping using TIoMapper +void TShader::setAutoMapBindings(bool map) { intermediate->setAutoMapBindings(map); } +// Enables position.Y output negation in vertex shader +void TShader::setInvertY(bool invert) { intermediate->setInvertY(invert); } +// Fragile: currently within one stage: simple auto-assignment of location +void TShader::setAutoMapLocations(bool map) { intermediate->setAutoMapLocations(map); } +// See comment above TDefaultHlslIoMapper in iomapper.cpp: +void TShader::setHlslIoMapping(bool hlslIoMap) { intermediate->setHlslIoMapping(hlslIoMap); } +void TShader::setFlattenUniformArrays(bool flatten) { intermediate->setFlattenUniformArrays(flatten); } +void TShader::setNoStorageFormat(bool useUnknownFormat) { intermediate->setNoStorageFormat(useUnknownFormat); } +void TShader::setResourceSetBinding(const std::vector& base) { intermediate->setResourceSetBinding(base); } +void TShader::setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { intermediate->setTextureSamplerTransformMode(mode); } + // // Turn the shader strings into a parse tree in the TIntermediate. // @@ -1476,21 +1712,16 @@ bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion { if (! InitThread()) return false; - - pool = new TPoolAllocator(); - SetThreadPoolAllocator(*pool); + SetThreadPoolAllocator(pool); + if (! preamble) preamble = ""; return CompileDeferred(compiler, strings, numStrings, lengths, stringNames, preamble, EShOptNone, builtInResources, defaultVersion, defaultProfile, forceDefaultVersionAndProfile, - forwardCompatible, messages, *intermediate, includer); -} - -bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion, bool forwardCompatible, EShMessages messages) -{ - return parse(builtInResources, defaultVersion, ENoProfile, false, forwardCompatible, messages); + forwardCompatible, messages, *intermediate, includer, sourceEntryPointName, + &environment); } // Fill in a string with the result of preprocessing ShaderStrings @@ -1504,9 +1735,8 @@ bool TShader::preprocess(const TBuiltInResource* builtInResources, { if (! InitThread()) return false; + SetThreadPoolAllocator(pool); - pool = new TPoolAllocator(); - SetThreadPoolAllocator(*pool); if (! preamble) preamble = ""; @@ -1526,8 +1756,9 @@ const char* TShader::getInfoDebugLog() return infoSink->debug.c_str(); } -TProgram::TProgram() : pool(0), reflection(0), linked(false) +TProgram::TProgram() : reflection(0), ioMapper(nullptr), linked(false) { + pool = new TPoolAllocator; infoSink = new TInfoSink; for (int s = 0; s < EShLangCount; ++s) { intermediate[s] = 0; @@ -1537,6 +1768,7 @@ TProgram::TProgram() : pool(0), reflection(0), linked(false) TProgram::~TProgram() { + delete ioMapper; delete infoSink; delete reflection; @@ -1560,9 +1792,8 @@ bool TProgram::link(EShMessages messages) linked = true; bool error = false; - - pool = new TPoolAllocator(); - SetThreadPoolAllocator(*pool); + + SetThreadPoolAllocator(pool); for (int s = 0; s < EShLangCount; ++s) { if (! linkStage((EShLanguage)s, messages)) @@ -1612,10 +1843,20 @@ bool TProgram::linkStage(EShLanguage stage, EShMessages messages) intermediate[stage] = new TIntermediate(stage, firstIntermediate->getVersion(), firstIntermediate->getProfile()); + + + // The new TIntermediate must use the same origin as the original TIntermediates. + // Otherwise linking will fail due to different coordinate systems. + if (firstIntermediate->getOriginUpperLeft()) { + intermediate[stage]->setOriginUpperLeft(); + } + intermediate[stage]->setSpv(firstIntermediate->getSpv()); + newedIntermediate[stage] = true; } - infoSink->info << "\nLinked " << StageName(stage) << " stage:\n\n"; + if (messages & EShMsgAST) + infoSink->info << "\nLinked " << StageName(stage) << " stage:\n\n"; if (stages[stage].size() > 1) { std::list::const_iterator it; @@ -1623,7 +1864,7 @@ bool TProgram::linkStage(EShLanguage stage, EShMessages messages) intermediate[stage]->merge(*infoSink, *(*it)->intermediate); } - intermediate[stage]->finalCheck(*infoSink); + intermediate[stage]->finalCheck(*infoSink, (messages & EShMsgKeepUncalled) != 0); if (messages & EShMsgAST) intermediate[stage]->output(*infoSink, true); @@ -1646,7 +1887,7 @@ const char* TProgram::getInfoDebugLog() // bool TProgram::buildReflection() -{ +{ if (! linked || reflection) return false; @@ -1662,20 +1903,47 @@ bool TProgram::buildReflection() return true; } -int TProgram::getNumLiveUniformVariables() { return reflection->getNumUniforms(); } -int TProgram::getNumLiveUniformBlocks() { return reflection->getNumUniformBlocks(); } -const char* TProgram::getUniformName(int index) { return reflection->getUniform(index).name.c_str(); } -const char* TProgram::getUniformBlockName(int index) { return reflection->getUniformBlock(index).name.c_str(); } -int TProgram::getUniformBlockSize(int index) { return reflection->getUniformBlock(index).size; } -int TProgram::getUniformIndex(const char* name) { return reflection->getIndex(name); } -int TProgram::getUniformBlockIndex(int index) { return reflection->getUniform(index).index; } -int TProgram::getUniformType(int index) { return reflection->getUniform(index).glDefineType; } -int TProgram::getUniformBufferOffset(int index) { return reflection->getUniform(index).offset; } -int TProgram::getUniformArraySize(int index) { return reflection->getUniform(index).size; } -int TProgram::getNumLiveAttributes() { return reflection->getNumAttributes(); } -const char* TProgram::getAttributeName(int index) { return reflection->getAttribute(index).name.c_str(); } -int TProgram::getAttributeType(int index) { return reflection->getAttribute(index).glDefineType; } +int TProgram::getNumLiveUniformVariables() const { return reflection->getNumUniforms(); } +int TProgram::getNumLiveUniformBlocks() const { return reflection->getNumUniformBlocks(); } +const char* TProgram::getUniformName(int index) const { return reflection->getUniform(index).name.c_str(); } +const char* TProgram::getUniformBlockName(int index) const { return reflection->getUniformBlock(index).name.c_str(); } +int TProgram::getUniformBlockSize(int index) const { return reflection->getUniformBlock(index).size; } +int TProgram::getUniformIndex(const char* name) const { return reflection->getIndex(name); } +int TProgram::getUniformBinding(int index) const { return reflection->getUniform(index).getBinding(); } +int TProgram::getUniformBlockBinding(int index) const { return reflection->getUniformBlock(index).getBinding(); } +int TProgram::getUniformBlockIndex(int index) const { return reflection->getUniform(index).index; } +int TProgram::getUniformBlockCounterIndex(int index) const { return reflection->getUniformBlock(index).counterIndex; } +int TProgram::getUniformType(int index) const { return reflection->getUniform(index).glDefineType; } +int TProgram::getUniformBufferOffset(int index) const { return reflection->getUniform(index).offset; } +int TProgram::getUniformArraySize(int index) const { return reflection->getUniform(index).size; } +int TProgram::getNumLiveAttributes() const { return reflection->getNumAttributes(); } +const char* TProgram::getAttributeName(int index) const { return reflection->getAttribute(index).name.c_str(); } +int TProgram::getAttributeType(int index) const { return reflection->getAttribute(index).glDefineType; } +const TType* TProgram::getAttributeTType(int index) const { return reflection->getAttribute(index).getType(); } +const TType* TProgram::getUniformTType(int index) const { return reflection->getUniform(index).getType(); } +const TType* TProgram::getUniformBlockTType(int index) const { return reflection->getUniformBlock(index).getType(); } +unsigned TProgram::getLocalSize(int dim) const { return reflection->getLocalSize(dim); } void TProgram::dumpReflection() { reflection->dump(); } +// +// I/O mapping implementation. +// +bool TProgram::mapIO(TIoMapResolver* resolver) +{ + if (! linked || ioMapper) + return false; + + ioMapper = new TIoMapper; + + for (int s = 0; s < EShLangCount; ++s) { + if (intermediate[s]) { + if (! ioMapper->addStage((EShLanguage)s, *intermediate[s], *infoSink, resolver)) + return false; + } + } + + return true; +} + } // end namespace glslang diff --git a/Externals/glslang/glslang/MachineIndependent/SymbolTable.cpp b/Externals/glslang/glslang/MachineIndependent/SymbolTable.cpp index bf0f1f9fa7..db46e1075d 100644 --- a/Externals/glslang/glslang/MachineIndependent/SymbolTable.cpp +++ b/Externals/glslang/glslang/MachineIndependent/SymbolTable.cpp @@ -1,12 +1,13 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2012-2013 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2012-2013 LunarG, Inc. +// Copyright (C) 2017 ARM Limited. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,22 +21,22 @@ // 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. +// 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. // // -// Symbol table for parsing. Most functionaliy and main ideas +// Symbol table for parsing. Most functionality and main ideas // are documented in the header file. // @@ -50,7 +51,7 @@ namespace glslang { // // Recursively generate mangled names. // -void TType::buildMangledName(TString& mangledName) +void TType::buildMangledName(TString& mangledName) const { if (isMatrix()) mangledName += 'm'; @@ -60,14 +61,22 @@ void TType::buildMangledName(TString& mangledName) switch (basicType) { case EbtFloat: mangledName += 'f'; break; case EbtDouble: mangledName += 'd'; break; + case EbtFloat16: mangledName += "f16"; break; case EbtInt: mangledName += 'i'; break; case EbtUint: mangledName += 'u'; break; + case EbtInt8: mangledName += "i8"; break; + case EbtUint8: mangledName += "u8"; break; + case EbtInt16: mangledName += "i16"; break; + case EbtUint16: mangledName += "u16"; break; case EbtInt64: mangledName += "i64"; break; case EbtUint64: mangledName += "u64"; break; case EbtBool: mangledName += 'b'; break; case EbtAtomicUint: mangledName += "au"; break; case EbtSampler: switch (sampler.type) { +#ifdef AMD_EXTENSIONS + case EbtFloat16: mangledName += "f16"; break; +#endif case EbtInt: mangledName += "i"; break; case EbtUint: mangledName += "u"; break; default: break; // some compilers want this @@ -96,11 +105,32 @@ void TType::buildMangledName(TString& mangledName) case EsdSubpass: mangledName += "P"; break; default: break; // some compilers want this } + + if (sampler.hasReturnStruct()) { + // Name mangle for sampler return struct uses struct table index. + mangledName += "-tx-struct"; + + char text[16]; // plenty enough space for the small integers. + snprintf(text, sizeof(text), "%d-", sampler.structReturnIndex); + mangledName += text; + } else { + switch (sampler.getVectorSize()) { + case 1: mangledName += "1"; break; + case 2: mangledName += "2"; break; + case 3: mangledName += "3"; break; + case 4: break; // default to prior name mangle behavior + } + } + if (sampler.ms) mangledName += "M"; break; case EbtStruct: - mangledName += "struct-"; + case EbtBlock: + if (basicType == EbtStruct) + mangledName += "struct-"; + else + mangledName += "block-"; if (typeName) mangledName += *typeName; for (unsigned int i = 0; i < structure->size(); ++i) { @@ -250,7 +280,7 @@ TSymbol::TSymbol(const TSymbol& copyOf) } TVariable::TVariable(const TVariable& copyOf) : TSymbol(copyOf) -{ +{ type.deepCopy(copyOf.type); userType = copyOf.userType; numExtensions = 0; @@ -276,7 +306,7 @@ TVariable* TVariable::clone() const } TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf) -{ +{ for (unsigned int i = 0; i < copyOf.parameters.size(); ++i) { TParameter param; parameters.push_back(param); @@ -292,6 +322,9 @@ TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf) op = copyOf.op; defined = copyOf.defined; prototyped = copyOf.prototyped; + implicitThis = copyOf.implicitThis; + illegalImplicitThis = copyOf.illegalImplicitThis; + defaultParamCount = copyOf.defaultParamCount; } TFunction* TFunction::clone() const @@ -315,6 +348,7 @@ TSymbolTableLevel* TSymbolTableLevel::clone() const { TSymbolTableLevel *symTableLevel = new TSymbolTableLevel(); symTableLevel->anonId = anonId; + symTableLevel->thisLevel = thisLevel; std::vector containerCopied(anonId, false); tLevel::const_iterator iter; for (iter = level.begin(); iter != level.end(); ++iter) { diff --git a/Externals/glslang/glslang/MachineIndependent/SymbolTable.h b/Externals/glslang/glslang/MachineIndependent/SymbolTable.h index 9877ab7fae..f928b7aedf 100644 --- a/Externals/glslang/glslang/MachineIndependent/SymbolTable.h +++ b/Externals/glslang/glslang/MachineIndependent/SymbolTable.h @@ -1,12 +1,12 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2013 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2013 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,18 +20,18 @@ // 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. +// 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 _SYMBOL_TABLE_INCLUDED_ @@ -87,6 +87,12 @@ public: virtual const TString& getName() const { return *name; } virtual void changeName(const TString* newName) { name = newName; } + virtual void addPrefix(const char* prefix) + { + TString newName(prefix); + newName.append(*name); + changeName(NewPoolTString(newName.c_str())); + } virtual const TString& getMangledName() const { return getName(); } virtual TFunction* getAsFunction() { return 0; } virtual const TFunction* getAsFunction() const { return 0; } @@ -120,7 +126,7 @@ protected: const TString *name; unsigned int uniqueId; // For cross-scope comparing during code generation - // For tracking what extensions must be present + // For tracking what extensions must be present // (don't use if correct version/profile is present). int numExtensions; const char** extensions; // an array of pointers to existing constant char strings @@ -145,9 +151,10 @@ protected: class TVariable : public TSymbol { public: TVariable(const TString *name, const TType& t, bool uT = false ) - : TSymbol(name), + : TSymbol(name), userType(uT), - constSubtree(nullptr) { type.shallowCopy(t); } + constSubtree(nullptr), + anonId(-1) { type.shallowCopy(t); } virtual TVariable* clone() const; virtual ~TVariable() { } @@ -161,6 +168,8 @@ public: virtual void setConstArray(const TConstUnionArray& array) { constArray = array; } virtual void setConstSubtree(TIntermTyped* subtree) { constSubtree = subtree; } virtual TIntermTyped* getConstSubtree() const { return constSubtree; } + virtual void setAnonId(int i) { anonId = i; } + virtual int getAnonId() const { return anonId; } virtual void dump(TInfoSink &infoSink) const; @@ -178,6 +187,7 @@ protected: // constant, or neither, but never both. TConstUnionArray constArray; // for compile-time constant value TIntermTyped* constSubtree; // for specialization constant computation + int anonId; // the ID used for anonymous blocks: TODO: see if uniqueId could serve a dual purpose }; // @@ -187,14 +197,17 @@ protected: struct TParameter { TString *name; TType* type; - void copyParam(const TParameter& param) + TIntermTyped* defaultValue; + void copyParam(const TParameter& param) { if (param.name) name = NewPoolTString(param.name->c_str()); else name = 0; type = param.type->clone(); + defaultValue = param.defaultValue; } + TBuiltInVariable getDeclaredBuiltIn() const { return type->getQualifier().declaredBuiltIn; } }; // @@ -205,40 +218,82 @@ public: explicit TFunction(TOperator o) : TSymbol(0), op(o), - defined(false), prototyped(false) { } + defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), defaultParamCount(0) { } TFunction(const TString *name, const TType& retType, TOperator tOp = EOpNull) : TSymbol(name), mangledName(*name + '('), op(tOp), - defined(false), prototyped(false) { returnType.shallowCopy(retType); } - virtual TFunction* clone() const; + defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), defaultParamCount(0) + { + returnType.shallowCopy(retType); + declaredBuiltIn = retType.getQualifier().builtIn; + } + virtual TFunction* clone() const override; virtual ~TFunction(); - virtual TFunction* getAsFunction() { return this; } - virtual const TFunction* getAsFunction() const { return this; } + virtual TFunction* getAsFunction() override { return this; } + virtual const TFunction* getAsFunction() const override { return this; } + // Install 'p' as the (non-'this') last parameter. + // Non-'this' parameters are reflected in both the list of parameters and the + // mangled name. virtual void addParameter(TParameter& p) { assert(writable); parameters.push_back(p); p.type->appendMangledName(mangledName); + + if (p.defaultValue != nullptr) + defaultParamCount++; } - virtual const TString& getMangledName() const { return mangledName; } - virtual const TType& getType() const { return returnType; } - virtual TType& getWritableType() { return returnType; } + // Install 'this' as the first parameter. + // 'this' is reflected in the list of parameters, but not the mangled name. + virtual void addThisParameter(TType& type, const char* name) + { + TParameter p = { NewPoolTString(name), new TType, nullptr }; + p.type->shallowCopy(type); + parameters.insert(parameters.begin(), p); + } + + virtual void addPrefix(const char* prefix) override + { + TSymbol::addPrefix(prefix); + mangledName.insert(0, prefix); + } + + virtual void removePrefix(const TString& prefix) + { + assert(mangledName.compare(0, prefix.size(), prefix) == 0); + mangledName.erase(0, prefix.size()); + } + + virtual const TString& getMangledName() const override { return mangledName; } + virtual const TType& getType() const override { return returnType; } + virtual TBuiltInVariable getDeclaredBuiltInType() const { return declaredBuiltIn; } + virtual TType& getWritableType() override { return returnType; } virtual void relateToOperator(TOperator o) { assert(writable); op = o; } virtual TOperator getBuiltInOp() const { return op; } virtual void setDefined() { assert(writable); defined = true; } virtual bool isDefined() const { return defined; } virtual void setPrototyped() { assert(writable); prototyped = true; } virtual bool isPrototyped() const { return prototyped; } + virtual void setImplicitThis() { assert(writable); implicitThis = true; } + virtual bool hasImplicitThis() const { return implicitThis; } + virtual void setIllegalImplicitThis() { assert(writable); illegalImplicitThis = true; } + virtual bool hasIllegalImplicitThis() const { return illegalImplicitThis; } + // Return total number of parameters virtual int getParamCount() const { return static_cast(parameters.size()); } + // Return number of parameters with default values. + virtual int getDefaultParamCount() const { return defaultParamCount; } + // Return number of fixed parameters (without default values) + virtual int getFixedParamCount() const { return getParamCount() - getDefaultParamCount(); } + virtual TParameter& operator[](int i) { assert(writable); return parameters[i]; } virtual const TParameter& operator[](int i) const { return parameters[i]; } - virtual void dump(TInfoSink &infoSink) const; + virtual void dump(TInfoSink &infoSink) const override; protected: explicit TFunction(const TFunction&); @@ -247,10 +302,18 @@ protected: typedef TVector TParamList; TParamList parameters; TType returnType; + TBuiltInVariable declaredBuiltIn; + TString mangledName; TOperator op; bool defined; bool prototyped; + bool implicitThis; // True if this function is allowed to see all members of 'this' + bool illegalImplicitThis; // True if this function is not supposed to have access to dynamic members of 'this', + // 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. + int defaultParamCount; }; // @@ -268,7 +331,7 @@ public: virtual const TAnonMember* getAsAnonMember() const { return this; } virtual const TVariable& getAnonContainer() const { return anonContainer; } virtual unsigned int getMemberNumber() const { return memberNumber; } - + virtual const TType& getType() const { const TTypeList& types = *anonContainer.getType().getStruct(); @@ -281,7 +344,7 @@ public: const TTypeList& types = *anonContainer.getType().getStruct(); return *types[memberNumber].type; } - + virtual int getAnonId() const { return anonId; } virtual void dump(TInfoSink &infoSink) const; @@ -297,7 +360,7 @@ protected: class TSymbolTableLevel { public: POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) - TSymbolTableLevel() : defaultPrecision(0), anonId(0) { } + TSymbolTableLevel() : defaultPrecision(0), anonId(0), thisLevel(false) { } ~TSymbolTableLevel(); bool insert(TSymbol& symbol, bool separateNameSpaces) @@ -305,27 +368,16 @@ public: // // returning true means symbol was added to the table with no semantic errors // - tInsertResult result; const TString& name = symbol.getName(); if (name == "") { + symbol.getAsVariable()->setAnonId(anonId++); // An empty name means an anonymous container, exposing its members to the external scope. // Give it a name and insert its members in the symbol table, pointing to the container. char buf[20]; - snprintf(buf, 20, "%s%d", AnonymousPrefix, anonId); + snprintf(buf, 20, "%s%d", AnonymousPrefix, symbol.getAsVariable()->getAnonId()); symbol.changeName(NewPoolTString(buf)); - bool isOkay = true; - const TTypeList& types = *symbol.getAsVariable()->getType().getStruct(); - for (unsigned int m = 0; m < types.size(); ++m) { - TAnonMember* member = new TAnonMember(&types[m].type->getFieldName(), m, *symbol.getAsVariable(), anonId); - result = level.insert(tLevelPair(member->getMangledName(), member)); - if (! result.second) - isOkay = false; - } - - ++anonId; - - return isOkay; + return insertAnonymousMembers(symbol, 0); } else { // Check for redefinition errors: // - STL itself will tell us if there is a direct name collision, with name mangling, at this level @@ -340,24 +392,45 @@ public: level.insert(tLevelPair(insertName, &symbol)); return true; - } else { - result = level.insert(tLevelPair(insertName, &symbol)); - - return result.second; - } + } else + return level.insert(tLevelPair(insertName, &symbol)).second; } } + // Add more members to an already inserted aggregate object + bool amend(TSymbol& symbol, int firstNewMember) + { + // See insert() for comments on basic explanation of insert. + // This operates similarly, but more simply. + // Only supporting amend of anonymous blocks so far. + if (IsAnonymous(symbol.getName())) + return insertAnonymousMembers(symbol, firstNewMember); + else + return false; + } + + bool insertAnonymousMembers(TSymbol& symbol, int firstMember) + { + const TTypeList& types = *symbol.getAsVariable()->getType().getStruct(); + for (unsigned int m = firstMember; m < types.size(); ++m) { + TAnonMember* member = new TAnonMember(&types[m].type->getFieldName(), m, *symbol.getAsVariable(), symbol.getAsVariable()->getAnonId()); + if (! level.insert(tLevelPair(member->getMangledName(), member)).second) + return false; + } + + return true; + } + TSymbol* find(const TString& name) const { tLevel::const_iterator it = level.find(name); - if (it == level.end()) + if (it == level.end()) return 0; else return (*it).second; } - void findFunctionNameList(const TString& name, TVector& list) + void findFunctionNameList(const TString& name, TVector& list) { size_t parenAt = name.find_first_of('('); TString base(name, 0, parenAt + 1); @@ -445,6 +518,9 @@ public: TSymbolTableLevel* clone() const; void readOnly(); + void setThisLevel() { thisLevel = true; } + bool isThisLevel() const { return thisLevel; } + protected: explicit TSymbolTableLevel(TSymbolTableLevel&); TSymbolTableLevel& operator=(TSymbolTableLevel&); @@ -456,6 +532,8 @@ protected: tLevel level; // named mappings TPrecisionQualifier *defaultPrecision; int anonId; + bool thisLevel; // True if this level of the symbol table is a structure scope containing member function + // that are supposed to see anonymous access to member variables. }; class TSymbolTable { @@ -474,7 +552,7 @@ public: while (table.size() > adoptedLevels) pop(0); } - + void adoptLevels(TSymbolTable& symTable) { for (unsigned int level = 0; level < symTable.table.size(); ++level) { @@ -506,12 +584,26 @@ public: void setNoBuiltInRedeclarations() { noBuiltInRedeclarations = true; } void setSeparateNameSpaces() { separateNameSpaces = true; } - + void push() { table.push_back(new TSymbolTableLevel); } + // Make a new symbol-table level to represent the scope introduced by a structure + // containing member functions, such that the member functions can find anonymous + // references to member variables. + // + // 'thisSymbol' should have a name of "" to trigger anonymous structure-member + // symbol finds. + void pushThis(TSymbol& thisSymbol) + { + assert(thisSymbol.getName().size() == 0); + table.push_back(new TSymbolTableLevel); + table.back()->setThisLevel(); + insert(thisSymbol); + } + void pop(TPrecisionQualifier *p) { table[currentLevel()]->getPreviousDefaultPrecisions(p); @@ -532,7 +624,7 @@ public: // make sure there isn't a function of this variable name if (! separateNameSpaces && ! symbol.getAsFunction() && table[currentLevel()]->hasFunctionName(symbol.getName())) return false; - + // check for not overloading or redefining a built-in function if (noBuiltInRedeclarations) { if (atGlobalLevel() && currentLevel() > 0) { @@ -546,9 +638,17 @@ public: return table[currentLevel()]->insert(symbol, separateNameSpaces); } + // Add more members to an already inserted aggregate object + bool amend(TSymbol& symbol, int firstNewMember) + { + // See insert() for comments on basic explanation of insert. + // This operates similarly, but more simply. + return table[currentLevel()]->amend(symbol, firstNewMember); + } + // // To allocate an internal temporary, which will need to be uniquely - // identified by the consumer of the AST, but never need to + // identified by the consumer of the AST, but never need to // found by doing a symbol table search by name, hence allowed an // arbitrary name in the symbol with no worry of collision. // @@ -590,19 +690,50 @@ public: } } - TSymbol* find(const TString& name, bool* builtIn = 0, bool *currentScope = 0) + // Normal find of a symbol, that can optionally say whether the symbol was found + // at a built-in level or the current top-scope level. + TSymbol* find(const TString& name, bool* builtIn = 0, bool* currentScope = 0, int* thisDepthP = 0) { int level = currentLevel(); TSymbol* symbol; + int thisDepth = 0; do { + if (table[level]->isThisLevel()) + ++thisDepth; symbol = table[level]->find(name); --level; - } while (symbol == 0 && level >= 0); + } while (symbol == nullptr && level >= 0); level++; if (builtIn) *builtIn = isBuiltInLevel(level); if (currentScope) *currentScope = isGlobalLevel(currentLevel()) || level == currentLevel(); // consider shared levels as "current scope" WRT user globals + if (thisDepthP != nullptr) { + if (! table[level]->isThisLevel()) + thisDepth = 0; + *thisDepthP = thisDepth; + } + + return symbol; + } + + // Find of a symbol that returns how many layers deep of nested + // structures-with-member-functions ('this' scopes) deep the symbol was + // found in. + TSymbol* find(const TString& name, int& thisDepth) + { + int level = currentLevel(); + TSymbol* symbol; + thisDepth = 0; + do { + if (table[level]->isThisLevel()) + ++thisDepth; + symbol = table[level]->find(name); + --level; + } while (symbol == 0 && level >= 0); + + if (! table[level + 1]->isThisLevel()) + thisDepth = 0; return symbol; } @@ -624,7 +755,7 @@ public: return false; } - void findFunctionNameList(const TString& name, TVector& list, bool& builtIn) + void findFunctionNameList(const TString& name, TVector& list, bool& builtIn) { // For user levels, return the set found in the first scope with a match builtIn = false; @@ -650,7 +781,7 @@ public: for (unsigned int level = 0; level < table.size(); ++level) table[level]->relateToOperator(name, op); } - + void setFunctionExtensions(const char* name, int num, const char* const extensions[]) { for (unsigned int level = 0; level < table.size(); ++level) diff --git a/Externals/glslang/glslang/MachineIndependent/Versions.cpp b/Externals/glslang/glslang/MachineIndependent/Versions.cpp old mode 100644 new mode 100755 index e46118af3d..51b6430853 --- a/Externals/glslang/glslang/MachineIndependent/Versions.cpp +++ b/Externals/glslang/glslang/MachineIndependent/Versions.cpp @@ -1,12 +1,13 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2012-2013 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2012-2013 LunarG, Inc. +// Copyright (C) 2017 ARM Limited. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,24 +21,24 @@ // 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. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. // // // Help manage multiple profiles, versions, extensions etc. // -// These don't return error codes, as the presumption is parsing will +// These don't return error codes, as the presumption is parsing will // always continue as if the tested feature were enabled, and thus there // is no error recovery needed. // @@ -47,25 +48,25 @@ // // To add a new hypothetical "Feature F" to the front end, where an extension // "XXX_extension_X" can be used to enable the feature, do the following. -// +// // OVERVIEW: Specific features are what are error-checked for, not -// extensions: A specific Feature F might be enabled by an extension, or a +// extensions: A specific Feature F might be enabled by an extension, or a // particular version in a particular profile, or a stage, or combinations, etc. -// -// The basic mechanism is to use the following to "declare" all the things that +// +// The basic mechanism is to use the following to "declare" all the things that // enable/disable Feature F, in a code path that implements Feature F: -// +// // requireProfile() // profileRequires() // requireStage() // checkDeprecated() // requireNotRemoved() // requireExtensions() -// -// Typically, only the first two calls are needed. They go into a code path that -// implements Feature F, and will log the proper error/warning messages. Parsing +// +// Typically, only the first two calls are needed. They go into a code path that +// implements Feature F, and will log the proper error/warning messages. Parsing // will then always continue as if the tested feature was enabled. -// +// // There is typically no if-testing or conditional parsing, just insertion of the calls above. // However, if symbols specific to the extension are added (step 5), they will // only be added under tests that the minimum version and profile are present. @@ -73,10 +74,10 @@ // 1) Add a symbol name for the extension string at the bottom of Versions.h: // // const char* const XXX_extension_X = "XXX_extension_X"; -// +// // 2) Add extension initialization to TParseVersions::initializeExtensionBehavior(), // the first function below: -// +// // extensionBehavior[XXX_extension_X] = EBhDisable; // // 3) Add any preprocessor directives etc. in the next function, TParseVersions::getPreamble(): @@ -84,50 +85,50 @@ // "#define XXX_extension_X 1\n" // // The new-line is important, as that ends preprocess tokens. -// +// // 4) Insert a profile check in the feature's path (unless all profiles support the feature, // for some version level). That is, call requireProfile() to constrain the profiles, e.g.: -// +// // // ... in a path specific to Feature F... // requireProfile(loc, // ECoreProfile | ECompatibilityProfile, // "Feature F"); -// +// // 5) For each profile that supports the feature, insert version/extension checks: -// +// // The mostly likely scenario is that Feature F can only be used with a // particular profile if XXX_extension_X is present or the version is // high enough that the core specification already incorporated it. -// +// // // following the requireProfile() call... -// profileRequires(loc, +// profileRequires(loc, // ECoreProfile | ECompatibilityProfile, // 420, // 0 if no version incorporated the feature into the core spec. // XXX_extension_X, // can be a list of extensions that all add the feature // "Feature F Description"); -// +// // This allows the feature if either A) one of the extensions is enabled or // B) the version is high enough. If no version yet incorporates the feature // into core, pass in 0. -// +// // This can be called multiple times, if different profiles support the -// feature starting at different version numbers or with different +// feature starting at different version numbers or with different // extensions. -// +// // This must be called for each profile allowed by the initial call to requireProfile(). -// +// // Profiles are all masks, which can be "or"-ed together. -// +// // ENoProfile // ECoreProfile // ECompatibilityProfile // EEsProfile -// +// // The ENoProfile profile is only for desktop, before profiles showed up in version 150; // All other #version with no profile default to either es or core, and so have profiles. -// +// // You can select all but a particular profile using ~. The following basically means "desktop": -// +// // ~EEsProfile // // 6) If built-in symbols are added by the extension, add them in Initialize.cpp: Their use @@ -154,8 +155,9 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_OES_standard_derivatives] = EBhDisable; extensionBehavior[E_GL_EXT_frag_depth] = EBhDisable; extensionBehavior[E_GL_OES_EGL_image_external] = EBhDisable; + extensionBehavior[E_GL_OES_EGL_image_external_essl3] = EBhDisable; extensionBehavior[E_GL_EXT_shader_texture_lod] = EBhDisable; - + extensionBehavior[E_GL_EXT_shadow_samplers] = EBhDisable; extensionBehavior[E_GL_ARB_texture_rectangle] = EBhDisable; extensionBehavior[E_GL_3DL_array_objects] = EBhDisable; extensionBehavior[E_GL_ARB_shading_language_420pack] = EBhDisable; @@ -179,14 +181,55 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_ARB_shader_ballot] = EBhDisable; extensionBehavior[E_GL_ARB_sparse_texture2] = EBhDisable; extensionBehavior[E_GL_ARB_sparse_texture_clamp] = EBhDisable; + extensionBehavior[E_GL_ARB_shader_stencil_export] = EBhDisable; // extensionBehavior[E_GL_ARB_cull_distance] = EBhDisable; // present for 4.5, but need extension control over block members + extensionBehavior[E_GL_ARB_post_depth_coverage] = EBhDisable; + extensionBehavior[E_GL_ARB_shader_viewport_layer_array] = EBhDisable; + + extensionBehavior[E_GL_KHR_shader_subgroup_basic] = EBhDisable; + extensionBehavior[E_GL_KHR_shader_subgroup_vote] = EBhDisable; + extensionBehavior[E_GL_KHR_shader_subgroup_arithmetic] = EBhDisable; + extensionBehavior[E_GL_KHR_shader_subgroup_ballot] = EBhDisable; + extensionBehavior[E_GL_KHR_shader_subgroup_shuffle] = EBhDisable; + extensionBehavior[E_GL_KHR_shader_subgroup_shuffle_relative] = EBhDisable; + extensionBehavior[E_GL_KHR_shader_subgroup_clustered] = EBhDisable; + extensionBehavior[E_GL_KHR_shader_subgroup_quad] = EBhDisable; extensionBehavior[E_GL_EXT_shader_non_constant_global_initializers] = EBhDisable; + extensionBehavior[E_GL_EXT_shader_image_load_formatted] = EBhDisable; + extensionBehavior[E_GL_EXT_post_depth_coverage] = EBhDisable; + extensionBehavior[E_GL_EXT_control_flow_attributes] = EBhDisable; + extensionBehavior[E_GL_EXT_nonuniform_qualifier] = EBhDisable; // #line and #include extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive] = EBhDisable; extensionBehavior[E_GL_GOOGLE_include_directive] = EBhDisable; +#ifdef AMD_EXTENSIONS + extensionBehavior[E_GL_AMD_shader_ballot] = EBhDisable; + extensionBehavior[E_GL_AMD_shader_trinary_minmax] = EBhDisable; + extensionBehavior[E_GL_AMD_shader_explicit_vertex_parameter] = EBhDisable; + extensionBehavior[E_GL_AMD_gcn_shader] = EBhDisable; + extensionBehavior[E_GL_AMD_gpu_shader_half_float] = EBhDisable; + extensionBehavior[E_GL_AMD_texture_gather_bias_lod] = EBhDisable; + extensionBehavior[E_GL_AMD_gpu_shader_int16] = EBhDisable; + extensionBehavior[E_GL_AMD_shader_image_load_store_lod] = EBhDisable; + extensionBehavior[E_GL_AMD_shader_fragment_mask] = EBhDisable; + extensionBehavior[E_GL_AMD_gpu_shader_half_float_fetch] = EBhDisable; +#endif + +#ifdef NV_EXTENSIONS + extensionBehavior[E_GL_NV_sample_mask_override_coverage] = EBhDisable; + extensionBehavior[E_SPV_NV_geometry_shader_passthrough] = EBhDisable; + extensionBehavior[E_GL_NV_viewport_array2] = EBhDisable; + extensionBehavior[E_GL_NV_stereo_view_rendering] = EBhDisable; + extensionBehavior[E_GL_NVX_multiview_per_view_attributes] = EBhDisable; + extensionBehavior[E_GL_NV_shader_atomic_int64] = EBhDisable; + extensionBehavior[E_GL_NV_conservative_raster_underestimation] = EBhDisable; + extensionBehavior[E_GL_NV_shader_noperspective_interpolation] = EBhDisable; + extensionBehavior[E_GL_NV_shader_subgroup_partitioned] = EBhDisable; +#endif + // AEP extensionBehavior[E_GL_ANDROID_extension_pack_es31a] = EBhDisable; extensionBehavior[E_GL_KHR_blend_equation_advanced] = EBhDisable; @@ -214,6 +257,24 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_OES_tessellation_point_size] = EBhDisable; extensionBehavior[E_GL_OES_texture_buffer] = EBhDisable; extensionBehavior[E_GL_OES_texture_cube_map_array] = EBhDisable; + + // EXT extensions + extensionBehavior[E_GL_EXT_device_group] = EBhDisable; + extensionBehavior[E_GL_EXT_multiview] = EBhDisable; + + // OVR extensions + extensionBehavior[E_GL_OVR_multiview] = EBhDisable; + extensionBehavior[E_GL_OVR_multiview2] = EBhDisable; + + // explicit types + extensionBehavior[E_GL_KHX_shader_explicit_arithmetic_types] = EBhDisable; + extensionBehavior[E_GL_KHX_shader_explicit_arithmetic_types_int8] = EBhDisable; + extensionBehavior[E_GL_KHX_shader_explicit_arithmetic_types_int16] = EBhDisable; + extensionBehavior[E_GL_KHX_shader_explicit_arithmetic_types_int32] = EBhDisable; + extensionBehavior[E_GL_KHX_shader_explicit_arithmetic_types_int64] = EBhDisable; + extensionBehavior[E_GL_KHX_shader_explicit_arithmetic_types_float16] = EBhDisable; + extensionBehavior[E_GL_KHX_shader_explicit_arithmetic_types_float32] = EBhDisable; + extensionBehavior[E_GL_KHX_shader_explicit_arithmetic_types_float64] = EBhDisable; } // Get code that is not part of a shared symbol table, is specific to this shader, @@ -221,14 +282,16 @@ void TParseVersions::initializeExtensionBehavior() void TParseVersions::getPreamble(std::string& preamble) { if (profile == EEsProfile) { - preamble = + preamble = "#define GL_ES 1\n" "#define GL_FRAGMENT_PRECISION_HIGH 1\n" "#define GL_OES_texture_3D 1\n" "#define GL_OES_standard_derivatives 1\n" "#define GL_EXT_frag_depth 1\n" "#define GL_OES_EGL_image_external 1\n" + "#define GL_OES_EGL_image_external_essl3 1\n" "#define GL_EXT_shader_texture_lod 1\n" + "#define GL_EXT_shadow_samplers 1\n" // AEP "#define GL_ANDROID_extension_pack_es31a 1\n" @@ -259,8 +322,15 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_OES_texture_cube_map_array 1\n" "#define GL_EXT_shader_non_constant_global_initializers 1\n" ; + +#ifdef NV_EXTENSIONS + if (profile == EEsProfile && version >= 300) { + preamble += "#define GL_NV_shader_noperspective_interpolation 1\n"; + } +#endif + } else { - preamble = + preamble = "#define GL_FRAGMENT_PRECISION_HIGH 1\n" "#define GL_ARB_texture_rectangle 1\n" "#define GL_ARB_shading_language_420pack 1\n" @@ -284,13 +354,82 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_ARB_shader_ballot 1\n" "#define GL_ARB_sparse_texture2 1\n" "#define GL_ARB_sparse_texture_clamp 1\n" + "#define GL_ARB_shader_stencil_export 1\n" // "#define GL_ARB_cull_distance 1\n" // present for 4.5, but need extension control over block members + "#define GL_ARB_post_depth_coverage 1\n" "#define GL_EXT_shader_non_constant_global_initializers 1\n" + "#define GL_EXT_shader_image_load_formatted 1\n" + "#define GL_EXT_post_depth_coverage 1\n" + "#define GL_EXT_control_flow_attributes 1\n" + "#define GL_EXT_nonuniform_qualifier 1\n" + + // GL_KHR_shader_subgroup + "#define GL_KHR_shader_subgroup_basic 1\n" + "#define GL_KHR_shader_subgroup_vote 1\n" + "#define GL_KHR_shader_subgroup_arithmetic 1\n" + "#define GL_KHR_shader_subgroup_ballot 1\n" + "#define GL_KHR_shader_subgroup_shuffle 1\n" + "#define GL_KHR_shader_subgroup_shuffle_relative 1\n" + "#define GL_KHR_shader_subgroup_clustered 1\n" + "#define GL_KHR_shader_subgroup_quad 1\n" + +#ifdef AMD_EXTENSIONS + "#define GL_AMD_shader_ballot 1\n" + "#define GL_AMD_shader_trinary_minmax 1\n" + "#define GL_AMD_shader_explicit_vertex_parameter 1\n" + "#define GL_AMD_gcn_shader 1\n" + "#define GL_AMD_gpu_shader_half_float 1\n" + "#define GL_AMD_texture_gather_bias_lod 1\n" + "#define GL_AMD_gpu_shader_int16 1\n" + "#define GL_AMD_shader_image_load_store_lod 1\n" + "#define GL_AMD_shader_fragment_mask 1\n" + "#define GL_AMD_gpu_shader_half_float_fetch 1\n" +#endif + +#ifdef NV_EXTENSIONS + "#define GL_NV_sample_mask_override_coverage 1\n" + "#define GL_NV_geometry_shader_passthrough 1\n" + "#define GL_NV_viewport_array2 1\n" + "#define GL_NV_shader_atomic_int64 1\n" + "#define GL_NV_conservative_raster_underestimation 1\n" + "#define GL_NV_shader_subgroup_partitioned 1\n" +#endif + "#define GL_KHX_shader_explicit_arithmetic_types 1\n" + "#define GL_KHX_shader_explicit_arithmetic_types_int8 1\n" + "#define GL_KHX_shader_explicit_arithmetic_types_int16 1\n" + "#define GL_KHX_shader_explicit_arithmetic_types_int32 1\n" + "#define GL_KHX_shader_explicit_arithmetic_types_int64 1\n" + "#define GL_KHX_shader_explicit_arithmetic_types_float16 1\n" + "#define GL_KHX_shader_explicit_arithmetic_types_float32 1\n" + "#define GL_KHX_shader_explicit_arithmetic_types_float64 1\n" + ; + + if (version >= 150) { + // define GL_core_profile and GL_compatibility_profile + preamble += "#define GL_core_profile 1\n"; + + if (profile == ECompatibilityProfile) + preamble += "#define GL_compatibility_profile 1\n"; + } + } + + if ((profile != EEsProfile && version >= 140) || + (profile == EEsProfile && version >= 310)) { + preamble += + "#define GL_EXT_device_group 1\n" + "#define GL_EXT_multiview 1\n" + ; + } + + if (version >= 300 /* both ES and non-ES */) { + preamble += + "#define GL_OVR_multiview 1\n" + "#define GL_OVR_multiview2 1\n" ; } // #line and #include - preamble += + preamble += "#define GL_GOOGLE_cpp_style_line_directive 1\n" "#define GL_GOOGLE_include_directive 1\n" ; @@ -298,9 +437,9 @@ void TParseVersions::getPreamble(std::string& preamble) // #define VULKAN XXXX const int numberBufSize = 12; char numberBuf[numberBufSize]; - if (spvVersion.vulkan > 0) { + if (spvVersion.vulkanGlsl > 0) { preamble += "#define VULKAN "; - snprintf(numberBuf, numberBufSize, "%d", spvVersion.vulkan); + snprintf(numberBuf, numberBufSize, "%d", spvVersion.vulkanGlsl); preamble += numberBuf; preamble += "\n"; } @@ -317,7 +456,7 @@ void TParseVersions::getPreamble(std::string& preamble) // // When to use requireProfile(): // -// Use if only some profiles support a feature. However, if within a profile the feature +// Use if only some profiles support a feature. However, if within a profile the feature // is version or extension specific, follow this call with calls to profileRequires(). // // Operation: If the current profile is not one of the profileMask, @@ -332,7 +471,7 @@ void TParseVersions::requireProfile(const TSourceLoc& loc, int profileMask, cons // // Map from stage enum to externally readable text name. // -const char* StageName(EShLanguage stage) +const char* StageName(EShLanguage stage) { switch(stage) { case EShLangVertex: return "vertex"; @@ -357,7 +496,7 @@ const char* StageName(EShLanguage stage) // Operation: Will issue warnings/errors based on the current profile, version, and extension // behaviors. It only checks extensions when the current profile is one of the profileMask. // -// A minVersion of 0 means no version of the profileMask support this in core, +// A minVersion of 0 means no version of the profileMask support this in core, // the extension must be present. // @@ -395,7 +534,7 @@ void TParseVersions::profileRequires(const TSourceLoc& loc, int profileMask, int // // When to use requireStage() // -// If only some stages support a feature. +// If only some stages support a feature. // // Operation: If the current stage is not present, give an error message. // @@ -445,6 +584,11 @@ void TParseVersions::requireNotRemoved(const TSourceLoc& loc, int profileMask, i } } +void TParseVersions::unimplemented(const TSourceLoc& loc, const char* featureDesc) +{ + error(loc, "feature not yet implemented", featureDesc, ""); +} + // Returns true if at least one of the extensions in the extensions parameter is requested. Otherwise, returns false. // Warns appropriately if the requested behavior of an extension is "warn". bool TParseVersions::checkExtensionsRequested(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc) @@ -480,7 +624,8 @@ bool TParseVersions::checkExtensionsRequested(const TSourceLoc& loc, int numExte // void TParseVersions::requireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc) { - if (checkExtensionsRequested(loc, numExtensions, extensions, featureDesc)) return; + if (checkExtensionsRequested(loc, numExtensions, extensions, featureDesc)) + return; // If we get this far, give errors explaining what extensions are needed if (numExtensions == 1) @@ -498,7 +643,8 @@ void TParseVersions::requireExtensions(const TSourceLoc& loc, int numExtensions, // void TParseVersions::ppRequireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc) { - if (checkExtensionsRequested(loc, numExtensions, extensions, featureDesc)) return; + if (checkExtensionsRequested(loc, numExtensions, extensions, featureDesc)) + return; // If we get this far, give errors explaining what extensions are needed if (numExtensions == 1) @@ -536,7 +682,8 @@ bool TParseVersions::extensionTurnedOn(const char* const extension) bool TParseVersions::extensionsTurnedOn(int numExtensions, const char* const extensions[]) { for (int i = 0; i < numExtensions; ++i) { - if (extensionTurnedOn(extensions[i])) return true; + if (extensionTurnedOn(extensions[i])) + return true; } return false; } @@ -592,6 +739,25 @@ void TParseVersions::updateExtensionBehavior(int line, const char* extension, co updateExtensionBehavior(line, "GL_OES_shader_io_blocks", behaviorString); else if (strcmp(extension, "GL_GOOGLE_include_directive") == 0) updateExtensionBehavior(line, "GL_GOOGLE_cpp_style_line_directive", behaviorString); + // subgroup_* to subgroup_basic + else if (strcmp(extension, "GL_KHR_shader_subgroup_vote") == 0) + updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString); + else if (strcmp(extension, "GL_KHR_shader_subgroup_arithmetic") == 0) + updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString); + else if (strcmp(extension, "GL_KHR_shader_subgroup_ballot") == 0) + updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString); + else if (strcmp(extension, "GL_KHR_shader_subgroup_shuffle") == 0) + updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString); + else if (strcmp(extension, "GL_KHR_shader_subgroup_shuffle_relative") == 0) + updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString); + else if (strcmp(extension, "GL_KHR_shader_subgroup_clustered") == 0) + updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString); + else if (strcmp(extension, "GL_KHR_shader_subgroup_quad") == 0) + updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString); +#ifdef NV_EXTENSIONS + else if (strcmp(extension, "GL_NV_shader_subgroup_partitioned") == 0) + updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString); +#endif } void TParseVersions::updateExtensionBehavior(const char* extension, TExtensionBehavior behavior) @@ -637,7 +803,7 @@ void TParseVersions::updateExtensionBehavior(const char* extension, TExtensionBe // Call for any operation needing full GLSL integer data-type support. void TParseVersions::fullIntegerCheck(const TSourceLoc& loc, const char* op) { - profileRequires(loc, ENoProfile, 130, nullptr, op); + profileRequires(loc, ENoProfile, 130, nullptr, op); profileRequires(loc, EEsProfile, 300, nullptr, op); } @@ -649,11 +815,118 @@ void TParseVersions::doubleCheck(const TSourceLoc& loc, const char* op) profileRequires(loc, ECompatibilityProfile, 400, nullptr, op); } +// Call for any operation needing GLSL float16 data-type support. +void TParseVersions::float16Check(const TSourceLoc& loc, const char* op, bool builtIn) +{ + if (!builtIn) { +#if AMD_EXTENSIONS + const char* const extensions[3] = {E_GL_AMD_gpu_shader_half_float, + E_GL_KHX_shader_explicit_arithmetic_types, + E_GL_KHX_shader_explicit_arithmetic_types_float16}; + +#else + const char* const extensions[2] = {E_GL_KHX_shader_explicit_arithmetic_types, + E_GL_KHX_shader_explicit_arithmetic_types_float16}; +#endif + requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, "explicit types"); + requireProfile(loc, ECoreProfile | ECompatibilityProfile, op); + profileRequires(loc, ECoreProfile, 450, nullptr, op); + profileRequires(loc, ECompatibilityProfile, 450, nullptr, 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_KHX_shader_explicit_arithmetic_types, + E_GL_KHX_shader_explicit_arithmetic_types_float32}; + requireExtensions(loc, 2, extensions, "explicit types"); + requireProfile(loc, ECoreProfile | ECompatibilityProfile, op); + profileRequires(loc, ECoreProfile, 450, nullptr, op); + profileRequires(loc, ECompatibilityProfile, 450, nullptr, op); + } +} + +// Call for any operation needing GLSL float64 data-type support. +void TParseVersions::explicitFloat64Check(const TSourceLoc& loc, const char* op, bool builtIn) +{ + if (!builtIn) { + const char* const extensions[2] = {E_GL_KHX_shader_explicit_arithmetic_types, + E_GL_KHX_shader_explicit_arithmetic_types_float64}; + requireExtensions(loc, 2, extensions, "explicit types"); + requireProfile(loc, ECoreProfile | ECompatibilityProfile, op); + profileRequires(loc, ECoreProfile, 450, nullptr, op); + profileRequires(loc, ECompatibilityProfile, 450, nullptr, op); + } +} + +// Call for any operation needing GLSL explicit int8 data-type support. +void TParseVersions::explicitInt8Check(const TSourceLoc& loc, const char* op, bool builtIn) +{ + if (! builtIn) { + const char* const extensions[2] = {E_GL_KHX_shader_explicit_arithmetic_types, + E_GL_KHX_shader_explicit_arithmetic_types_int8}; + requireExtensions(loc, 2, extensions, "explicit types"); + requireProfile(loc, ECoreProfile | ECompatibilityProfile, op); + profileRequires(loc, ECoreProfile, 450, nullptr, op); + profileRequires(loc, ECompatibilityProfile, 450, nullptr, op); + } +} + +#ifdef AMD_EXTENSIONS +// Call for any operation needing GLSL float16 opaque-type support +void TParseVersions::float16OpaqueCheck(const TSourceLoc& loc, const char* op, bool builtIn) +{ + if (! builtIn) { + requireExtensions(loc, 1, &E_GL_AMD_gpu_shader_half_float_fetch, op); + requireProfile(loc, ECoreProfile | ECompatibilityProfile, op); + profileRequires(loc, ECoreProfile, 450, nullptr, op); + profileRequires(loc, ECompatibilityProfile, 450, nullptr, op); + } +} +#endif + +// Call for any operation needing GLSL explicit int16 data-type support. +void TParseVersions::explicitInt16Check(const TSourceLoc& loc, const char* op, bool builtIn) +{ + if (! builtIn) { +#if AMD_EXTENSIONS + const char* const extensions[3] = {E_GL_AMD_gpu_shader_int16, + E_GL_KHX_shader_explicit_arithmetic_types, + E_GL_KHX_shader_explicit_arithmetic_types_int16}; +#else + const char* const extensions[2] = {E_GL_KHX_shader_explicit_arithmetic_types, + E_GL_KHX_shader_explicit_arithmetic_types_int16}; +#endif + requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, "explicit types"); + requireProfile(loc, ECoreProfile | ECompatibilityProfile, op); + profileRequires(loc, ECoreProfile, 450, nullptr, op); + profileRequires(loc, ECompatibilityProfile, 450, nullptr, op); + } +} + +// Call for any operation needing GLSL explicit int32 data-type support. +void TParseVersions::explicitInt32Check(const TSourceLoc& loc, const char* op, bool builtIn) +{ + if (! builtIn) { + const char* const extensions[2] = {E_GL_KHX_shader_explicit_arithmetic_types, + E_GL_KHX_shader_explicit_arithmetic_types_int32}; + requireExtensions(loc, 2, extensions, "explicit types"); + requireProfile(loc, ECoreProfile | ECompatibilityProfile, op); + profileRequires(loc, ECoreProfile, 450, nullptr, op); + profileRequires(loc, ECompatibilityProfile, 450, nullptr, op); + } +} + // Call for any operation needing GLSL 64-bit integer data-type support. void TParseVersions::int64Check(const TSourceLoc& loc, const char* op, bool builtIn) { if (! builtIn) { - requireExtensions(loc, 1, &E_GL_ARB_gpu_shader_int64, "shader int64"); + const char* const extensions[3] = {E_GL_ARB_gpu_shader_int64, + E_GL_KHX_shader_explicit_arithmetic_types, + E_GL_KHX_shader_explicit_arithmetic_types_int64}; + requireExtensions(loc, 3, extensions, "shader int64"); requireProfile(loc, ECoreProfile | ECompatibilityProfile, op); profileRequires(loc, ECoreProfile, 450, nullptr, op); profileRequires(loc, ECompatibilityProfile, 450, nullptr, op); @@ -670,7 +943,7 @@ void TParseVersions::spvRemoved(const TSourceLoc& loc, const char* op) // Call for any operation removed because Vulkan SPIR-V is being generated. void TParseVersions::vulkanRemoved(const TSourceLoc& loc, const char* op) { - if (spvVersion.vulkan >= 100) + if (spvVersion.vulkan > 0) error(loc, "not allowed when using GLSL for Vulkan", op, ""); } diff --git a/Externals/glslang/glslang/MachineIndependent/Versions.h b/Externals/glslang/glslang/MachineIndependent/Versions.h old mode 100644 new mode 100755 index 19d101dbf1..b297d27b5c --- a/Externals/glslang/glslang/MachineIndependent/Versions.h +++ b/Externals/glslang/glslang/MachineIndependent/Versions.h @@ -1,12 +1,13 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2012-2013 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2012-2013 LunarG, Inc. +// Copyright (C) 2017 ARM Limited. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,18 +21,18 @@ // 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. +// 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 _VERSIONS_INCLUDED_ #define _VERSIONS_INCLUDED_ @@ -72,14 +73,19 @@ inline const char* ProfileName(EProfile profile) } // -// SPIR-V has versions for multiple things; tie them together. -// 0 means a target or rule set is not enabled. +// What source rules, validation rules, target language, etc. are needed +// desired for SPIR-V? +// +// 0 means a target or rule set is not enabled (ignore rules from that entity). +// Non-0 means to apply semantic rules arising from that version of its rule set. +// The union of all requested rule sets will be applied. // struct SpvVersion { - SpvVersion() : spv(0), vulkan(0), openGl(0) {} - unsigned int spv; // the version of the targeted SPIR-V, as defined by SPIR-V in word 1 of the SPIR-V binary header - int vulkan; // the version of semantics for Vulkan; e.g., for GLSL from KHR_vulkan_glsl "#define VULKAN" - int openGl; // the version of semantics for OpenGL; e.g., for GLSL from KHR_vulkan_glsl "#define GL_SPIRV" + SpvVersion() : spv(0), vulkanGlsl(0), vulkan(0), openGl(0) {} + unsigned int spv; // the version of SPIR-V to target, as defined by "word 1" of the SPIR-V binary header + int vulkanGlsl; // the version of GLSL semantics for Vulkan, from GL_KHR_vulkan_glsl, for "#define VULKAN XXX" + int vulkan; // the version of Vulkan, for which SPIR-V execution environment rules to use + int openGl; // the version of GLSL semantics for OpenGL, from GL_ARB_gl_spirv, for "#define GL_SPIRV XXX" }; // @@ -102,7 +108,9 @@ const char* const E_GL_OES_texture_3D = "GL_OES_texture_3D"; const char* const E_GL_OES_standard_derivatives = "GL_OES_standard_derivatives"; const char* const E_GL_EXT_frag_depth = "GL_EXT_frag_depth"; const char* const E_GL_OES_EGL_image_external = "GL_OES_EGL_image_external"; +const char* const E_GL_OES_EGL_image_external_essl3 = "GL_OES_EGL_image_external_essl3"; const char* const E_GL_EXT_shader_texture_lod = "GL_EXT_shader_texture_lod"; +const char* const E_GL_EXT_shadow_samplers = "GL_EXT_shadow_samplers"; const char* const E_GL_ARB_texture_rectangle = "GL_ARB_texture_rectangle"; const char* const E_GL_3DL_array_objects = "GL_3DL_array_objects"; @@ -127,14 +135,77 @@ const char* const E_GL_ARB_gpu_shader_int64 = "GL_ARB_gpu_shader_int const char* const E_GL_ARB_shader_ballot = "GL_ARB_shader_ballot"; const char* const E_GL_ARB_sparse_texture2 = "GL_ARB_sparse_texture2"; const char* const E_GL_ARB_sparse_texture_clamp = "GL_ARB_sparse_texture_clamp"; -//const char* const E_GL_ARB_cull_distance = "GL_ARB_cull_distance"; // present for 4.5, but need extension control over block members +const char* const E_GL_ARB_shader_stencil_export = "GL_ARB_shader_stencil_export"; +// const char* const E_GL_ARB_cull_distance = "GL_ARB_cull_distance"; // present for 4.5, but need extension control over block members +const char* const E_GL_ARB_post_depth_coverage = "GL_ARB_post_depth_coverage"; +const char* const E_GL_ARB_shader_viewport_layer_array = "GL_ARB_shader_viewport_layer_array"; + +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"; +const char* const E_GL_KHR_shader_subgroup_arithmetic = "GL_KHR_shader_subgroup_arithmetic"; +const char* const E_GL_KHR_shader_subgroup_ballot = "GL_KHR_shader_subgroup_ballot"; +const char* const E_GL_KHR_shader_subgroup_shuffle = "GL_KHR_shader_subgroup_shuffle"; +const char* const E_GL_KHR_shader_subgroup_shuffle_relative = "GL_KHR_shader_subgroup_shuffle_relative"; +const char* const E_GL_KHR_shader_subgroup_clustered = "GL_KHR_shader_subgroup_clustered"; +const char* const E_GL_KHR_shader_subgroup_quad = "GL_KHR_shader_subgroup_quad"; const char* const E_GL_EXT_shader_non_constant_global_initializers = "GL_EXT_shader_non_constant_global_initializers"; +const char* const E_GL_EXT_shader_image_load_formatted = "GL_EXT_shader_image_load_formatted"; + +// EXT extensions +const char* const E_GL_EXT_device_group = "GL_EXT_device_group"; +const char* const E_GL_EXT_multiview = "GL_EXT_multiview"; +const char* const E_GL_EXT_post_depth_coverage = "GL_EXT_post_depth_coverage"; +const char* const E_GL_EXT_control_flow_attributes = "GL_EXT_control_flow_attributes"; +const char* const E_GL_EXT_nonuniform_qualifier = "GL_EXT_nonuniform_qualifier"; + +// Arrays of extensions for the above viewportEXTs duplications + +const char* const post_depth_coverageEXTs[] = { E_GL_ARB_post_depth_coverage, E_GL_EXT_post_depth_coverage }; +const int Num_post_depth_coverageEXTs = sizeof(post_depth_coverageEXTs) / sizeof(post_depth_coverageEXTs[0]); + +// OVR extensions +const char* const E_GL_OVR_multiview = "GL_OVR_multiview"; +const char* const E_GL_OVR_multiview2 = "GL_OVR_multiview2"; + +const char* const OVR_multiview_EXTs[] = { E_GL_OVR_multiview, E_GL_OVR_multiview2 }; +const int Num_OVR_multiview_EXTs = sizeof(OVR_multiview_EXTs) / sizeof(OVR_multiview_EXTs[0]); // #line and #include const char* const E_GL_GOOGLE_cpp_style_line_directive = "GL_GOOGLE_cpp_style_line_directive"; const char* const E_GL_GOOGLE_include_directive = "GL_GOOGLE_include_directive"; +#ifdef AMD_EXTENSIONS +const char* const E_GL_AMD_shader_ballot = "GL_AMD_shader_ballot"; +const char* const E_GL_AMD_shader_trinary_minmax = "GL_AMD_shader_trinary_minmax"; +const char* const E_GL_AMD_shader_explicit_vertex_parameter = "GL_AMD_shader_explicit_vertex_parameter"; +const char* const E_GL_AMD_gcn_shader = "GL_AMD_gcn_shader"; +const char* const E_GL_AMD_gpu_shader_half_float = "GL_AMD_gpu_shader_half_float"; +const char* const E_GL_AMD_texture_gather_bias_lod = "GL_AMD_texture_gather_bias_lod"; +const char* const E_GL_AMD_gpu_shader_int16 = "GL_AMD_gpu_shader_int16"; +const char* const E_GL_AMD_shader_image_load_store_lod = "GL_AMD_shader_image_load_store_lod"; +const char* const E_GL_AMD_shader_fragment_mask = "GL_AMD_shader_fragment_mask"; +const char* const E_GL_AMD_gpu_shader_half_float_fetch = "GL_AMD_gpu_shader_half_float_fetch"; +#endif + +#ifdef NV_EXTENSIONS + +const char* const E_GL_NV_sample_mask_override_coverage = "GL_NV_sample_mask_override_coverage"; +const char* const E_SPV_NV_geometry_shader_passthrough = "GL_NV_geometry_shader_passthrough"; +const char* const E_GL_NV_viewport_array2 = "GL_NV_viewport_array2"; +const char* const E_GL_NV_stereo_view_rendering = "GL_NV_stereo_view_rendering"; +const char* const E_GL_NVX_multiview_per_view_attributes = "GL_NVX_multiview_per_view_attributes"; +const char* const E_GL_NV_shader_atomic_int64 = "GL_NV_shader_atomic_int64"; +const char* const E_GL_NV_conservative_raster_underestimation = "GL_NV_conservative_raster_underestimation"; +const char* const E_GL_NV_shader_noperspective_interpolation = "GL_NV_shader_noperspective_interpolation"; +const char* const E_GL_NV_shader_subgroup_partitioned = "GL_NV_shader_subgroup_partitioned"; + +// Arrays of extensions for the above viewportEXTs duplications + +const char* const viewportEXTs[] = { E_GL_ARB_shader_viewport_layer_array, E_GL_NV_viewport_array2 }; +const int Num_viewportEXTs = sizeof(viewportEXTs) / sizeof(viewportEXTs[0]); +#endif + // AEP const char* const E_GL_ANDROID_extension_pack_es31a = "GL_ANDROID_extension_pack_es31a"; const char* const E_GL_KHR_blend_equation_advanced = "GL_KHR_blend_equation_advanced"; @@ -163,6 +234,16 @@ const char* const E_GL_OES_tessellation_point_size = "GL_OES_tessel const char* const E_GL_OES_texture_buffer = "GL_OES_texture_buffer"; const char* const E_GL_OES_texture_cube_map_array = "GL_OES_texture_cube_map_array"; +// KHX +const char* const E_GL_KHX_shader_explicit_arithmetic_types = "GL_KHX_shader_explicit_arithmetic_types"; +const char* const E_GL_KHX_shader_explicit_arithmetic_types_int8 = "GL_KHX_shader_explicit_arithmetic_types_int8"; +const char* const E_GL_KHX_shader_explicit_arithmetic_types_int16 = "GL_KHX_shader_explicit_arithmetic_types_int16"; +const char* const E_GL_KHX_shader_explicit_arithmetic_types_int32 = "GL_KHX_shader_explicit_arithmetic_types_int32"; +const char* const E_GL_KHX_shader_explicit_arithmetic_types_int64 = "GL_KHX_shader_explicit_arithmetic_types_int64"; +const char* const E_GL_KHX_shader_explicit_arithmetic_types_float16 = "GL_KHX_shader_explicit_arithmetic_types_float16"; +const char* const E_GL_KHX_shader_explicit_arithmetic_types_float32 = "GL_KHX_shader_explicit_arithmetic_types_float32"; +const char* const E_GL_KHX_shader_explicit_arithmetic_types_float64 = "GL_KHX_shader_explicit_arithmetic_types_float64"; + // Arrays of extensions for the above AEP duplications const char* const AEP_geometry_shader[] = { E_GL_EXT_geometry_shader, E_GL_OES_geometry_shader }; diff --git a/Externals/glslang/glslang/MachineIndependent/attribute.cpp b/Externals/glslang/glslang/MachineIndependent/attribute.cpp new file mode 100644 index 0000000000..73b665d808 --- /dev/null +++ b/Externals/glslang/glslang/MachineIndependent/attribute.cpp @@ -0,0 +1,257 @@ +// +// Copyright (C) 2017 LunarG, Inc. +// Copyright (C) 2018 Google, 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 Google, Inc., 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. +// + +#include "attribute.h" +#include "../Include/intermediate.h" +#include "ParseHelper.h" + +namespace glslang { + +// extract integers out of attribute arguments stored in attribute aggregate +bool TAttributeArgs::getInt(int& value, int argNum) const +{ + const TConstUnion* intConst = getConstUnion(EbtInt, argNum); + + if (intConst == nullptr) + return false; + + value = intConst->getIConst(); + return true; +} + +// extract strings out of attribute arguments stored in attribute aggregate. +// convert to lower case if converToLower is true (for case-insensitive compare convenience) +bool TAttributeArgs::getString(TString& value, int argNum, bool convertToLower) const +{ + const TConstUnion* stringConst = getConstUnion(EbtString, argNum); + + if (stringConst == nullptr) + return false; + + value = *stringConst->getSConst(); + + // Convenience. + if (convertToLower) + std::transform(value.begin(), value.end(), value.begin(), ::tolower); + + return true; +} + +// How many arguments were supplied? +int TAttributeArgs::size() const +{ + return args == nullptr ? 0 : (int)args->getSequence().size(); +} + +// Helper to get attribute const union. Returns nullptr on failure. +const TConstUnion* TAttributeArgs::getConstUnion(TBasicType basicType, int argNum) const +{ + if (args == nullptr) + return nullptr; + + if (argNum >= (int)args->getSequence().size()) + return nullptr; + + const TConstUnion* constVal = &args->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0]; + if (constVal == nullptr || constVal->getType() != basicType) + return nullptr; + + return constVal; +} + +// Implementation of TParseContext parts of attributes +TAttributeType TParseContext::attributeFromName(const TString& name) const +{ + if (name == "branch" || name == "dont_flatten") + return EatBranch; + else if (name == "flatten") + return EatFlatten; + else if (name == "unroll") + return EatUnroll; + else if (name == "loop" || name == "dont_unroll") + return EatLoop; + else if (name == "dependency_infinite") + return EatDependencyInfinite; + else if (name == "dependency_length") + return EatDependencyLength; + else + return EatNone; +} + +// Make an initial leaf for the grammar from a no-argument attribute +TAttributes* TParseContext::makeAttributes(const TString& identifier) const +{ + TAttributes *attributes = nullptr; + attributes = NewPoolObject(attributes); + TAttributeArgs args = { attributeFromName(identifier), nullptr }; + attributes->push_back(args); + return attributes; +} + +// Make an initial leaf for the grammar from a one-argument attribute +TAttributes* TParseContext::makeAttributes(const TString& identifier, TIntermNode* node) const +{ + TAttributes *attributes = nullptr; + attributes = NewPoolObject(attributes); + + // for now, node is always a simple single expression, but other code expects + // a list, so make it so + TIntermAggregate* agg = intermediate.makeAggregate(node); + TAttributeArgs args = { attributeFromName(identifier), agg }; + attributes->push_back(args); + return attributes; +} + +// Merge two sets of attributes into a single set. +// The second argument is destructively consumed. +TAttributes* TParseContext::mergeAttributes(TAttributes* attr1, TAttributes* attr2) const +{ + attr1->splice(attr1->end(), *attr2); + return attr1; +} + +// +// Selection attributes +// +void TParseContext::handleSelectionAttributes(const TAttributes& attributes, TIntermNode* node) +{ + TIntermSelection* selection = node->getAsSelectionNode(); + if (selection == nullptr) + return; + + for (auto it = attributes.begin(); it != attributes.end(); ++it) { + if (it->size() > 0) { + warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", ""); + continue; + } + + switch (it->name) { + case EatFlatten: + selection->setFlatten(); + break; + case EatBranch: + selection->setDontFlatten(); + break; + default: + warn(node->getLoc(), "attribute does not apply to a selection", "", ""); + break; + } + } +} + +// +// Switch attributes +// +void TParseContext::handleSwitchAttributes(const TAttributes& attributes, TIntermNode* node) +{ + TIntermSwitch* selection = node->getAsSwitchNode(); + if (selection == nullptr) + return; + + for (auto it = attributes.begin(); it != attributes.end(); ++it) { + if (it->size() > 0) { + warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", ""); + continue; + } + + switch (it->name) { + case EatFlatten: + selection->setFlatten(); + break; + case EatBranch: + selection->setDontFlatten(); + break; + default: + warn(node->getLoc(), "attribute does not apply to a switch", "", ""); + break; + } + } +} + +// +// Loop attributes +// +void TParseContext::handleLoopAttributes(const TAttributes& attributes, TIntermNode* node) +{ + TIntermLoop* loop = node->getAsLoopNode(); + if (loop == nullptr) { + // the actual loop might be part of a sequence + TIntermAggregate* agg = node->getAsAggregate(); + if (agg == nullptr) + return; + for (auto it = agg->getSequence().begin(); it != agg->getSequence().end(); ++it) { + loop = (*it)->getAsLoopNode(); + if (loop != nullptr) + break; + } + if (loop == nullptr) + return; + } + + for (auto it = attributes.begin(); it != attributes.end(); ++it) { + if (it->name != EatDependencyLength && it->size() > 0) { + warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", ""); + continue; + } + + int value; + switch (it->name) { + case EatUnroll: + loop->setUnroll(); + break; + case EatLoop: + loop->setDontUnroll(); + break; + case EatDependencyInfinite: + loop->setLoopDependency(TIntermLoop::dependencyInfinite); + break; + case EatDependencyLength: + if (it->size() == 1 && it->getInt(value)) { + if (value <= 0) + error(node->getLoc(), "must be positive", "dependency_length", ""); + loop->setLoopDependency(value); + } else + warn(node->getLoc(), "expected a single integer argument", "dependency_length", ""); + break; + default: + warn(node->getLoc(), "attribute does not apply to a loop", "", ""); + break; + } + } +} + + +} // end namespace glslang diff --git a/Externals/glslang/glslang/MachineIndependent/attribute.h b/Externals/glslang/glslang/MachineIndependent/attribute.h new file mode 100644 index 0000000000..8d0c5bcafb --- /dev/null +++ b/Externals/glslang/glslang/MachineIndependent/attribute.h @@ -0,0 +1,102 @@ +// +// Copyright (C) 2017 LunarG, Inc. +// Copyright (C) 2018 Google, 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 _ATTRIBUTE_INCLUDED_ +#define _ATTRIBUTE_INCLUDED_ + +#include "../Include/Common.h" +#include "../Include/ConstantUnion.h" + +namespace glslang { + + enum TAttributeType { + EatNone, + EatAllow_uav_condition, + EatBranch, + EatCall, + EatDomain, + EatEarlyDepthStencil, + EatFastOpt, + EatFlatten, + EatForceCase, + EatInstance, + EatMaxTessFactor, + EatNumThreads, + EatMaxVertexCount, + EatOutputControlPoints, + EatOutputTopology, + EatPartitioning, + EatPatchConstantFunc, + EatPatchSize, + EatUnroll, + EatLoop, + EatBinding, + EatGlobalBinding, + EatLocation, + EatInputAttachment, + EatBuiltIn, + EatPushConstant, + EatConstantId, + EatDependencyInfinite, + EatDependencyLength + }; + + class TIntermAggregate; + + struct TAttributeArgs { + TAttributeType name; + const TIntermAggregate* args; + + // Obtain attribute as integer + // Return false if it cannot be obtained + bool getInt(int& value, int argNum = 0) const; + + // Obtain attribute as string, with optional to-lower transform + // Return false if it cannot be obtained + bool getString(TString& value, int argNum = 0, bool convertToLower = true) const; + + // How many arguments were provided to the attribute? + int size() const; + + protected: + const TConstUnion* getConstUnion(TBasicType basicType, int argNum) const; + }; + + typedef TList TAttributes; + +} // end namespace glslang + +#endif // _ATTRIBUTE_INCLUDED_ diff --git a/Externals/glslang/glslang/MachineIndependent/gl_types.h b/Externals/glslang/glslang/MachineIndependent/gl_types.h index 9e877d37dc..c9fee9ecce 100644 --- a/Externals/glslang/glslang/MachineIndependent/gl_types.h +++ b/Externals/glslang/glslang/MachineIndependent/gl_types.h @@ -21,6 +21,8 @@ ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ +#pragma once + #define GL_FLOAT 0x1406 #define GL_FLOAT_VEC2 0x8B50 #define GL_FLOAT_VEC3 0x8B51 @@ -76,6 +78,24 @@ #define GL_DOUBLE_MAT4x2 0x8F4D #define GL_DOUBLE_MAT4x3 0x8F4E +#ifdef AMD_EXTENSIONS +// Those constants are borrowed from extension NV_gpu_shader5 +#define GL_FLOAT16_NV 0x8FF8 +#define GL_FLOAT16_VEC2_NV 0x8FF9 +#define GL_FLOAT16_VEC3_NV 0x8FFA +#define GL_FLOAT16_VEC4_NV 0x8FFB + +#define GL_FLOAT16_MAT2_AMD 0x91C5 +#define GL_FLOAT16_MAT3_AMD 0x91C6 +#define GL_FLOAT16_MAT4_AMD 0x91C7 +#define GL_FLOAT16_MAT2x3_AMD 0x91C8 +#define GL_FLOAT16_MAT2x4_AMD 0x91C9 +#define GL_FLOAT16_MAT3x2_AMD 0x91CA +#define GL_FLOAT16_MAT3x4_AMD 0x91CB +#define GL_FLOAT16_MAT4x2_AMD 0x91CC +#define GL_FLOAT16_MAT4x3_AMD 0x91CD +#endif + #define GL_SAMPLER_1D 0x8B5D #define GL_SAMPLER_2D 0x8B5E #define GL_SAMPLER_3D 0x8B5F @@ -97,6 +117,40 @@ #define GL_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900C #define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D +#ifdef AMD_EXTENSIONS +#define GL_FLOAT16_SAMPLER_1D_AMD 0x91CE +#define GL_FLOAT16_SAMPLER_2D_AMD 0x91CF +#define GL_FLOAT16_SAMPLER_3D_AMD 0x91D0 +#define GL_FLOAT16_SAMPLER_CUBE_AMD 0x91D1 +#define GL_FLOAT16_SAMPLER_2D_RECT_AMD 0x91D2 +#define GL_FLOAT16_SAMPLER_1D_ARRAY_AMD 0x91D3 +#define GL_FLOAT16_SAMPLER_2D_ARRAY_AMD 0x91D4 +#define GL_FLOAT16_SAMPLER_CUBE_MAP_ARRAY_AMD 0x91D5 +#define GL_FLOAT16_SAMPLER_BUFFER_AMD 0x91D6 +#define GL_FLOAT16_SAMPLER_2D_MULTISAMPLE_AMD 0x91D7 +#define GL_FLOAT16_SAMPLER_2D_MULTISAMPLE_ARRAY_AMD 0x91D8 + +#define GL_FLOAT16_SAMPLER_1D_SHADOW_AMD 0x91D9 +#define GL_FLOAT16_SAMPLER_2D_SHADOW_AMD 0x91DA +#define GL_FLOAT16_SAMPLER_2D_RECT_SHADOW_AMD 0x91DB +#define GL_FLOAT16_SAMPLER_1D_ARRAY_SHADOW_AMD 0x91DC +#define GL_FLOAT16_SAMPLER_2D_ARRAY_SHADOW_AMD 0x91DD +#define GL_FLOAT16_SAMPLER_CUBE_SHADOW_AMD 0x91DE +#define GL_FLOAT16_SAMPLER_CUBE_MAP_ARRAY_SHADOW_AMD 0x91DF + +#define GL_FLOAT16_IMAGE_1D_AMD 0x91E0 +#define GL_FLOAT16_IMAGE_2D_AMD 0x91E1 +#define GL_FLOAT16_IMAGE_3D_AMD 0x91E2 +#define GL_FLOAT16_IMAGE_2D_RECT_AMD 0x91E3 +#define GL_FLOAT16_IMAGE_CUBE_AMD 0x91E4 +#define GL_FLOAT16_IMAGE_1D_ARRAY_AMD 0x91E5 +#define GL_FLOAT16_IMAGE_2D_ARRAY_AMD 0x91E6 +#define GL_FLOAT16_IMAGE_CUBE_MAP_ARRAY_AMD 0x91E7 +#define GL_FLOAT16_IMAGE_BUFFER_AMD 0x91E8 +#define GL_FLOAT16_IMAGE_2D_MULTISAMPLE_AMD 0x91E9 +#define GL_FLOAT16_IMAGE_2D_MULTISAMPLE_ARRAY_AMD 0x91EA +#endif + #define GL_INT_SAMPLER_1D 0x8DC9 #define GL_INT_SAMPLER_2D 0x8DCA #define GL_INT_SAMPLER_3D 0x8DCB diff --git a/Externals/glslang/glslang/MachineIndependent/glslang.y b/Externals/glslang/glslang/MachineIndependent/glslang.y index 2cd1cc6100..e65483a82e 100644 --- a/Externals/glslang/glslang/MachineIndependent/glslang.y +++ b/Externals/glslang/glslang/MachineIndependent/glslang.y @@ -1,12 +1,13 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2012-2013 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2012-2013 LunarG, Inc. +// Copyright (C) 2017 ARM Limited. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,18 +21,18 @@ // 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. +// 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. // /** @@ -58,11 +59,14 @@ Jutta Degener, 1995 #include "SymbolTable.h" #include "ParseHelper.h" #include "../Public/ShaderLang.h" +#include "attribute.h" using namespace glslang; %} +%define parse.error verbose + %union { struct { glslang::TSourceLoc loc; @@ -84,6 +88,7 @@ using namespace glslang; TIntermNode* intermNode; glslang::TIntermNodePair nodePair; glslang::TIntermTyped* intermTypedNode; + glslang::TAttributes* attributes; }; union { glslang::TPublicType type; @@ -119,14 +124,29 @@ extern int yylex(YYSTYPE*, TParseContext&); %expect 1 // One shift reduce conflict because of if | else %token ATTRIBUTE VARYING -%token CONST BOOL FLOAT DOUBLE INT UINT INT64_T UINT64_T +%token FLOAT16_T FLOAT FLOAT32_T DOUBLE FLOAT64_T +%token CONST BOOL INT UINT INT64_T UINT64_T INT32_T UINT32_T INT16_T UINT16_T INT8_T UINT8_T %token BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT SUBROUTINE -%token BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 I64VEC2 I64VEC3 I64VEC4 UVEC2 UVEC3 UVEC4 U64VEC2 U64VEC3 U64VEC4 VEC2 VEC3 VEC4 +%token BVEC2 BVEC3 BVEC4 +%token IVEC2 IVEC3 IVEC4 +%token UVEC2 UVEC3 UVEC4 +%token I64VEC2 I64VEC3 I64VEC4 +%token U64VEC2 U64VEC3 U64VEC4 +%token I32VEC2 I32VEC3 I32VEC4 +%token U32VEC2 U32VEC3 U32VEC4 +%token I16VEC2 I16VEC3 I16VEC4 +%token U16VEC2 U16VEC3 U16VEC4 +%token I8VEC2 I8VEC3 I8VEC4 +%token U8VEC2 U8VEC3 U8VEC4 +%token VEC2 VEC3 VEC4 %token MAT2 MAT3 MAT4 CENTROID IN OUT INOUT -%token UNIFORM PATCH SAMPLE BUFFER SHARED +%token UNIFORM PATCH SAMPLE BUFFER SHARED NONUNIFORM %token COHERENT VOLATILE RESTRICT READONLY WRITEONLY %token DVEC2 DVEC3 DVEC4 DMAT2 DMAT3 DMAT4 -%token NOPERSPECTIVE FLAT SMOOTH LAYOUT +%token F16VEC2 F16VEC3 F16VEC4 F16MAT2 F16MAT3 F16MAT4 +%token F32VEC2 F32VEC3 F32VEC4 F32MAT2 F32MAT3 F32MAT4 +%token F64VEC2 F64VEC3 F64VEC4 F64MAT2 F64MAT3 F64MAT4 +%token NOPERSPECTIVE FLAT SMOOTH LAYOUT __EXPLICITINTERPAMD %token MAT2X2 MAT2X3 MAT2X4 %token MAT3X2 MAT3X3 MAT3X4 @@ -134,6 +154,15 @@ extern int yylex(YYSTYPE*, TParseContext&); %token DMAT2X2 DMAT2X3 DMAT2X4 %token DMAT3X2 DMAT3X3 DMAT3X4 %token DMAT4X2 DMAT4X3 DMAT4X4 +%token F16MAT2X2 F16MAT2X3 F16MAT2X4 +%token F16MAT3X2 F16MAT3X3 F16MAT3X4 +%token F16MAT4X2 F16MAT4X3 F16MAT4X4 +%token F32MAT2X2 F32MAT2X3 F32MAT2X4 +%token F32MAT3X2 F32MAT3X3 F32MAT3X4 +%token F32MAT4X2 F32MAT4X3 F32MAT4X4 +%token F64MAT2X2 F64MAT2X3 F64MAT2X4 +%token F64MAT3X2 F64MAT3X3 F64MAT3X4 +%token F64MAT4X2 F64MAT4X3 F64MAT4X4 %token ATOMIC_UINT // combined image/sampler @@ -150,6 +179,12 @@ extern int yylex(YYSTYPE*, TParseContext&); %token SAMPLER2DMSARRAY ISAMPLER2DMSARRAY USAMPLER2DMSARRAY %token SAMPLEREXTERNALOES +%token F16SAMPLER1D F16SAMPLER2D F16SAMPLER3D F16SAMPLER2DRECT F16SAMPLERCUBE +%token F16SAMPLER1DARRAY F16SAMPLER2DARRAY F16SAMPLERCUBEARRAY +%token F16SAMPLERBUFFER F16SAMPLER2DMS F16SAMPLER2DMSARRAY +%token F16SAMPLER1DSHADOW F16SAMPLER2DSHADOW F16SAMPLER1DARRAYSHADOW F16SAMPLER2DARRAYSHADOW +%token F16SAMPLER2DRECTSHADOW F16SAMPLERCUBESHADOW F16SAMPLERCUBEARRAYSHADOW + // pure sampler %token SAMPLER SAMPLERSHADOW @@ -165,8 +200,13 @@ extern int yylex(YYSTYPE*, TParseContext&); %token TEXTURE2DMS ITEXTURE2DMS UTEXTURE2DMS %token TEXTURE2DMSARRAY ITEXTURE2DMSARRAY UTEXTURE2DMSARRAY +%token F16TEXTURE1D F16TEXTURE2D F16TEXTURE3D F16TEXTURE2DRECT F16TEXTURECUBE +%token F16TEXTURE1DARRAY F16TEXTURE2DARRAY F16TEXTURECUBEARRAY +%token F16TEXTUREBUFFER F16TEXTURE2DMS F16TEXTURE2DMSARRAY + // input attachments %token SUBPASSINPUT SUBPASSINPUTMS ISUBPASSINPUT ISUBPASSINPUTMS USUBPASSINPUT USUBPASSINPUTMS +%token F16SUBPASSINPUT F16SUBPASSINPUTMS %token IMAGE1D IIMAGE1D UIMAGE1D IMAGE2D IIMAGE2D %token UIMAGE2D IMAGE3D IIMAGE3D UIMAGE3D @@ -179,10 +219,14 @@ extern int yylex(YYSTYPE*, TParseContext&); %token IMAGE2DMS IIMAGE2DMS UIMAGE2DMS %token IMAGE2DMSARRAY IIMAGE2DMSARRAY UIMAGE2DMSARRAY +%token F16IMAGE1D F16IMAGE2D F16IMAGE3D F16IMAGE2DRECT +%token F16IMAGECUBE F16IMAGE1DARRAY F16IMAGE2DARRAY F16IMAGECUBEARRAY +%token F16IMAGEBUFFER F16IMAGE2DMS F16IMAGE2DMSARRAY + %token STRUCT VOID WHILE %token IDENTIFIER TYPE_NAME -%token FLOATCONSTANT DOUBLECONSTANT INTCONSTANT UINTCONSTANT INT64CONSTANT UINT64CONSTANT BOOLCONSTANT +%token FLOATCONSTANT DOUBLECONSTANT INT16CONSTANT UINT16CONSTANT INT32CONSTANT UINT32CONSTANT INTCONSTANT UINTCONSTANT INT64CONSTANT UINT64CONSTANT BOOLCONSTANT FLOAT16CONSTANT %token LEFT_OP RIGHT_OP %token INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP %token AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN @@ -211,12 +255,12 @@ extern int yylex(YYSTYPE*, TParseContext&); %type translation_unit function_definition %type statement simple_statement %type statement_list switch_statement_list compound_statement -%type declaration_statement selection_statement expression_statement -%type switch_statement case_label +%type declaration_statement selection_statement selection_statement_nonattributed expression_statement +%type switch_statement switch_statement_nonattributed case_label %type declaration external_declaration %type for_init_statement compound_statement_no_new_scope %type selection_rest_statement for_rest_statement -%type iteration_statement jump_statement statement_no_new_scope statement_scoped +%type iteration_statement iteration_statement_nonattributed jump_statement statement_no_new_scope statement_scoped %type single_declaration init_declarator_list %type parameter_declaration parameter_declarator parameter_type_specifier @@ -224,6 +268,7 @@ extern int yylex(YYSTYPE*, TParseContext&); %type array_specifier %type precise_qualifier invariant_qualifier interpolation_qualifier storage_qualifier precision_qualifier %type layout_qualifier layout_qualifier_id_list layout_qualifier_id +%type non_uniform_qualifier %type type_qualifier fully_specified_type type_specifier %type single_type_qualifier @@ -239,6 +284,8 @@ extern int yylex(YYSTYPE*, TParseContext&); %type identifier_list +%type attribute attribute_list single_attribute + %start translation_unit %% @@ -252,6 +299,14 @@ primary_expression : variable_identifier { $$ = $1; } + | INT32CONSTANT { + parseContext.explicitInt32Check($1.loc, "32-bit signed literal"); + $$ = parseContext.intermediate.addConstantUnion($1.i, $1.loc, true); + } + | UINT32CONSTANT { + parseContext.explicitInt32Check($1.loc, "32-bit signed literal"); + $$ = parseContext.intermediate.addConstantUnion($1.u, $1.loc, true); + } | INTCONSTANT { $$ = parseContext.intermediate.addConstantUnion($1.i, $1.loc, true); } @@ -267,6 +322,14 @@ primary_expression parseContext.int64Check($1.loc, "64-bit unsigned integer literal"); $$ = parseContext.intermediate.addConstantUnion($1.u64, $1.loc, true); } + | INT16CONSTANT { + parseContext.explicitInt16Check($1.loc, "16-bit integer literal"); + $$ = parseContext.intermediate.addConstantUnion((short)$1.i, $1.loc, true); + } + | UINT16CONSTANT { + parseContext.explicitInt16Check($1.loc, "16-bit unsigned integer literal"); + $$ = parseContext.intermediate.addConstantUnion((unsigned short)$1.u, $1.loc, true); + } | FLOATCONSTANT { $$ = parseContext.intermediate.addConstantUnion($1.d, EbtFloat, $1.loc, true); } @@ -274,6 +337,10 @@ primary_expression parseContext.doubleCheck($1.loc, "double literal"); $$ = parseContext.intermediate.addConstantUnion($1.d, EbtDouble, $1.loc, true); } + | FLOAT16CONSTANT { + parseContext.float16Check($1.loc, "half float literal"); + $$ = parseContext.intermediate.addConstantUnion($1.d, EbtFloat16, $1.loc, true); + } | BOOLCONSTANT { $$ = parseContext.intermediate.addConstantUnion($1.b, $1.loc, true); } @@ -407,6 +474,11 @@ function_identifier $$.function = new TFunction(&empty, TType(EbtVoid), EOpNull); } } + | non_uniform_qualifier { + // Constructor + $$.intermNode = 0; + $$.function = parseContext.handleConstructorCall($1.loc, $1); + } ; unary_expression @@ -691,6 +763,7 @@ expression $$ = $1; } | expression COMMA assignment_expression { + parseContext.samplerConstructorLocationCheck($2.loc, ",", $3); $$ = parseContext.intermediate.addComma($1, $3, $2.loc); if ($$ == 0) { parseContext.binaryOpError($2.loc, ",", $1->getCompleteString(), $3->getCompleteString()); @@ -834,6 +907,11 @@ function_header // Add the function as a prototype after parsing it (we do not support recursion) TFunction *function; TType type($1); + + // Potentially rename shader entry point function. No-op most of the time. + parseContext.renameShaderFunction($2.string); + + // Make the function function = new TFunction($2.string, type); $$ = function; } @@ -862,14 +940,16 @@ parameter_declarator parseContext.profileRequires($1.loc, EEsProfile, 300, 0, "arrayed type"); parseContext.arraySizeRequiredCheck($1.loc, *$1.arraySizes); } - parseContext.arrayDimCheck($2.loc, $1.arraySizes, $3.arraySizes); + TType* type = new TType($1); + type->transferArraySizes($3.arraySizes); + type->copyArrayInnerSizes($1.arraySizes); + parseContext.arrayOfArrayVersionCheck($2.loc, type->getArraySizes()); parseContext.arraySizeRequiredCheck($3.loc, *$3.arraySizes); parseContext.reservedErrorCheck($2.loc, *$2.string); - $1.arraySizes = $3.arraySizes; + TParameter param = { $2.string, type }; - TParameter param = { $2.string, new TType($1)}; $$.loc = $2.loc; $$.param = param; } @@ -894,7 +974,7 @@ parameter_declaration $$ = $1; parseContext.parameterTypeCheck($1.loc, EvqIn, *$1.param.type); - parseContext.paramCheckFix($1.loc, EvqTemporary, *$$.param.type); + parseContext.paramCheckFixStorage($1.loc, EvqTemporary, *$$.param.type); parseContext.precisionQualifierCheck($$.loc, $$.param.type->getBasicType(), $$.param.type->getQualifier()); } // @@ -914,7 +994,7 @@ parameter_declaration $$ = $1; parseContext.parameterTypeCheck($1.loc, EvqIn, *$1.param.type); - parseContext.paramCheckFix($1.loc, EvqTemporary, *$$.param.type); + parseContext.paramCheckFixStorage($1.loc, EvqTemporary, *$$.param.type); parseContext.precisionQualifierCheck($$.loc, $$.param.type->getBasicType(), $$.param.type->getQualifier()); } ; @@ -1003,7 +1083,7 @@ fully_specified_type } if ($2.arraySizes && parseContext.arrayQualifierError($2.loc, $1.qualifier)) - $2.arraySizes = 0; + $2.arraySizes = nullptr; parseContext.checkNoShaderLayouts($2.loc, $1.shaderQualifiers); $2.shaderQualifiers.merge($1.shaderQualifiers); @@ -1045,11 +1125,24 @@ interpolation_qualifier } | NOPERSPECTIVE { parseContext.globalCheck($1.loc, "noperspective"); +#ifdef NV_EXTENSIONS + parseContext.profileRequires($1.loc, EEsProfile, 0, E_GL_NV_shader_noperspective_interpolation, "noperspective"); +#else parseContext.requireProfile($1.loc, ~EEsProfile, "noperspective"); +#endif parseContext.profileRequires($1.loc, ENoProfile, 130, 0, "noperspective"); $$.init($1.loc); $$.qualifier.nopersp = true; } + | __EXPLICITINTERPAMD { +#ifdef AMD_EXTENSIONS + parseContext.globalCheck($1.loc, "__explicitInterpAMD"); + parseContext.profileRequires($1.loc, ECoreProfile, 450, E_GL_AMD_shader_explicit_vertex_parameter, "explicit interpolation"); + parseContext.profileRequires($1.loc, ECompatibilityProfile, 450, E_GL_AMD_shader_explicit_vertex_parameter, "explicit interpolation"); + $$.init($1.loc); + $$.qualifier.explicitInterp = true; +#endif + } ; layout_qualifier @@ -1115,6 +1208,7 @@ single_type_qualifier $$ = $1; } | precision_qualifier { + parseContext.checkPrecisionQualifier($1.loc, $1.qualifier.precision); $$ = $1; } | interpolation_qualifier { @@ -1129,6 +1223,9 @@ single_type_qualifier // allow inheritance of storage qualifier from block declaration $$ = $1; } + | non_uniform_qualifier { + $$ = $1; + } ; storage_qualifier @@ -1208,6 +1305,7 @@ storage_qualifier $$.qualifier.storage = EvqBuffer; } | SHARED { + parseContext.globalCheck($1.loc, "shared"); parseContext.profileRequires($1.loc, ECoreProfile | ECompatibilityProfile, 430, E_GL_ARB_compute_shader, "shared"); parseContext.profileRequires($1.loc, EEsProfile, 310, 0, "shared"); parseContext.requireStage($1.loc, EShLangCompute, "shared"); @@ -1237,25 +1335,32 @@ storage_qualifier | SUBROUTINE { parseContext.spvRemoved($1.loc, "subroutine"); parseContext.globalCheck($1.loc, "subroutine"); + parseContext.unimplemented($1.loc, "subroutine"); $$.init($1.loc); - $$.qualifier.storage = EvqUniform; } | SUBROUTINE LEFT_PAREN type_name_list RIGHT_PAREN { parseContext.spvRemoved($1.loc, "subroutine"); parseContext.globalCheck($1.loc, "subroutine"); + parseContext.unimplemented($1.loc, "subroutine"); $$.init($1.loc); - $$.qualifier.storage = EvqUniform; - // TODO: 4.0 semantics: subroutines - // 1) make sure each identifier is a type declared earlier with SUBROUTINE - // 2) save all of the identifiers for future comparison with the declared function + } + ; + +non_uniform_qualifier + : NONUNIFORM { + $$.init($1.loc); + $$.qualifier.nonUniform = true; } ; type_name_list - : TYPE_NAME { - // TODO: 4.0 functionality: subroutine type to list + : IDENTIFIER { + // TODO } - | type_name_list COMMA TYPE_NAME { + | type_name_list COMMA IDENTIFIER { + // TODO: 4.0 semantics: subroutines + // 1) make sure each identifier is a type declared earlier with SUBROUTINE + // 2) save all of the identifiers for future comparison with the declared function } ; @@ -1265,7 +1370,7 @@ type_specifier $$.qualifier.precision = parseContext.getDefaultPrecision($$); } | type_specifier_nonarray array_specifier { - parseContext.arrayDimCheck($2.loc, $2.arraySizes, 0); + parseContext.arrayOfArrayVersionCheck($2.loc, $2.arraySizes); $$ = $1; $$.qualifier.precision = parseContext.getDefaultPrecision($$); $$.arraySizes = $2.arraySizes; @@ -1313,6 +1418,21 @@ type_specifier_nonarray $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; } + | FLOAT16_T { + parseContext.float16Check($1.loc, "float16_t", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat16; + } + | FLOAT32_T { + parseContext.explicitFloat32Check($1.loc, "float32_t", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat; + } + | FLOAT64_T { + parseContext.explicitFloat64Check($1.loc, "float64_t", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtDouble; + } | INT { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtInt; @@ -1322,6 +1442,36 @@ type_specifier_nonarray $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtUint; } + | INT8_T { + parseContext.explicitInt8Check($1.loc, "8-bit signed integer", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtInt8; + } + | UINT8_T { + parseContext.explicitInt8Check($1.loc, "8-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtUint8; + } + | INT16_T { + parseContext.explicitInt16Check($1.loc, "16-bit signed integer", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtInt16; + } + | UINT16_T { + parseContext.explicitInt16Check($1.loc, "16-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtUint16; + } + | INT32_T { + parseContext.explicitInt32Check($1.loc, "32-bit signed integer", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtInt; + } + | UINT32_T { + parseContext.explicitInt32Check($1.loc, "32-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtUint; + } | INT64_T { parseContext.int64Check($1.loc, "64-bit integer", parseContext.symbolTable.atBuiltInLevel()); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); @@ -1369,6 +1519,60 @@ type_specifier_nonarray $$.basicType = EbtDouble; $$.setVector(4); } + | F16VEC2 { + parseContext.float16Check($1.loc, "half float vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat16; + $$.setVector(2); + } + | F16VEC3 { + parseContext.float16Check($1.loc, "half float vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat16; + $$.setVector(3); + } + | F16VEC4 { + parseContext.float16Check($1.loc, "half float vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat16; + $$.setVector(4); + } + | F32VEC2 { + parseContext.explicitFloat32Check($1.loc, "float32_t vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat; + $$.setVector(2); + } + | F32VEC3 { + parseContext.explicitFloat32Check($1.loc, "float32_t vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat; + $$.setVector(3); + } + | F32VEC4 { + parseContext.explicitFloat32Check($1.loc, "float32_t vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat; + $$.setVector(4); + } + | F64VEC2 { + parseContext.explicitFloat64Check($1.loc, "float64_t vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtDouble; + $$.setVector(2); + } + | F64VEC3 { + parseContext.explicitFloat64Check($1.loc, "float64_t vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtDouble; + $$.setVector(3); + } + | F64VEC4 { + parseContext.explicitFloat64Check($1.loc, "float64_t vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtDouble; + $$.setVector(4); + } | BVEC2 { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtBool; @@ -1399,6 +1603,60 @@ type_specifier_nonarray $$.basicType = EbtInt; $$.setVector(4); } + | I8VEC2 { + parseContext.explicitInt8Check($1.loc, "8-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtInt8; + $$.setVector(2); + } + | I8VEC3 { + parseContext.explicitInt8Check($1.loc, "8-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtInt8; + $$.setVector(3); + } + | I8VEC4 { + parseContext.explicitInt8Check($1.loc, "8-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtInt8; + $$.setVector(4); + } + | I16VEC2 { + parseContext.explicitInt16Check($1.loc, "16-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtInt16; + $$.setVector(2); + } + | I16VEC3 { + parseContext.explicitInt16Check($1.loc, "16-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtInt16; + $$.setVector(3); + } + | I16VEC4 { + parseContext.explicitInt16Check($1.loc, "16-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtInt16; + $$.setVector(4); + } + | I32VEC2 { + parseContext.explicitInt32Check($1.loc, "32-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtInt; + $$.setVector(2); + } + | I32VEC3 { + parseContext.explicitInt32Check($1.loc, "32-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtInt; + $$.setVector(3); + } + | I32VEC4 { + parseContext.explicitInt32Check($1.loc, "32-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtInt; + $$.setVector(4); + } | I64VEC2 { parseContext.int64Check($1.loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel()); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); @@ -1435,6 +1693,60 @@ type_specifier_nonarray $$.basicType = EbtUint; $$.setVector(4); } + | U8VEC2 { + parseContext.explicitInt8Check($1.loc, "8-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtUint8; + $$.setVector(2); + } + | U8VEC3 { + parseContext.explicitInt8Check($1.loc, "8-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtInt8; + $$.setVector(3); + } + | U8VEC4 { + parseContext.explicitInt8Check($1.loc, "8-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtUint8; + $$.setVector(4); + } + | U16VEC2 { + parseContext.explicitInt16Check($1.loc, "16-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtUint16; + $$.setVector(2); + } + | U16VEC3 { + parseContext.explicitInt16Check($1.loc, "16-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtUint16; + $$.setVector(3); + } + | U16VEC4 { + parseContext.explicitInt16Check($1.loc, "16-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtUint16; + $$.setVector(4); + } + | U32VEC2 { + parseContext.explicitInt32Check($1.loc, "32-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtUint; + $$.setVector(2); + } + | U32VEC3 { + parseContext.explicitInt32Check($1.loc, "32-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtUint; + $$.setVector(3); + } + | U32VEC4 { + parseContext.explicitInt32Check($1.loc, "32-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtUint; + $$.setVector(4); + } | U64VEC2 { parseContext.int64Check($1.loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); @@ -1585,6 +1897,222 @@ type_specifier_nonarray $$.basicType = EbtDouble; $$.setMatrix(4, 4); } + | F16MAT2 { + parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat16; + $$.setMatrix(2, 2); + } + | F16MAT3 { + parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat16; + $$.setMatrix(3, 3); + } + | F16MAT4 { + parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat16; + $$.setMatrix(4, 4); + } + | F16MAT2X2 { + parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat16; + $$.setMatrix(2, 2); + } + | F16MAT2X3 { + parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat16; + $$.setMatrix(2, 3); + } + | F16MAT2X4 { + parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat16; + $$.setMatrix(2, 4); + } + | F16MAT3X2 { + parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat16; + $$.setMatrix(3, 2); + } + | F16MAT3X3 { + parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat16; + $$.setMatrix(3, 3); + } + | F16MAT3X4 { + parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat16; + $$.setMatrix(3, 4); + } + | F16MAT4X2 { + parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat16; + $$.setMatrix(4, 2); + } + | F16MAT4X3 { + parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat16; + $$.setMatrix(4, 3); + } + | F16MAT4X4 { + parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat16; + $$.setMatrix(4, 4); + } + | F32MAT2 { + parseContext.explicitFloat32Check($1.loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat; + $$.setMatrix(2, 2); + } + | F32MAT3 { + parseContext.explicitFloat32Check($1.loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat; + $$.setMatrix(3, 3); + } + | F32MAT4 { + parseContext.explicitFloat32Check($1.loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat; + $$.setMatrix(4, 4); + } + | F32MAT2X2 { + parseContext.explicitFloat32Check($1.loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat; + $$.setMatrix(2, 2); + } + | F32MAT2X3 { + parseContext.explicitFloat32Check($1.loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat; + $$.setMatrix(2, 3); + } + | F32MAT2X4 { + parseContext.explicitFloat32Check($1.loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat; + $$.setMatrix(2, 4); + } + | F32MAT3X2 { + parseContext.explicitFloat32Check($1.loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat; + $$.setMatrix(3, 2); + } + | F32MAT3X3 { + parseContext.explicitFloat32Check($1.loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat; + $$.setMatrix(3, 3); + } + | F32MAT3X4 { + parseContext.explicitFloat32Check($1.loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat; + $$.setMatrix(3, 4); + } + | F32MAT4X2 { + parseContext.explicitFloat32Check($1.loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat; + $$.setMatrix(4, 2); + } + | F32MAT4X3 { + parseContext.explicitFloat32Check($1.loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat; + $$.setMatrix(4, 3); + } + | F32MAT4X4 { + parseContext.explicitFloat32Check($1.loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtFloat; + $$.setMatrix(4, 4); + } + | F64MAT2 { + parseContext.explicitFloat64Check($1.loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtDouble; + $$.setMatrix(2, 2); + } + | F64MAT3 { + parseContext.explicitFloat64Check($1.loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtDouble; + $$.setMatrix(3, 3); + } + | F64MAT4 { + parseContext.explicitFloat64Check($1.loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtDouble; + $$.setMatrix(4, 4); + } + | F64MAT2X2 { + parseContext.explicitFloat64Check($1.loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtDouble; + $$.setMatrix(2, 2); + } + | F64MAT2X3 { + parseContext.explicitFloat64Check($1.loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtDouble; + $$.setMatrix(2, 3); + } + | F64MAT2X4 { + parseContext.explicitFloat64Check($1.loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtDouble; + $$.setMatrix(2, 4); + } + | F64MAT3X2 { + parseContext.explicitFloat64Check($1.loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtDouble; + $$.setMatrix(3, 2); + } + | F64MAT3X3 { + parseContext.explicitFloat64Check($1.loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtDouble; + $$.setMatrix(3, 3); + } + | F64MAT3X4 { + parseContext.explicitFloat64Check($1.loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtDouble; + $$.setMatrix(3, 4); + } + | F64MAT4X2 { + parseContext.explicitFloat64Check($1.loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtDouble; + $$.setMatrix(4, 2); + } + | F64MAT4X3 { + parseContext.explicitFloat64Check($1.loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtDouble; + $$.setMatrix(4, 3); + } + | F64MAT4X4 { + parseContext.explicitFloat64Check($1.loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtDouble; + $$.setMatrix(4, 4); + } | ATOMIC_UINT { parseContext.vulkanRemoved($1.loc, "atomic counter types"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); @@ -1655,6 +2183,110 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.set(EbtFloat, EsdCube, true, true); } + | F16SAMPLER1D { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.set(EbtFloat16, Esd1D); +#endif + } + | F16SAMPLER2D { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.set(EbtFloat16, Esd2D); +#endif + } + | F16SAMPLER3D { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.set(EbtFloat16, Esd3D); +#endif + } + | F16SAMPLERCUBE { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.set(EbtFloat16, EsdCube); +#endif + } + | F16SAMPLER1DSHADOW { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.set(EbtFloat16, Esd1D, false, true); +#endif + } + | F16SAMPLER2DSHADOW { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.set(EbtFloat16, Esd2D, false, true); +#endif + } + | F16SAMPLERCUBESHADOW { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.set(EbtFloat16, EsdCube, false, true); +#endif + } + | F16SAMPLER1DARRAY { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.set(EbtFloat16, Esd1D, true); +#endif + } + | F16SAMPLER2DARRAY { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.set(EbtFloat16, Esd2D, true); +#endif + } + | F16SAMPLER1DARRAYSHADOW { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.set(EbtFloat16, Esd1D, true, true); +#endif + } + | F16SAMPLER2DARRAYSHADOW { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.set(EbtFloat16, Esd2D, true, true); +#endif + } + | F16SAMPLERCUBEARRAY { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.set(EbtFloat16, EsdCube, true); +#endif + } + | F16SAMPLERCUBEARRAYSHADOW { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.set(EbtFloat16, EsdCube, true, true); +#endif + } | ISAMPLER1D { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -1735,6 +2367,22 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.set(EbtFloat, EsdRect, false, true); } + | F16SAMPLER2DRECT { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.set(EbtFloat16, EsdRect); +#endif + } + | F16SAMPLER2DRECTSHADOW { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.set(EbtFloat16, EsdRect, false, true); +#endif + } | ISAMPLER2DRECT { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -1750,6 +2398,14 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.set(EbtFloat, EsdBuffer); } + | F16SAMPLERBUFFER { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.set(EbtFloat16, EsdBuffer); +#endif + } | ISAMPLERBUFFER { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -1765,6 +2421,14 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.set(EbtFloat, Esd2D, false, false, true); } + | F16SAMPLER2DMS { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.set(EbtFloat16, Esd2D, false, false, true); +#endif + } | ISAMPLER2DMS { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -1780,6 +2444,14 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.set(EbtFloat, Esd2D, true, false, true); } + | F16SAMPLER2DMSARRAY { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.set(EbtFloat16, Esd2D, true, false, true); +#endif + } | ISAMPLER2DMSARRAY { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -1805,36 +2477,92 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.setTexture(EbtFloat, Esd1D); } + | F16TEXTURE1D { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setTexture(EbtFloat16, Esd1D); +#endif + } | TEXTURE2D { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; $$.sampler.setTexture(EbtFloat, Esd2D); } + | F16TEXTURE2D { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setTexture(EbtFloat16, Esd2D); +#endif + } | TEXTURE3D { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; $$.sampler.setTexture(EbtFloat, Esd3D); } + | F16TEXTURE3D { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setTexture(EbtFloat16, Esd3D); +#endif + } | TEXTURECUBE { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; $$.sampler.setTexture(EbtFloat, EsdCube); } + | F16TEXTURECUBE { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setTexture(EbtFloat16, EsdCube); +#endif + } | TEXTURE1DARRAY { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; $$.sampler.setTexture(EbtFloat, Esd1D, true); } + | F16TEXTURE1DARRAY { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setTexture(EbtFloat16, Esd1D, true); +#endif + } | TEXTURE2DARRAY { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; $$.sampler.setTexture(EbtFloat, Esd2D, true); } + | F16TEXTURE2DARRAY { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setTexture(EbtFloat16, Esd2D, true); +#endif + } | TEXTURECUBEARRAY { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; $$.sampler.setTexture(EbtFloat, EsdCube, true); } + | F16TEXTURECUBEARRAY { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setTexture(EbtFloat16, EsdCube, true); +#endif + } | ITEXTURE1D { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -1910,6 +2638,14 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.setTexture(EbtFloat, EsdRect); } + | F16TEXTURE2DRECT { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setTexture(EbtFloat16, EsdRect); +#endif + } | ITEXTURE2DRECT { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -1925,6 +2661,14 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.setTexture(EbtFloat, EsdBuffer); } + | F16TEXTUREBUFFER { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setTexture(EbtFloat16, EsdBuffer); +#endif + } | ITEXTUREBUFFER { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -1940,6 +2684,14 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.setTexture(EbtFloat, Esd2D, false, false, true); } + | F16TEXTURE2DMS { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setTexture(EbtFloat16, Esd2D, false, false, true); +#endif + } | ITEXTURE2DMS { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -1955,6 +2707,14 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.setTexture(EbtFloat, Esd2D, true, false, true); } + | F16TEXTURE2DMSARRAY { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setTexture(EbtFloat16, Esd2D, true, false, true); +#endif + } | ITEXTURE2DMSARRAY { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -1970,6 +2730,14 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.setImage(EbtFloat, Esd1D); } + | F16IMAGE1D { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtFloat16, Esd1D); +#endif + } | IIMAGE1D { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -1985,6 +2753,14 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.setImage(EbtFloat, Esd2D); } + | F16IMAGE2D { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtFloat16, Esd2D); +#endif + } | IIMAGE2D { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -2000,6 +2776,14 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.setImage(EbtFloat, Esd3D); } + | F16IMAGE3D { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtFloat16, Esd3D); +#endif + } | IIMAGE3D { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -2015,6 +2799,14 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.setImage(EbtFloat, EsdRect); } + | F16IMAGE2DRECT { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtFloat16, EsdRect); +#endif + } | IIMAGE2DRECT { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -2030,6 +2822,14 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.setImage(EbtFloat, EsdCube); } + | F16IMAGECUBE { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtFloat16, EsdCube); +#endif + } | IIMAGECUBE { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -2045,6 +2845,14 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.setImage(EbtFloat, EsdBuffer); } + | F16IMAGEBUFFER { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtFloat16, EsdBuffer); +#endif + } | IIMAGEBUFFER { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -2060,6 +2868,14 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.setImage(EbtFloat, Esd1D, true); } + | F16IMAGE1DARRAY { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtFloat16, Esd1D, true); +#endif + } | IIMAGE1DARRAY { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -2075,6 +2891,14 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.setImage(EbtFloat, Esd2D, true); } + | F16IMAGE2DARRAY { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtFloat16, Esd2D, true); +#endif + } | IIMAGE2DARRAY { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -2090,6 +2914,14 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.setImage(EbtFloat, EsdCube, true); } + | F16IMAGECUBEARRAY { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtFloat16, EsdCube, true); +#endif + } | IIMAGECUBEARRAY { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -2105,6 +2937,14 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.setImage(EbtFloat, Esd2D, false, false, true); } + | F16IMAGE2DMS { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtFloat16, Esd2D, false, false, true); +#endif + } | IIMAGE2DMS { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -2120,6 +2960,14 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.setImage(EbtFloat, Esd2D, true, false, true); } + | F16IMAGE2DMSARRAY { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtFloat16, Esd2D, true, false, true); +#endif + } | IIMAGE2DMSARRAY { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -2148,6 +2996,24 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.setSubpass(EbtFloat, true); } + | F16SUBPASSINPUT { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float subpass input", parseContext.symbolTable.atBuiltInLevel()); + parseContext.requireStage($1.loc, EShLangFragment, "subpass input"); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setSubpass(EbtFloat16); +#endif + } + | F16SUBPASSINPUTMS { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck($1.loc, "half float subpass input", parseContext.symbolTable.atBuiltInLevel()); + parseContext.requireStage($1.loc, EShLangFragment, "subpass input"); + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setSubpass(EbtFloat16, true); +#endif + } | ISUBPASSINPUT { parseContext.requireStage($1.loc, EShLangFragment, "subpass input"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); @@ -2196,20 +3062,17 @@ precision_qualifier : HIGH_PRECISION { parseContext.profileRequires($1.loc, ENoProfile, 130, 0, "highp precision qualifier"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); - if (parseContext.profile == EEsProfile) - $$.qualifier.precision = EpqHigh; + parseContext.handlePrecisionQualifier($1.loc, $$.qualifier, EpqHigh); } | MEDIUM_PRECISION { parseContext.profileRequires($1.loc, ENoProfile, 130, 0, "mediump precision qualifier"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); - if (parseContext.profile == EEsProfile) - $$.qualifier.precision = EpqMedium; + parseContext.handlePrecisionQualifier($1.loc, $$.qualifier, EpqMedium); } | LOW_PRECISION { parseContext.profileRequires($1.loc, ENoProfile, 130, 0, "lowp precision qualifier"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); - if (parseContext.profile == EEsProfile) - $$.qualifier.precision = EpqLow; + parseContext.handlePrecisionQualifier($1.loc, $$.qualifier, EpqLow); } ; @@ -2265,12 +3128,15 @@ struct_declaration parseContext.precisionQualifierCheck($1.loc, $1.basicType, $1.qualifier); for (unsigned int i = 0; i < $$->size(); ++i) { - parseContext.arrayDimCheck($1.loc, (*$$)[i].type, $1.arraySizes); - (*$$)[i].type->mergeType($1); + TType type($1); + type.setFieldName((*$$)[i].type->getFieldName()); + type.transferArraySizes((*$$)[i].type->getArraySizes()); + type.copyArrayInnerSizes($1.arraySizes); + parseContext.arrayOfArrayVersionCheck((*$$)[i].loc, type.getArraySizes()); + (*$$)[i].type->shallowCopy(type); } } | type_qualifier type_specifier struct_declarator_list SEMICOLON { - parseContext.globalQualifierFixCheck($1.loc, $1.qualifier); if ($2.arraySizes) { parseContext.profileRequires($2.loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); parseContext.profileRequires($2.loc, EEsProfile, 300, 0, "arrayed type"); @@ -2280,14 +3146,18 @@ struct_declaration $$ = $3; - parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers); + 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); for (unsigned int i = 0; i < $$->size(); ++i) { - parseContext.arrayDimCheck($1.loc, (*$$)[i].type, $2.arraySizes); - (*$$)[i].type->mergeType($2); + TType type($2); + type.setFieldName((*$$)[i].type->getFieldName()); + type.transferArraySizes((*$$)[i].type->getArraySizes()); + type.copyArrayInnerSizes($2.arraySizes); + parseContext.arrayOfArrayVersionCheck((*$$)[i].loc, type.getArraySizes()); + (*$$)[i].type->shallowCopy(type); } } ; @@ -2309,12 +3179,12 @@ struct_declarator $$.type->setFieldName(*$1.string); } | IDENTIFIER array_specifier { - parseContext.arrayDimCheck($1.loc, $2.arraySizes, 0); + parseContext.arrayOfArrayVersionCheck($1.loc, $2.arraySizes); $$.type = new TType(EbtVoid); $$.loc = $1.loc; $$.type->setFieldName(*$1.string); - $$.type->newArraySizes(*$2.arraySizes); + $$.type->transferArraySizes($2.arraySizes); } ; @@ -2445,6 +3315,15 @@ expression_statement ; selection_statement + : selection_statement_nonattributed { + $$ = $1; + } + | attribute selection_statement_nonattributed { + parseContext.handleSelectionAttributes(*$1, $2); + $$ = $2; + } + +selection_statement_nonattributed : IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement { parseContext.boolCheck($1.loc, $3); $$ = parseContext.intermediate.addSelection($3, $5, $1.loc); @@ -2481,6 +3360,15 @@ condition ; switch_statement + : switch_statement_nonattributed { + $$ = $1; + } + | attribute switch_statement_nonattributed { + parseContext.handleSwitchAttributes(*$1, $2); + $$ = $2; + } + +switch_statement_nonattributed : SWITCH LEFT_PAREN expression RIGHT_PAREN { // start new switch sequence on the switch stack ++parseContext.controlFlowNestingLevel; @@ -2534,6 +3422,15 @@ case_label ; iteration_statement + : iteration_statement_nonattributed { + $$ = $1; + } + | attribute iteration_statement_nonattributed { + parseContext.handleLoopAttributes(*$1, $2); + $$ = $2; + } + +iteration_statement_nonattributed : WHILE LEFT_PAREN { if (! parseContext.limits.whileLoops) parseContext.error($1.loc, "while loops not available", "limitation", ""); @@ -2630,7 +3527,7 @@ jump_statement if (parseContext.currentFunctionType->getBasicType() != EbtVoid) parseContext.error($1.loc, "non-void function must return a value", "return", ""); if (parseContext.inMain) - parseContext.postMainReturn = true; + parseContext.postEntryPointReturn = true; } | RETURN expression SEMICOLON { $$ = parseContext.handleReturnValue($1.loc, $2); @@ -2649,8 +3546,10 @@ translation_unit parseContext.intermediate.setTreeRoot($$); } | translation_unit external_declaration { - $$ = parseContext.intermediate.growAggregate($1, $2); - parseContext.intermediate.setTreeRoot($$); + if ($2 != nullptr) { + $$ = parseContext.intermediate.growAggregate($1, $2); + parseContext.intermediate.setTreeRoot($$); + } } ; @@ -2661,6 +3560,11 @@ external_declaration | declaration { $$ = $1; } + | SEMICOLON { + parseContext.requireProfile($1.loc, ~EEsProfile, "extraneous semicolon"); + parseContext.profileRequires($1.loc, ~EEsProfile, 460, nullptr, "extraneous semicolon"); + $$ = nullptr; + } ; function_definition @@ -2681,8 +3585,30 @@ function_definition // information. This information can be queried from the parse tree $$->getAsAggregate()->setOptimize(parseContext.contextPragma.optimize); $$->getAsAggregate()->setDebug(parseContext.contextPragma.debug); - $$->getAsAggregate()->addToPragmaTable(parseContext.contextPragma.pragmaTable); + $$->getAsAggregate()->setPragmaTable(parseContext.contextPragma.pragmaTable); } ; +attribute + : LEFT_BRACKET LEFT_BRACKET attribute_list RIGHT_BRACKET RIGHT_BRACKET { + $$ = $3; + parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_control_flow_attributes, "attribute"); + } + +attribute_list + : single_attribute { + $$ = $1; + } + | attribute_list COMMA single_attribute { + $$ = parseContext.mergeAttributes($1, $3); + } + +single_attribute + : IDENTIFIER { + $$ = parseContext.makeAttributes(*$1.string); + } + | IDENTIFIER LEFT_PAREN constant_expression RIGHT_PAREN { + $$ = parseContext.makeAttributes(*$1.string, $3); + } + %% diff --git a/Externals/glslang/glslang/MachineIndependent/glslang_tab.cpp b/Externals/glslang/glslang/MachineIndependent/glslang_tab.cpp index c8664f9dde..38672d67d3 100644 --- a/Externals/glslang/glslang/MachineIndependent/glslang_tab.cpp +++ b/Externals/glslang/glslang/MachineIndependent/glslang_tab.cpp @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 3.0.4. */ +/* A Bison parser, made by GNU Bison 3.0. */ /* Bison implementation for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -44,7 +44,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "3.0.4" +#define YYBISON_VERSION "3.0" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -62,7 +62,7 @@ /* Copy the first part of user declarations. */ -#line 41 "MachineIndependent/glslang.y" /* yacc.c:339 */ +#line 42 "MachineIndependent/glslang.y" /* yacc.c:339 */ /* Based on: @@ -83,17 +83,18 @@ Jutta Degener, 1995 #include "SymbolTable.h" #include "ParseHelper.h" #include "../Public/ShaderLang.h" +#include "attribute.h" using namespace glslang; -#line 91 "MachineIndependent/glslang_tab.cpp" /* yacc.c:339 */ +#line 92 "MachineIndependent/glslang_tab.cpp" /* yacc.c:339 */ -# ifndef YY_NULLPTR +# ifndef YY_NULL # if defined __cplusplus && 201103L <= __cplusplus -# define YY_NULLPTR nullptr +# define YY_NULL nullptr # else -# define YY_NULLPTR 0 +# define YY_NULL 0 # endif # endif @@ -102,7 +103,7 @@ using namespace glslang; # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else -# define YYERROR_VERBOSE 0 +# define YYERROR_VERBOSE 1 #endif /* In a future release of Bison, this section will be replaced @@ -124,280 +125,401 @@ extern int yydebug; { ATTRIBUTE = 258, VARYING = 259, - CONST = 260, - BOOL = 261, - FLOAT = 262, + FLOAT16_T = 260, + FLOAT = 261, + FLOAT32_T = 262, DOUBLE = 263, - INT = 264, - UINT = 265, - INT64_T = 266, - UINT64_T = 267, - BREAK = 268, - CONTINUE = 269, - DO = 270, - ELSE = 271, - FOR = 272, - IF = 273, - DISCARD = 274, - RETURN = 275, - SWITCH = 276, - CASE = 277, - DEFAULT = 278, - SUBROUTINE = 279, - BVEC2 = 280, - BVEC3 = 281, - BVEC4 = 282, - IVEC2 = 283, - IVEC3 = 284, - IVEC4 = 285, - I64VEC2 = 286, - I64VEC3 = 287, - I64VEC4 = 288, - UVEC2 = 289, - UVEC3 = 290, - UVEC4 = 291, - U64VEC2 = 292, - U64VEC3 = 293, - U64VEC4 = 294, - VEC2 = 295, - VEC3 = 296, - VEC4 = 297, - MAT2 = 298, - MAT3 = 299, - MAT4 = 300, - CENTROID = 301, - IN = 302, - OUT = 303, - INOUT = 304, - UNIFORM = 305, - PATCH = 306, - SAMPLE = 307, - BUFFER = 308, - SHARED = 309, - COHERENT = 310, - VOLATILE = 311, - RESTRICT = 312, - READONLY = 313, - WRITEONLY = 314, - DVEC2 = 315, - DVEC3 = 316, - DVEC4 = 317, - DMAT2 = 318, - DMAT3 = 319, - DMAT4 = 320, - NOPERSPECTIVE = 321, - FLAT = 322, - SMOOTH = 323, - LAYOUT = 324, - MAT2X2 = 325, - MAT2X3 = 326, - MAT2X4 = 327, - MAT3X2 = 328, - MAT3X3 = 329, - MAT3X4 = 330, - MAT4X2 = 331, - MAT4X3 = 332, - MAT4X4 = 333, - DMAT2X2 = 334, - DMAT2X3 = 335, - DMAT2X4 = 336, - DMAT3X2 = 337, - DMAT3X3 = 338, - DMAT3X4 = 339, - DMAT4X2 = 340, - DMAT4X3 = 341, - DMAT4X4 = 342, - ATOMIC_UINT = 343, - SAMPLER1D = 344, - SAMPLER2D = 345, - SAMPLER3D = 346, - SAMPLERCUBE = 347, - SAMPLER1DSHADOW = 348, - SAMPLER2DSHADOW = 349, - SAMPLERCUBESHADOW = 350, - SAMPLER1DARRAY = 351, - SAMPLER2DARRAY = 352, - SAMPLER1DARRAYSHADOW = 353, - SAMPLER2DARRAYSHADOW = 354, - ISAMPLER1D = 355, - ISAMPLER2D = 356, - ISAMPLER3D = 357, - ISAMPLERCUBE = 358, - ISAMPLER1DARRAY = 359, - ISAMPLER2DARRAY = 360, - USAMPLER1D = 361, - USAMPLER2D = 362, - USAMPLER3D = 363, - USAMPLERCUBE = 364, - USAMPLER1DARRAY = 365, - USAMPLER2DARRAY = 366, - SAMPLER2DRECT = 367, - SAMPLER2DRECTSHADOW = 368, - ISAMPLER2DRECT = 369, - USAMPLER2DRECT = 370, - SAMPLERBUFFER = 371, - ISAMPLERBUFFER = 372, - USAMPLERBUFFER = 373, - SAMPLERCUBEARRAY = 374, - SAMPLERCUBEARRAYSHADOW = 375, - ISAMPLERCUBEARRAY = 376, - USAMPLERCUBEARRAY = 377, - SAMPLER2DMS = 378, - ISAMPLER2DMS = 379, - USAMPLER2DMS = 380, - SAMPLER2DMSARRAY = 381, - ISAMPLER2DMSARRAY = 382, - USAMPLER2DMSARRAY = 383, - SAMPLEREXTERNALOES = 384, - SAMPLER = 385, - SAMPLERSHADOW = 386, - TEXTURE1D = 387, - TEXTURE2D = 388, - TEXTURE3D = 389, - TEXTURECUBE = 390, - TEXTURE1DARRAY = 391, - TEXTURE2DARRAY = 392, - ITEXTURE1D = 393, - ITEXTURE2D = 394, - ITEXTURE3D = 395, - ITEXTURECUBE = 396, - ITEXTURE1DARRAY = 397, - ITEXTURE2DARRAY = 398, - UTEXTURE1D = 399, - UTEXTURE2D = 400, - UTEXTURE3D = 401, - UTEXTURECUBE = 402, - UTEXTURE1DARRAY = 403, - UTEXTURE2DARRAY = 404, - TEXTURE2DRECT = 405, - ITEXTURE2DRECT = 406, - UTEXTURE2DRECT = 407, - TEXTUREBUFFER = 408, - ITEXTUREBUFFER = 409, - UTEXTUREBUFFER = 410, - TEXTURECUBEARRAY = 411, - ITEXTURECUBEARRAY = 412, - UTEXTURECUBEARRAY = 413, - TEXTURE2DMS = 414, - ITEXTURE2DMS = 415, - UTEXTURE2DMS = 416, - TEXTURE2DMSARRAY = 417, - ITEXTURE2DMSARRAY = 418, - UTEXTURE2DMSARRAY = 419, - SUBPASSINPUT = 420, - SUBPASSINPUTMS = 421, - ISUBPASSINPUT = 422, - ISUBPASSINPUTMS = 423, - USUBPASSINPUT = 424, - USUBPASSINPUTMS = 425, - IMAGE1D = 426, - IIMAGE1D = 427, - UIMAGE1D = 428, - IMAGE2D = 429, - IIMAGE2D = 430, - UIMAGE2D = 431, - IMAGE3D = 432, - IIMAGE3D = 433, - UIMAGE3D = 434, - IMAGE2DRECT = 435, - IIMAGE2DRECT = 436, - UIMAGE2DRECT = 437, - IMAGECUBE = 438, - IIMAGECUBE = 439, - UIMAGECUBE = 440, - IMAGEBUFFER = 441, - IIMAGEBUFFER = 442, - UIMAGEBUFFER = 443, - IMAGE1DARRAY = 444, - IIMAGE1DARRAY = 445, - UIMAGE1DARRAY = 446, - IMAGE2DARRAY = 447, - IIMAGE2DARRAY = 448, - UIMAGE2DARRAY = 449, - IMAGECUBEARRAY = 450, - IIMAGECUBEARRAY = 451, - UIMAGECUBEARRAY = 452, - IMAGE2DMS = 453, - IIMAGE2DMS = 454, - UIMAGE2DMS = 455, - IMAGE2DMSARRAY = 456, - IIMAGE2DMSARRAY = 457, - UIMAGE2DMSARRAY = 458, - STRUCT = 459, - VOID = 460, - WHILE = 461, - IDENTIFIER = 462, - TYPE_NAME = 463, - FLOATCONSTANT = 464, - DOUBLECONSTANT = 465, - INTCONSTANT = 466, - UINTCONSTANT = 467, - INT64CONSTANT = 468, - UINT64CONSTANT = 469, - BOOLCONSTANT = 470, - LEFT_OP = 471, - RIGHT_OP = 472, - INC_OP = 473, - DEC_OP = 474, - LE_OP = 475, - GE_OP = 476, - EQ_OP = 477, - NE_OP = 478, - AND_OP = 479, - OR_OP = 480, - XOR_OP = 481, - MUL_ASSIGN = 482, - DIV_ASSIGN = 483, - ADD_ASSIGN = 484, - MOD_ASSIGN = 485, - LEFT_ASSIGN = 486, - RIGHT_ASSIGN = 487, - AND_ASSIGN = 488, - XOR_ASSIGN = 489, - OR_ASSIGN = 490, - SUB_ASSIGN = 491, - LEFT_PAREN = 492, - RIGHT_PAREN = 493, - LEFT_BRACKET = 494, - RIGHT_BRACKET = 495, - LEFT_BRACE = 496, - RIGHT_BRACE = 497, - DOT = 498, - COMMA = 499, - COLON = 500, - EQUAL = 501, - SEMICOLON = 502, - BANG = 503, - DASH = 504, - TILDE = 505, - PLUS = 506, - STAR = 507, - SLASH = 508, - PERCENT = 509, - LEFT_ANGLE = 510, - RIGHT_ANGLE = 511, - VERTICAL_BAR = 512, - CARET = 513, - AMPERSAND = 514, - QUESTION = 515, - INVARIANT = 516, - PRECISE = 517, - HIGH_PRECISION = 518, - MEDIUM_PRECISION = 519, - LOW_PRECISION = 520, - PRECISION = 521, - PACKED = 522, - RESOURCE = 523, - SUPERP = 524 + FLOAT64_T = 264, + CONST = 265, + BOOL = 266, + INT = 267, + UINT = 268, + INT64_T = 269, + UINT64_T = 270, + INT32_T = 271, + UINT32_T = 272, + INT16_T = 273, + UINT16_T = 274, + INT8_T = 275, + UINT8_T = 276, + BREAK = 277, + CONTINUE = 278, + DO = 279, + ELSE = 280, + FOR = 281, + IF = 282, + DISCARD = 283, + RETURN = 284, + SWITCH = 285, + CASE = 286, + DEFAULT = 287, + SUBROUTINE = 288, + BVEC2 = 289, + BVEC3 = 290, + BVEC4 = 291, + IVEC2 = 292, + IVEC3 = 293, + IVEC4 = 294, + UVEC2 = 295, + UVEC3 = 296, + UVEC4 = 297, + I64VEC2 = 298, + I64VEC3 = 299, + I64VEC4 = 300, + U64VEC2 = 301, + U64VEC3 = 302, + U64VEC4 = 303, + I32VEC2 = 304, + I32VEC3 = 305, + I32VEC4 = 306, + U32VEC2 = 307, + U32VEC3 = 308, + U32VEC4 = 309, + I16VEC2 = 310, + I16VEC3 = 311, + I16VEC4 = 312, + U16VEC2 = 313, + U16VEC3 = 314, + U16VEC4 = 315, + I8VEC2 = 316, + I8VEC3 = 317, + I8VEC4 = 318, + U8VEC2 = 319, + U8VEC3 = 320, + U8VEC4 = 321, + VEC2 = 322, + VEC3 = 323, + VEC4 = 324, + MAT2 = 325, + MAT3 = 326, + MAT4 = 327, + CENTROID = 328, + IN = 329, + OUT = 330, + INOUT = 331, + UNIFORM = 332, + PATCH = 333, + SAMPLE = 334, + BUFFER = 335, + SHARED = 336, + NONUNIFORM = 337, + COHERENT = 338, + VOLATILE = 339, + RESTRICT = 340, + READONLY = 341, + WRITEONLY = 342, + DVEC2 = 343, + DVEC3 = 344, + DVEC4 = 345, + DMAT2 = 346, + DMAT3 = 347, + DMAT4 = 348, + F16VEC2 = 349, + F16VEC3 = 350, + F16VEC4 = 351, + F16MAT2 = 352, + F16MAT3 = 353, + F16MAT4 = 354, + F32VEC2 = 355, + F32VEC3 = 356, + F32VEC4 = 357, + F32MAT2 = 358, + F32MAT3 = 359, + F32MAT4 = 360, + F64VEC2 = 361, + F64VEC3 = 362, + F64VEC4 = 363, + F64MAT2 = 364, + F64MAT3 = 365, + F64MAT4 = 366, + NOPERSPECTIVE = 367, + FLAT = 368, + SMOOTH = 369, + LAYOUT = 370, + __EXPLICITINTERPAMD = 371, + MAT2X2 = 372, + MAT2X3 = 373, + MAT2X4 = 374, + MAT3X2 = 375, + MAT3X3 = 376, + MAT3X4 = 377, + MAT4X2 = 378, + MAT4X3 = 379, + MAT4X4 = 380, + DMAT2X2 = 381, + DMAT2X3 = 382, + DMAT2X4 = 383, + DMAT3X2 = 384, + DMAT3X3 = 385, + DMAT3X4 = 386, + DMAT4X2 = 387, + DMAT4X3 = 388, + DMAT4X4 = 389, + F16MAT2X2 = 390, + F16MAT2X3 = 391, + F16MAT2X4 = 392, + F16MAT3X2 = 393, + F16MAT3X3 = 394, + F16MAT3X4 = 395, + F16MAT4X2 = 396, + F16MAT4X3 = 397, + F16MAT4X4 = 398, + F32MAT2X2 = 399, + F32MAT2X3 = 400, + F32MAT2X4 = 401, + F32MAT3X2 = 402, + F32MAT3X3 = 403, + F32MAT3X4 = 404, + F32MAT4X2 = 405, + F32MAT4X3 = 406, + F32MAT4X4 = 407, + F64MAT2X2 = 408, + F64MAT2X3 = 409, + F64MAT2X4 = 410, + F64MAT3X2 = 411, + F64MAT3X3 = 412, + F64MAT3X4 = 413, + F64MAT4X2 = 414, + F64MAT4X3 = 415, + F64MAT4X4 = 416, + ATOMIC_UINT = 417, + SAMPLER1D = 418, + SAMPLER2D = 419, + SAMPLER3D = 420, + SAMPLERCUBE = 421, + SAMPLER1DSHADOW = 422, + SAMPLER2DSHADOW = 423, + SAMPLERCUBESHADOW = 424, + SAMPLER1DARRAY = 425, + SAMPLER2DARRAY = 426, + SAMPLER1DARRAYSHADOW = 427, + SAMPLER2DARRAYSHADOW = 428, + ISAMPLER1D = 429, + ISAMPLER2D = 430, + ISAMPLER3D = 431, + ISAMPLERCUBE = 432, + ISAMPLER1DARRAY = 433, + ISAMPLER2DARRAY = 434, + USAMPLER1D = 435, + USAMPLER2D = 436, + USAMPLER3D = 437, + USAMPLERCUBE = 438, + USAMPLER1DARRAY = 439, + USAMPLER2DARRAY = 440, + SAMPLER2DRECT = 441, + SAMPLER2DRECTSHADOW = 442, + ISAMPLER2DRECT = 443, + USAMPLER2DRECT = 444, + SAMPLERBUFFER = 445, + ISAMPLERBUFFER = 446, + USAMPLERBUFFER = 447, + SAMPLERCUBEARRAY = 448, + SAMPLERCUBEARRAYSHADOW = 449, + ISAMPLERCUBEARRAY = 450, + USAMPLERCUBEARRAY = 451, + SAMPLER2DMS = 452, + ISAMPLER2DMS = 453, + USAMPLER2DMS = 454, + SAMPLER2DMSARRAY = 455, + ISAMPLER2DMSARRAY = 456, + USAMPLER2DMSARRAY = 457, + SAMPLEREXTERNALOES = 458, + F16SAMPLER1D = 459, + F16SAMPLER2D = 460, + F16SAMPLER3D = 461, + F16SAMPLER2DRECT = 462, + F16SAMPLERCUBE = 463, + F16SAMPLER1DARRAY = 464, + F16SAMPLER2DARRAY = 465, + F16SAMPLERCUBEARRAY = 466, + F16SAMPLERBUFFER = 467, + F16SAMPLER2DMS = 468, + F16SAMPLER2DMSARRAY = 469, + F16SAMPLER1DSHADOW = 470, + F16SAMPLER2DSHADOW = 471, + F16SAMPLER1DARRAYSHADOW = 472, + F16SAMPLER2DARRAYSHADOW = 473, + F16SAMPLER2DRECTSHADOW = 474, + F16SAMPLERCUBESHADOW = 475, + F16SAMPLERCUBEARRAYSHADOW = 476, + SAMPLER = 477, + SAMPLERSHADOW = 478, + TEXTURE1D = 479, + TEXTURE2D = 480, + TEXTURE3D = 481, + TEXTURECUBE = 482, + TEXTURE1DARRAY = 483, + TEXTURE2DARRAY = 484, + ITEXTURE1D = 485, + ITEXTURE2D = 486, + ITEXTURE3D = 487, + ITEXTURECUBE = 488, + ITEXTURE1DARRAY = 489, + ITEXTURE2DARRAY = 490, + UTEXTURE1D = 491, + UTEXTURE2D = 492, + UTEXTURE3D = 493, + UTEXTURECUBE = 494, + UTEXTURE1DARRAY = 495, + UTEXTURE2DARRAY = 496, + TEXTURE2DRECT = 497, + ITEXTURE2DRECT = 498, + UTEXTURE2DRECT = 499, + TEXTUREBUFFER = 500, + ITEXTUREBUFFER = 501, + UTEXTUREBUFFER = 502, + TEXTURECUBEARRAY = 503, + ITEXTURECUBEARRAY = 504, + UTEXTURECUBEARRAY = 505, + TEXTURE2DMS = 506, + ITEXTURE2DMS = 507, + UTEXTURE2DMS = 508, + TEXTURE2DMSARRAY = 509, + ITEXTURE2DMSARRAY = 510, + UTEXTURE2DMSARRAY = 511, + F16TEXTURE1D = 512, + F16TEXTURE2D = 513, + F16TEXTURE3D = 514, + F16TEXTURE2DRECT = 515, + F16TEXTURECUBE = 516, + F16TEXTURE1DARRAY = 517, + F16TEXTURE2DARRAY = 518, + F16TEXTURECUBEARRAY = 519, + F16TEXTUREBUFFER = 520, + F16TEXTURE2DMS = 521, + F16TEXTURE2DMSARRAY = 522, + SUBPASSINPUT = 523, + SUBPASSINPUTMS = 524, + ISUBPASSINPUT = 525, + ISUBPASSINPUTMS = 526, + USUBPASSINPUT = 527, + USUBPASSINPUTMS = 528, + F16SUBPASSINPUT = 529, + F16SUBPASSINPUTMS = 530, + IMAGE1D = 531, + IIMAGE1D = 532, + UIMAGE1D = 533, + IMAGE2D = 534, + IIMAGE2D = 535, + UIMAGE2D = 536, + IMAGE3D = 537, + IIMAGE3D = 538, + UIMAGE3D = 539, + IMAGE2DRECT = 540, + IIMAGE2DRECT = 541, + UIMAGE2DRECT = 542, + IMAGECUBE = 543, + IIMAGECUBE = 544, + UIMAGECUBE = 545, + IMAGEBUFFER = 546, + IIMAGEBUFFER = 547, + UIMAGEBUFFER = 548, + IMAGE1DARRAY = 549, + IIMAGE1DARRAY = 550, + UIMAGE1DARRAY = 551, + IMAGE2DARRAY = 552, + IIMAGE2DARRAY = 553, + UIMAGE2DARRAY = 554, + IMAGECUBEARRAY = 555, + IIMAGECUBEARRAY = 556, + UIMAGECUBEARRAY = 557, + IMAGE2DMS = 558, + IIMAGE2DMS = 559, + UIMAGE2DMS = 560, + IMAGE2DMSARRAY = 561, + IIMAGE2DMSARRAY = 562, + UIMAGE2DMSARRAY = 563, + F16IMAGE1D = 564, + F16IMAGE2D = 565, + F16IMAGE3D = 566, + F16IMAGE2DRECT = 567, + F16IMAGECUBE = 568, + F16IMAGE1DARRAY = 569, + F16IMAGE2DARRAY = 570, + F16IMAGECUBEARRAY = 571, + F16IMAGEBUFFER = 572, + F16IMAGE2DMS = 573, + F16IMAGE2DMSARRAY = 574, + STRUCT = 575, + VOID = 576, + WHILE = 577, + IDENTIFIER = 578, + TYPE_NAME = 579, + FLOATCONSTANT = 580, + DOUBLECONSTANT = 581, + INT16CONSTANT = 582, + UINT16CONSTANT = 583, + INT32CONSTANT = 584, + UINT32CONSTANT = 585, + INTCONSTANT = 586, + UINTCONSTANT = 587, + INT64CONSTANT = 588, + UINT64CONSTANT = 589, + BOOLCONSTANT = 590, + FLOAT16CONSTANT = 591, + LEFT_OP = 592, + RIGHT_OP = 593, + INC_OP = 594, + DEC_OP = 595, + LE_OP = 596, + GE_OP = 597, + EQ_OP = 598, + NE_OP = 599, + AND_OP = 600, + OR_OP = 601, + XOR_OP = 602, + MUL_ASSIGN = 603, + DIV_ASSIGN = 604, + ADD_ASSIGN = 605, + MOD_ASSIGN = 606, + LEFT_ASSIGN = 607, + RIGHT_ASSIGN = 608, + AND_ASSIGN = 609, + XOR_ASSIGN = 610, + OR_ASSIGN = 611, + SUB_ASSIGN = 612, + LEFT_PAREN = 613, + RIGHT_PAREN = 614, + LEFT_BRACKET = 615, + RIGHT_BRACKET = 616, + LEFT_BRACE = 617, + RIGHT_BRACE = 618, + DOT = 619, + COMMA = 620, + COLON = 621, + EQUAL = 622, + SEMICOLON = 623, + BANG = 624, + DASH = 625, + TILDE = 626, + PLUS = 627, + STAR = 628, + SLASH = 629, + PERCENT = 630, + LEFT_ANGLE = 631, + RIGHT_ANGLE = 632, + VERTICAL_BAR = 633, + CARET = 634, + AMPERSAND = 635, + QUESTION = 636, + INVARIANT = 637, + PRECISE = 638, + HIGH_PRECISION = 639, + MEDIUM_PRECISION = 640, + LOW_PRECISION = 641, + PRECISION = 642, + PACKED = 643, + RESOURCE = 644, + SUPERP = 645 }; #endif /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED - +typedef union YYSTYPE YYSTYPE; union YYSTYPE { -#line 66 "MachineIndependent/glslang.y" /* yacc.c:355 */ +#line 70 "MachineIndependent/glslang.y" /* yacc.c:355 */ struct { glslang::TSourceLoc loc; @@ -419,6 +541,7 @@ union YYSTYPE TIntermNode* intermNode; glslang::TIntermNodePair nodePair; glslang::TIntermTyped* intermTypedNode; + glslang::TAttributes* attributes; }; union { glslang::TPublicType type; @@ -431,10 +554,8 @@ union YYSTYPE }; } interm; -#line 435 "MachineIndependent/glslang_tab.cpp" /* yacc.c:355 */ +#line 558 "MachineIndependent/glslang_tab.cpp" /* yacc.c:355 */ }; - -typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif @@ -446,7 +567,7 @@ int yyparse (glslang::TParseContext* pParseContext); #endif /* !YY_YY_MACHINEINDEPENDENT_GLSLANG_TAB_CPP_H_INCLUDED */ /* Copy the second part of user declarations. */ -#line 100 "MachineIndependent/glslang.y" /* yacc.c:358 */ +#line 105 "MachineIndependent/glslang.y" /* yacc.c:358 */ /* windows only pragma */ @@ -462,7 +583,7 @@ int yyparse (glslang::TParseContext* pParseContext); extern int yylex(YYSTYPE*, TParseContext&); -#line 466 "MachineIndependent/glslang_tab.cpp" /* yacc.c:358 */ +#line 587 "MachineIndependent/glslang_tab.cpp" /* yacc.c:358 */ #ifdef short # undef short @@ -519,30 +640,11 @@ typedef short int yytype_int16; # endif #endif -#ifndef YY_ATTRIBUTE -# if (defined __GNUC__ \ - && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ - || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C -# define YY_ATTRIBUTE(Spec) __attribute__(Spec) -# else -# define YY_ATTRIBUTE(Spec) /* empty */ -# endif -#endif - -#ifndef YY_ATTRIBUTE_PURE -# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) -#endif - -#ifndef YY_ATTRIBUTE_UNUSED -# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) -#endif - -#if !defined _Noreturn \ - && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) -# if defined _MSC_VER && 1200 <= _MSC_VER -# define _Noreturn __declspec (noreturn) -# else -# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +#ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if (! defined __GNUC__ || __GNUC__ < 2 \ + || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)) +# define __attribute__(Spec) /* empty */ # endif #endif @@ -702,23 +804,23 @@ union yyalloc #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 248 +#define YYFINAL 366 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 5943 +#define YYLAST 8949 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 270 +#define YYNTOKENS 391 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 100 +#define YYNNTS 107 /* YYNRULES -- Number of rules. */ -#define YYNRULES 421 +#define YYNRULES 556 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 553 +#define YYNSTATES 697 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 524 +#define YYMAXUTOK 645 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -779,109 +881,162 @@ static const yytype_uint16 yytranslate[] = 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269 + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, 388, 389, 390 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 246, 246, 252, 255, 258, 262, 266, 270, 273, - 277, 280, 288, 291, 294, 297, 300, 305, 313, 320, - 327, 333, 337, 344, 347, 353, 360, 370, 378, 383, - 413, 419, 423, 427, 447, 448, 449, 450, 456, 457, - 462, 467, 476, 477, 482, 490, 491, 497, 506, 507, - 512, 517, 522, 530, 531, 539, 550, 551, 560, 561, - 570, 571, 580, 581, 589, 590, 598, 599, 607, 608, - 608, 626, 627, 642, 646, 650, 654, 659, 663, 667, - 671, 675, 679, 683, 690, 693, 703, 710, 715, 720, - 728, 732, 736, 740, 745, 750, 759, 759, 770, 774, - 781, 788, 791, 798, 806, 826, 844, 859, 882, 893, - 903, 913, 923, 932, 935, 939, 943, 948, 956, 961, - 966, 971, 976, 985, 996, 1023, 1032, 1039, 1046, 1056, - 1062, 1065, 1072, 1076, 1080, 1088, 1097, 1100, 1111, 1114, - 1117, 1120, 1124, 1128, 1135, 1139, 1151, 1165, 1170, 1176, - 1182, 1189, 1195, 1200, 1205, 1210, 1217, 1221, 1225, 1229, - 1233, 1237, 1243, 1255, 1258, 1263, 1267, 1276, 1281, 1289, - 1293, 1303, 1307, 1311, 1316, 1320, 1325, 1330, 1335, 1339, - 1344, 1349, 1354, 1360, 1366, 1372, 1377, 1382, 1387, 1392, - 1397, 1402, 1408, 1414, 1420, 1426, 1432, 1438, 1444, 1450, - 1456, 1461, 1466, 1471, 1476, 1481, 1486, 1491, 1496, 1501, - 1506, 1511, 1516, 1522, 1528, 1534, 1540, 1546, 1552, 1558, - 1564, 1570, 1576, 1582, 1588, 1593, 1598, 1603, 1608, 1613, - 1618, 1623, 1628, 1633, 1638, 1643, 1648, 1653, 1658, 1663, - 1668, 1673, 1678, 1683, 1688, 1693, 1698, 1703, 1708, 1713, - 1718, 1723, 1728, 1733, 1738, 1743, 1748, 1753, 1758, 1763, - 1768, 1773, 1778, 1783, 1788, 1793, 1798, 1803, 1808, 1813, - 1818, 1823, 1828, 1833, 1838, 1843, 1848, 1853, 1858, 1863, - 1868, 1873, 1878, 1883, 1888, 1893, 1898, 1903, 1908, 1913, - 1918, 1923, 1928, 1933, 1938, 1943, 1948, 1953, 1958, 1963, - 1968, 1973, 1978, 1983, 1988, 1993, 1998, 2003, 2008, 2013, - 2018, 2023, 2028, 2033, 2038, 2043, 2048, 2053, 2058, 2063, - 2068, 2073, 2078, 2083, 2088, 2093, 2098, 2103, 2108, 2113, - 2118, 2123, 2128, 2133, 2139, 2145, 2151, 2157, 2163, 2169, - 2175, 2180, 2196, 2202, 2208, 2217, 2217, 2228, 2228, 2238, - 2241, 2254, 2272, 2296, 2300, 2306, 2311, 2322, 2325, 2331, - 2340, 2343, 2349, 2353, 2354, 2360, 2361, 2362, 2363, 2364, - 2365, 2366, 2370, 2371, 2375, 2371, 2387, 2388, 2392, 2392, - 2399, 2399, 2413, 2416, 2424, 2432, 2443, 2444, 2448, 2455, - 2459, 2467, 2471, 2484, 2484, 2504, 2507, 2513, 2525, 2537, - 2537, 2552, 2552, 2568, 2568, 2589, 2592, 2598, 2601, 2607, - 2611, 2618, 2623, 2628, 2635, 2638, 2647, 2651, 2658, 2661, - 2667, 2667 + 0, 293, 293, 299, 302, 306, 310, 313, 317, 321, + 325, 329, 333, 336, 340, 344, 347, 355, 358, 361, + 364, 367, 372, 380, 387, 394, 400, 404, 411, 414, + 420, 427, 437, 445, 450, 477, 485, 491, 495, 499, + 519, 520, 521, 522, 528, 529, 534, 539, 548, 549, + 554, 562, 563, 569, 578, 579, 584, 589, 594, 602, + 603, 611, 622, 623, 632, 633, 642, 643, 652, 653, + 661, 662, 670, 671, 679, 680, 680, 698, 699, 714, + 718, 722, 726, 731, 735, 739, 743, 747, 751, 755, + 762, 765, 776, 783, 788, 793, 801, 805, 809, 813, + 818, 823, 832, 832, 843, 847, 854, 861, 864, 871, + 879, 899, 922, 937, 962, 973, 983, 993, 1003, 1012, + 1015, 1019, 1023, 1028, 1036, 1041, 1046, 1051, 1056, 1065, + 1076, 1103, 1112, 1119, 1126, 1137, 1149, 1155, 1158, 1165, + 1169, 1173, 1181, 1190, 1193, 1204, 1207, 1210, 1214, 1218, + 1222, 1226, 1232, 1236, 1248, 1262, 1267, 1273, 1279, 1286, + 1292, 1297, 1302, 1307, 1315, 1319, 1323, 1327, 1331, 1335, + 1341, 1350, 1357, 1360, 1368, 1372, 1381, 1386, 1394, 1398, + 1408, 1412, 1416, 1421, 1426, 1431, 1436, 1440, 1445, 1450, + 1455, 1460, 1465, 1470, 1475, 1480, 1485, 1489, 1494, 1499, + 1504, 1510, 1516, 1522, 1528, 1534, 1540, 1546, 1552, 1558, + 1564, 1570, 1576, 1581, 1586, 1591, 1596, 1601, 1606, 1612, + 1618, 1624, 1630, 1636, 1642, 1648, 1654, 1660, 1666, 1672, + 1678, 1684, 1690, 1696, 1702, 1708, 1714, 1720, 1726, 1732, + 1738, 1744, 1750, 1756, 1762, 1768, 1773, 1778, 1783, 1788, + 1793, 1798, 1803, 1808, 1813, 1818, 1823, 1828, 1834, 1840, + 1846, 1852, 1858, 1864, 1870, 1876, 1882, 1888, 1894, 1900, + 1906, 1912, 1918, 1924, 1930, 1936, 1942, 1948, 1954, 1960, + 1966, 1972, 1978, 1984, 1990, 1996, 2002, 2008, 2014, 2020, + 2026, 2032, 2038, 2044, 2050, 2056, 2062, 2068, 2074, 2080, + 2086, 2092, 2098, 2104, 2110, 2116, 2121, 2126, 2131, 2136, + 2141, 2146, 2151, 2156, 2161, 2166, 2171, 2176, 2181, 2186, + 2194, 2202, 2210, 2218, 2226, 2234, 2242, 2250, 2258, 2266, + 2274, 2282, 2290, 2295, 2300, 2305, 2310, 2315, 2320, 2325, + 2330, 2335, 2340, 2345, 2350, 2355, 2360, 2365, 2370, 2378, + 2386, 2391, 2396, 2401, 2409, 2414, 2419, 2424, 2432, 2437, + 2442, 2447, 2455, 2460, 2465, 2470, 2475, 2480, 2488, 2493, + 2501, 2506, 2514, 2519, 2527, 2532, 2540, 2545, 2553, 2558, + 2566, 2571, 2576, 2581, 2586, 2591, 2596, 2601, 2606, 2611, + 2616, 2621, 2626, 2631, 2636, 2641, 2649, 2654, 2659, 2664, + 2672, 2677, 2682, 2687, 2695, 2700, 2705, 2710, 2718, 2723, + 2728, 2733, 2741, 2746, 2751, 2756, 2764, 2769, 2774, 2779, + 2787, 2792, 2797, 2802, 2810, 2815, 2820, 2825, 2833, 2838, + 2843, 2848, 2856, 2861, 2866, 2871, 2879, 2884, 2889, 2894, + 2902, 2907, 2912, 2917, 2925, 2930, 2935, 2940, 2948, 2953, + 2958, 2963, 2971, 2976, 2981, 2987, 2993, 2999, 3008, 3017, + 3023, 3029, 3035, 3041, 3046, 3062, 3067, 3072, 3080, 3080, + 3091, 3091, 3101, 3104, 3117, 3139, 3166, 3170, 3176, 3181, + 3192, 3195, 3201, 3210, 3213, 3219, 3223, 3224, 3230, 3231, + 3232, 3233, 3234, 3235, 3236, 3240, 3241, 3245, 3241, 3257, + 3258, 3262, 3262, 3269, 3269, 3283, 3286, 3294, 3302, 3313, + 3314, 3318, 3321, 3327, 3334, 3338, 3346, 3350, 3363, 3366, + 3372, 3372, 3392, 3395, 3401, 3413, 3425, 3428, 3434, 3434, + 3449, 3449, 3465, 3465, 3486, 3489, 3495, 3498, 3504, 3508, + 3515, 3520, 3525, 3532, 3535, 3544, 3548, 3557, 3560, 3563, + 3571, 3571, 3593, 3599, 3602, 3607, 3610 }; #endif -#if YYDEBUG || YYERROR_VERBOSE || 0 +#if YYDEBUG || YYERROR_VERBOSE || 1 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { - "$end", "error", "$undefined", "ATTRIBUTE", "VARYING", "CONST", "BOOL", - "FLOAT", "DOUBLE", "INT", "UINT", "INT64_T", "UINT64_T", "BREAK", - "CONTINUE", "DO", "ELSE", "FOR", "IF", "DISCARD", "RETURN", "SWITCH", - "CASE", "DEFAULT", "SUBROUTINE", "BVEC2", "BVEC3", "BVEC4", "IVEC2", - "IVEC3", "IVEC4", "I64VEC2", "I64VEC3", "I64VEC4", "UVEC2", "UVEC3", - "UVEC4", "U64VEC2", "U64VEC3", "U64VEC4", "VEC2", "VEC3", "VEC4", "MAT2", - "MAT3", "MAT4", "CENTROID", "IN", "OUT", "INOUT", "UNIFORM", "PATCH", - "SAMPLE", "BUFFER", "SHARED", "COHERENT", "VOLATILE", "RESTRICT", - "READONLY", "WRITEONLY", "DVEC2", "DVEC3", "DVEC4", "DMAT2", "DMAT3", - "DMAT4", "NOPERSPECTIVE", "FLAT", "SMOOTH", "LAYOUT", "MAT2X2", "MAT2X3", - "MAT2X4", "MAT3X2", "MAT3X3", "MAT3X4", "MAT4X2", "MAT4X3", "MAT4X4", - "DMAT2X2", "DMAT2X3", "DMAT2X4", "DMAT3X2", "DMAT3X3", "DMAT3X4", - "DMAT4X2", "DMAT4X3", "DMAT4X4", "ATOMIC_UINT", "SAMPLER1D", "SAMPLER2D", - "SAMPLER3D", "SAMPLERCUBE", "SAMPLER1DSHADOW", "SAMPLER2DSHADOW", - "SAMPLERCUBESHADOW", "SAMPLER1DARRAY", "SAMPLER2DARRAY", - "SAMPLER1DARRAYSHADOW", "SAMPLER2DARRAYSHADOW", "ISAMPLER1D", - "ISAMPLER2D", "ISAMPLER3D", "ISAMPLERCUBE", "ISAMPLER1DARRAY", - "ISAMPLER2DARRAY", "USAMPLER1D", "USAMPLER2D", "USAMPLER3D", - "USAMPLERCUBE", "USAMPLER1DARRAY", "USAMPLER2DARRAY", "SAMPLER2DRECT", - "SAMPLER2DRECTSHADOW", "ISAMPLER2DRECT", "USAMPLER2DRECT", - "SAMPLERBUFFER", "ISAMPLERBUFFER", "USAMPLERBUFFER", "SAMPLERCUBEARRAY", - "SAMPLERCUBEARRAYSHADOW", "ISAMPLERCUBEARRAY", "USAMPLERCUBEARRAY", - "SAMPLER2DMS", "ISAMPLER2DMS", "USAMPLER2DMS", "SAMPLER2DMSARRAY", - "ISAMPLER2DMSARRAY", "USAMPLER2DMSARRAY", "SAMPLEREXTERNALOES", - "SAMPLER", "SAMPLERSHADOW", "TEXTURE1D", "TEXTURE2D", "TEXTURE3D", - "TEXTURECUBE", "TEXTURE1DARRAY", "TEXTURE2DARRAY", "ITEXTURE1D", - "ITEXTURE2D", "ITEXTURE3D", "ITEXTURECUBE", "ITEXTURE1DARRAY", - "ITEXTURE2DARRAY", "UTEXTURE1D", "UTEXTURE2D", "UTEXTURE3D", - "UTEXTURECUBE", "UTEXTURE1DARRAY", "UTEXTURE2DARRAY", "TEXTURE2DRECT", - "ITEXTURE2DRECT", "UTEXTURE2DRECT", "TEXTUREBUFFER", "ITEXTUREBUFFER", - "UTEXTUREBUFFER", "TEXTURECUBEARRAY", "ITEXTURECUBEARRAY", - "UTEXTURECUBEARRAY", "TEXTURE2DMS", "ITEXTURE2DMS", "UTEXTURE2DMS", - "TEXTURE2DMSARRAY", "ITEXTURE2DMSARRAY", "UTEXTURE2DMSARRAY", + "$end", "error", "$undefined", "ATTRIBUTE", "VARYING", "FLOAT16_T", + "FLOAT", "FLOAT32_T", "DOUBLE", "FLOAT64_T", "CONST", "BOOL", "INT", + "UINT", "INT64_T", "UINT64_T", "INT32_T", "UINT32_T", "INT16_T", + "UINT16_T", "INT8_T", "UINT8_T", "BREAK", "CONTINUE", "DO", "ELSE", + "FOR", "IF", "DISCARD", "RETURN", "SWITCH", "CASE", "DEFAULT", + "SUBROUTINE", "BVEC2", "BVEC3", "BVEC4", "IVEC2", "IVEC3", "IVEC4", + "UVEC2", "UVEC3", "UVEC4", "I64VEC2", "I64VEC3", "I64VEC4", "U64VEC2", + "U64VEC3", "U64VEC4", "I32VEC2", "I32VEC3", "I32VEC4", "U32VEC2", + "U32VEC3", "U32VEC4", "I16VEC2", "I16VEC3", "I16VEC4", "U16VEC2", + "U16VEC3", "U16VEC4", "I8VEC2", "I8VEC3", "I8VEC4", "U8VEC2", "U8VEC3", + "U8VEC4", "VEC2", "VEC3", "VEC4", "MAT2", "MAT3", "MAT4", "CENTROID", + "IN", "OUT", "INOUT", "UNIFORM", "PATCH", "SAMPLE", "BUFFER", "SHARED", + "NONUNIFORM", "COHERENT", "VOLATILE", "RESTRICT", "READONLY", + "WRITEONLY", "DVEC2", "DVEC3", "DVEC4", "DMAT2", "DMAT3", "DMAT4", + "F16VEC2", "F16VEC3", "F16VEC4", "F16MAT2", "F16MAT3", "F16MAT4", + "F32VEC2", "F32VEC3", "F32VEC4", "F32MAT2", "F32MAT3", "F32MAT4", + "F64VEC2", "F64VEC3", "F64VEC4", "F64MAT2", "F64MAT3", "F64MAT4", + "NOPERSPECTIVE", "FLAT", "SMOOTH", "LAYOUT", "__EXPLICITINTERPAMD", + "MAT2X2", "MAT2X3", "MAT2X4", "MAT3X2", "MAT3X3", "MAT3X4", "MAT4X2", + "MAT4X3", "MAT4X4", "DMAT2X2", "DMAT2X3", "DMAT2X4", "DMAT3X2", + "DMAT3X3", "DMAT3X4", "DMAT4X2", "DMAT4X3", "DMAT4X4", "F16MAT2X2", + "F16MAT2X3", "F16MAT2X4", "F16MAT3X2", "F16MAT3X3", "F16MAT3X4", + "F16MAT4X2", "F16MAT4X3", "F16MAT4X4", "F32MAT2X2", "F32MAT2X3", + "F32MAT2X4", "F32MAT3X2", "F32MAT3X3", "F32MAT3X4", "F32MAT4X2", + "F32MAT4X3", "F32MAT4X4", "F64MAT2X2", "F64MAT2X3", "F64MAT2X4", + "F64MAT3X2", "F64MAT3X3", "F64MAT3X4", "F64MAT4X2", "F64MAT4X3", + "F64MAT4X4", "ATOMIC_UINT", "SAMPLER1D", "SAMPLER2D", "SAMPLER3D", + "SAMPLERCUBE", "SAMPLER1DSHADOW", "SAMPLER2DSHADOW", "SAMPLERCUBESHADOW", + "SAMPLER1DARRAY", "SAMPLER2DARRAY", "SAMPLER1DARRAYSHADOW", + "SAMPLER2DARRAYSHADOW", "ISAMPLER1D", "ISAMPLER2D", "ISAMPLER3D", + "ISAMPLERCUBE", "ISAMPLER1DARRAY", "ISAMPLER2DARRAY", "USAMPLER1D", + "USAMPLER2D", "USAMPLER3D", "USAMPLERCUBE", "USAMPLER1DARRAY", + "USAMPLER2DARRAY", "SAMPLER2DRECT", "SAMPLER2DRECTSHADOW", + "ISAMPLER2DRECT", "USAMPLER2DRECT", "SAMPLERBUFFER", "ISAMPLERBUFFER", + "USAMPLERBUFFER", "SAMPLERCUBEARRAY", "SAMPLERCUBEARRAYSHADOW", + "ISAMPLERCUBEARRAY", "USAMPLERCUBEARRAY", "SAMPLER2DMS", "ISAMPLER2DMS", + "USAMPLER2DMS", "SAMPLER2DMSARRAY", "ISAMPLER2DMSARRAY", + "USAMPLER2DMSARRAY", "SAMPLEREXTERNALOES", "F16SAMPLER1D", + "F16SAMPLER2D", "F16SAMPLER3D", "F16SAMPLER2DRECT", "F16SAMPLERCUBE", + "F16SAMPLER1DARRAY", "F16SAMPLER2DARRAY", "F16SAMPLERCUBEARRAY", + "F16SAMPLERBUFFER", "F16SAMPLER2DMS", "F16SAMPLER2DMSARRAY", + "F16SAMPLER1DSHADOW", "F16SAMPLER2DSHADOW", "F16SAMPLER1DARRAYSHADOW", + "F16SAMPLER2DARRAYSHADOW", "F16SAMPLER2DRECTSHADOW", + "F16SAMPLERCUBESHADOW", "F16SAMPLERCUBEARRAYSHADOW", "SAMPLER", + "SAMPLERSHADOW", "TEXTURE1D", "TEXTURE2D", "TEXTURE3D", "TEXTURECUBE", + "TEXTURE1DARRAY", "TEXTURE2DARRAY", "ITEXTURE1D", "ITEXTURE2D", + "ITEXTURE3D", "ITEXTURECUBE", "ITEXTURE1DARRAY", "ITEXTURE2DARRAY", + "UTEXTURE1D", "UTEXTURE2D", "UTEXTURE3D", "UTEXTURECUBE", + "UTEXTURE1DARRAY", "UTEXTURE2DARRAY", "TEXTURE2DRECT", "ITEXTURE2DRECT", + "UTEXTURE2DRECT", "TEXTUREBUFFER", "ITEXTUREBUFFER", "UTEXTUREBUFFER", + "TEXTURECUBEARRAY", "ITEXTURECUBEARRAY", "UTEXTURECUBEARRAY", + "TEXTURE2DMS", "ITEXTURE2DMS", "UTEXTURE2DMS", "TEXTURE2DMSARRAY", + "ITEXTURE2DMSARRAY", "UTEXTURE2DMSARRAY", "F16TEXTURE1D", "F16TEXTURE2D", + "F16TEXTURE3D", "F16TEXTURE2DRECT", "F16TEXTURECUBE", + "F16TEXTURE1DARRAY", "F16TEXTURE2DARRAY", "F16TEXTURECUBEARRAY", + "F16TEXTUREBUFFER", "F16TEXTURE2DMS", "F16TEXTURE2DMSARRAY", "SUBPASSINPUT", "SUBPASSINPUTMS", "ISUBPASSINPUT", "ISUBPASSINPUTMS", - "USUBPASSINPUT", "USUBPASSINPUTMS", "IMAGE1D", "IIMAGE1D", "UIMAGE1D", - "IMAGE2D", "IIMAGE2D", "UIMAGE2D", "IMAGE3D", "IIMAGE3D", "UIMAGE3D", - "IMAGE2DRECT", "IIMAGE2DRECT", "UIMAGE2DRECT", "IMAGECUBE", "IIMAGECUBE", - "UIMAGECUBE", "IMAGEBUFFER", "IIMAGEBUFFER", "UIMAGEBUFFER", - "IMAGE1DARRAY", "IIMAGE1DARRAY", "UIMAGE1DARRAY", "IMAGE2DARRAY", - "IIMAGE2DARRAY", "UIMAGE2DARRAY", "IMAGECUBEARRAY", "IIMAGECUBEARRAY", - "UIMAGECUBEARRAY", "IMAGE2DMS", "IIMAGE2DMS", "UIMAGE2DMS", - "IMAGE2DMSARRAY", "IIMAGE2DMSARRAY", "UIMAGE2DMSARRAY", "STRUCT", "VOID", - "WHILE", "IDENTIFIER", "TYPE_NAME", "FLOATCONSTANT", "DOUBLECONSTANT", - "INTCONSTANT", "UINTCONSTANT", "INT64CONSTANT", "UINT64CONSTANT", - "BOOLCONSTANT", "LEFT_OP", "RIGHT_OP", "INC_OP", "DEC_OP", "LE_OP", + "USUBPASSINPUT", "USUBPASSINPUTMS", "F16SUBPASSINPUT", + "F16SUBPASSINPUTMS", "IMAGE1D", "IIMAGE1D", "UIMAGE1D", "IMAGE2D", + "IIMAGE2D", "UIMAGE2D", "IMAGE3D", "IIMAGE3D", "UIMAGE3D", "IMAGE2DRECT", + "IIMAGE2DRECT", "UIMAGE2DRECT", "IMAGECUBE", "IIMAGECUBE", "UIMAGECUBE", + "IMAGEBUFFER", "IIMAGEBUFFER", "UIMAGEBUFFER", "IMAGE1DARRAY", + "IIMAGE1DARRAY", "UIMAGE1DARRAY", "IMAGE2DARRAY", "IIMAGE2DARRAY", + "UIMAGE2DARRAY", "IMAGECUBEARRAY", "IIMAGECUBEARRAY", "UIMAGECUBEARRAY", + "IMAGE2DMS", "IIMAGE2DMS", "UIMAGE2DMS", "IMAGE2DMSARRAY", + "IIMAGE2DMSARRAY", "UIMAGE2DMSARRAY", "F16IMAGE1D", "F16IMAGE2D", + "F16IMAGE3D", "F16IMAGE2DRECT", "F16IMAGECUBE", "F16IMAGE1DARRAY", + "F16IMAGE2DARRAY", "F16IMAGECUBEARRAY", "F16IMAGEBUFFER", "F16IMAGE2DMS", + "F16IMAGE2DMSARRAY", "STRUCT", "VOID", "WHILE", "IDENTIFIER", + "TYPE_NAME", "FLOATCONSTANT", "DOUBLECONSTANT", "INT16CONSTANT", + "UINT16CONSTANT", "INT32CONSTANT", "UINT32CONSTANT", "INTCONSTANT", + "UINTCONSTANT", "INT64CONSTANT", "UINT64CONSTANT", "BOOLCONSTANT", + "FLOAT16CONSTANT", "LEFT_OP", "RIGHT_OP", "INC_OP", "DEC_OP", "LE_OP", "GE_OP", "EQ_OP", "NE_OP", "AND_OP", "OR_OP", "XOR_OP", "MUL_ASSIGN", "DIV_ASSIGN", "ADD_ASSIGN", "MOD_ASSIGN", "LEFT_ASSIGN", "RIGHT_ASSIGN", "AND_ASSIGN", "XOR_ASSIGN", "OR_ASSIGN", "SUB_ASSIGN", "LEFT_PAREN", @@ -910,20 +1065,24 @@ static const char *const yytname[] = "fully_specified_type", "invariant_qualifier", "interpolation_qualifier", "layout_qualifier", "layout_qualifier_id_list", "layout_qualifier_id", "precise_qualifier", "type_qualifier", "single_type_qualifier", - "storage_qualifier", "type_name_list", "type_specifier", - "array_specifier", "type_specifier_nonarray", "precision_qualifier", - "struct_specifier", "$@3", "$@4", "struct_declaration_list", - "struct_declaration", "struct_declarator_list", "struct_declarator", - "initializer", "initializer_list", "declaration_statement", "statement", + "storage_qualifier", "non_uniform_qualifier", "type_name_list", + "type_specifier", "array_specifier", "type_specifier_nonarray", + "precision_qualifier", "struct_specifier", "$@3", "$@4", + "struct_declaration_list", "struct_declaration", + "struct_declarator_list", "struct_declarator", "initializer", + "initializer_list", "declaration_statement", "statement", "simple_statement", "compound_statement", "$@5", "$@6", "statement_no_new_scope", "statement_scoped", "$@7", "$@8", "compound_statement_no_new_scope", "statement_list", "expression_statement", "selection_statement", - "selection_rest_statement", "condition", "switch_statement", "$@9", - "switch_statement_list", "case_label", "iteration_statement", "$@10", - "$@11", "$@12", "for_init_statement", "conditionopt", - "for_rest_statement", "jump_statement", "translation_unit", - "external_declaration", "function_definition", "$@13", YY_NULLPTR + "selection_statement_nonattributed", "selection_rest_statement", + "condition", "switch_statement", "switch_statement_nonattributed", "$@9", + "switch_statement_list", "case_label", "iteration_statement", + "iteration_statement_nonattributed", "$@10", "$@11", "$@12", + "for_init_statement", "conditionopt", "for_rest_statement", + "jump_statement", "translation_unit", "external_declaration", + "function_definition", "$@13", "attribute", "attribute_list", + "single_attribute", YY_NULL }; #endif @@ -958,16 +1117,29 @@ static const yytype_uint16 yytoknum[] = 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 521, 522, 523, 524 + 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, + 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, + 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, + 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, + 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, + 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, + 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, + 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, + 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, + 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, + 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, + 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, + 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, + 645 }; # endif -#define YYPACT_NINF -496 +#define YYPACT_NINF -634 #define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-496))) + (!!((Yystate) == (-634))) -#define YYTABLE_NINF -379 +#define YYTABLE_NINF -502 #define yytable_value_is_error(Yytable_value) \ 0 @@ -976,62 +1148,76 @@ static const yytype_uint16 yytoknum[] = STATE-NUM. */ static const yytype_int16 yypact[] = { - 2394, -496, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -199, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -496, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -496, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -496, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -496, -496, -496, -496, -496, -187, -496, -496, -496, - -496, -496, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -496, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -496, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -496, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -496, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -496, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -496, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -496, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -496, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -496, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -496, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -496, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -496, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -180, -496, -496, -496, -496, -496, -496, -496, -134, - -496, -191, -181, -155, -131, 3871, -133, -496, -69, -496, - -496, -496, -496, 2900, -496, -496, -496, -92, -496, -496, - 546, -496, -496, -68, -45, -91, -496, 5735, -200, -496, - -496, -85, -496, 3871, -496, -496, -496, 3871, -50, -49, - -496, -209, -193, -496, -496, -496, 4323, -80, -496, -496, - -496, -202, -496, -86, -171, -496, -496, 3871, -84, -496, - -198, 810, -496, -496, -496, -496, -92, -214, -496, 4558, - -176, -496, -46, -496, -127, -496, -496, -496, -496, -496, - -496, -496, -496, 5271, 5271, 5271, -496, -496, -496, -496, - -496, -496, -496, -175, -496, -496, -496, -73, -169, 5503, - -71, -496, 5271, -118, -170, -195, -197, -90, -89, -87, - -88, -57, -58, -208, -67, -496, 4804, -496, -36, 5271, - -496, -45, 3871, 3871, -33, 3145, -496, -496, -496, -72, - -70, -496, -61, -59, -66, 5039, -55, 5271, -62, -51, - -54, -496, -496, -141, -496, -496, -125, -496, -181, -48, - -496, -496, -496, -496, 1074, -496, -496, -496, -496, -496, - -496, -80, 4558, -174, 4558, -496, -496, 4558, 3871, -496, - -23, -496, -496, -496, -167, -496, -496, 5271, -20, -496, - -496, 5271, -43, -496, -496, -496, 5271, 5271, 5271, 5271, - 5271, 5271, 5271, 5271, 5271, 5271, 5271, 5271, 5271, 5271, - 5271, 5271, 5271, 5271, 5271, -496, -496, -496, -44, -496, - -496, -496, -496, 3387, -33, -92, -121, -496, -496, -496, - -496, -496, 1338, -496, 5271, -496, -496, -120, 5271, -102, - -496, -496, -496, 1338, -496, -496, -496, -496, -496, -496, - -496, -496, -496, -496, -496, 5271, 5271, -496, -496, -496, - -496, 4558, -496, -105, -496, 3629, -496, -496, -42, -52, - -496, -496, -496, -496, -496, -118, -118, -170, -170, -195, - -195, -195, -195, -197, -197, -90, -89, -87, -88, -57, - -58, 5271, -496, -496, -119, -80, -33, -496, -16, 2130, - -164, -496, -160, -496, 2637, 1338, -496, -496, -496, -496, - 4077, -496, -496, -99, -496, -496, -40, -496, -496, 2637, - -41, -496, -52, -8, 3871, -35, -38, -496, -496, 5271, - 5271, -496, -39, -32, 191, -31, 1866, -496, -30, -34, - 1602, -496, -496, -138, 5271, 1602, -41, -496, -496, 1338, - 4558, -496, -496, -496, -29, -52, -496, -496, 1338, -27, - -496, -496, -496 + 3391, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -311, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -295, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, -634, -301, -634, -634, + -634, -634, -634, -634, -634, -634, -241, -634, -302, -342, + -290, -254, 5696, -300, -634, -210, -634, -634, -634, -634, + 4160, -634, -634, -634, -634, -219, -634, -634, 696, -634, + -634, -189, -69, -207, -634, 8625, -320, -634, -634, -203, + -634, 5696, -634, -634, -634, 5696, -155, -154, -634, -324, + -288, -634, -634, -634, 6417, -190, -634, -634, -634, -292, + -634, -196, -287, -634, -634, 5696, -195, -634, -306, 1081, + -634, -634, -634, -634, -219, -325, -634, 6785, -310, -634, + -151, -634, -277, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, 7889, 7889, 7889, -634, + -634, -634, -634, -634, -634, -634, -309, -634, -634, -634, + -185, -283, 8257, -183, -634, 7889, -227, -263, -299, -318, + -194, -204, -202, -200, -165, -166, -321, -179, -634, -634, + 7153, -634, -140, 7889, -634, -69, 5696, 5696, -139, 4544, + -634, -634, -634, -182, -180, -634, -173, -169, -178, 7521, + -164, 7889, -174, -163, -167, -162, -634, -634, -252, -634, + -634, -237, -634, -342, -161, -158, -634, -634, -634, -634, + 1466, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -19, -190, 6785, -296, 6785, -634, -634, 6785, 5696, -634, + -127, -634, -634, -634, -278, -634, -634, 7889, -121, -634, + -634, 7889, -156, -634, -634, -634, 7889, 7889, 7889, 7889, + 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, + 7889, 7889, 7889, 7889, 7889, -634, -634, -634, -157, -634, + -634, -634, -634, 4928, -139, -219, -236, -634, -634, -634, + -634, -634, 1851, -634, 7889, -634, -634, -230, 7889, -213, + -634, -634, -118, -634, 1851, -634, -634, -634, -634, -634, + -634, -634, -634, -634, -634, -634, 7889, 7889, -634, -634, + -634, -634, -634, -634, -634, 6785, -634, -270, -634, 5312, + -634, -634, -153, -150, -634, -634, -634, -634, -634, -227, + -227, -263, -263, -299, -299, -299, -299, -318, -318, -194, + -204, -202, -200, -165, -166, 7889, -634, -634, -226, -190, + -139, -634, -113, 3006, -275, -634, -253, -634, 3776, -148, + -282, -634, 1851, -634, -634, -634, -634, 6049, -634, -634, + -208, -634, -634, -147, -634, -634, 3776, -146, -634, -150, + -111, 5696, -145, 7889, -144, -118, -143, -634, -634, 7889, + 7889, -634, -149, -141, 196, -136, 2621, -634, -116, -120, + 2236, -137, -634, -634, -634, -634, -239, 7889, 2236, -146, + -634, -634, 1851, 6785, -634, -634, -634, -634, -119, -150, + -634, -634, 1851, -112, -634, -634, -634 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -1039,92 +1225,108 @@ static const yytype_int16 yypact[] = means the default is an error. */ static const yytype_uint16 yydefact[] = { - 0, 145, 146, 144, 178, 172, 173, 174, 175, 176, - 177, 161, 185, 186, 187, 188, 189, 190, 191, 192, - 193, 194, 195, 196, 197, 198, 199, 179, 180, 181, - 200, 201, 202, 150, 148, 149, 147, 153, 151, 152, - 154, 155, 156, 157, 158, 159, 160, 182, 183, 184, - 212, 213, 214, 128, 127, 126, 0, 203, 204, 205, - 206, 207, 208, 209, 210, 211, 215, 216, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, 232, 233, 234, 235, 238, 239, 240, - 241, 242, 243, 245, 246, 247, 248, 249, 250, 252, - 253, 254, 255, 256, 257, 258, 236, 237, 244, 251, - 259, 260, 261, 262, 263, 264, 333, 265, 266, 267, - 268, 269, 270, 271, 272, 274, 275, 276, 277, 278, - 279, 281, 282, 283, 284, 285, 286, 288, 289, 290, - 291, 292, 293, 273, 280, 287, 294, 295, 296, 297, - 298, 299, 334, 335, 336, 337, 338, 339, 300, 301, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, - 332, 0, 171, 341, 125, 135, 342, 343, 344, 0, - 419, 0, 420, 0, 102, 101, 0, 113, 118, 142, - 141, 139, 143, 0, 136, 138, 123, 165, 140, 340, - 0, 416, 418, 0, 0, 0, 347, 0, 0, 90, - 87, 0, 100, 0, 109, 103, 111, 0, 112, 0, - 88, 119, 0, 93, 137, 124, 0, 166, 1, 417, - 163, 0, 134, 132, 0, 130, 345, 0, 0, 91, - 0, 0, 421, 104, 108, 110, 106, 114, 105, 0, - 120, 96, 0, 94, 0, 2, 8, 9, 4, 5, - 6, 7, 10, 0, 0, 0, 167, 36, 35, 37, - 34, 3, 12, 30, 14, 19, 20, 0, 0, 24, - 0, 38, 0, 42, 45, 48, 53, 56, 58, 60, - 62, 64, 66, 68, 0, 28, 0, 162, 0, 0, - 129, 0, 0, 0, 0, 0, 349, 89, 92, 0, - 0, 401, 0, 0, 0, 0, 0, 0, 0, 0, - 373, 382, 386, 38, 71, 84, 0, 362, 0, 123, - 365, 384, 364, 363, 0, 366, 367, 368, 369, 370, - 371, 107, 0, 115, 0, 357, 122, 0, 0, 98, - 0, 95, 31, 32, 0, 16, 17, 0, 0, 22, - 21, 0, 171, 25, 27, 33, 0, 0, 0, 0, + 0, 153, 154, 183, 181, 184, 182, 185, 152, 196, + 186, 187, 194, 195, 192, 193, 190, 191, 188, 189, + 169, 212, 213, 214, 215, 216, 217, 230, 231, 232, + 227, 228, 229, 242, 243, 244, 224, 225, 226, 239, + 240, 241, 221, 222, 223, 236, 237, 238, 218, 219, + 220, 233, 234, 235, 197, 198, 199, 245, 246, 247, + 158, 156, 157, 155, 161, 159, 160, 162, 163, 171, + 164, 165, 166, 167, 168, 200, 201, 202, 257, 258, + 259, 203, 204, 205, 269, 270, 271, 206, 207, 208, + 281, 282, 283, 209, 210, 211, 293, 294, 295, 134, + 133, 132, 0, 135, 248, 249, 250, 251, 252, 253, + 254, 255, 256, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 272, 273, 274, 275, 276, 277, 278, 279, + 280, 284, 285, 286, 287, 288, 289, 290, 291, 292, + 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 332, 333, 334, 335, 336, 337, 339, 340, 341, + 342, 343, 344, 346, 347, 350, 351, 352, 354, 355, + 317, 318, 338, 345, 356, 358, 359, 360, 362, 363, + 454, 319, 320, 321, 348, 322, 326, 327, 330, 353, + 357, 361, 323, 324, 328, 329, 349, 325, 331, 364, + 365, 366, 368, 370, 372, 374, 376, 380, 381, 382, + 383, 384, 385, 387, 388, 389, 390, 391, 392, 394, + 396, 397, 398, 400, 401, 378, 386, 393, 402, 404, + 405, 406, 408, 409, 367, 369, 371, 395, 373, 375, + 377, 379, 399, 403, 407, 455, 456, 459, 460, 461, + 462, 457, 458, 410, 412, 413, 414, 416, 417, 418, + 420, 421, 422, 424, 425, 426, 428, 429, 430, 432, + 433, 434, 436, 437, 438, 440, 441, 442, 444, 445, + 446, 448, 449, 450, 452, 453, 411, 415, 419, 423, + 427, 435, 439, 443, 431, 447, 451, 0, 180, 464, + 549, 131, 142, 465, 466, 467, 0, 548, 0, 550, + 0, 108, 107, 0, 119, 124, 149, 148, 146, 150, + 0, 143, 145, 151, 129, 174, 147, 463, 0, 545, + 547, 0, 0, 0, 470, 0, 0, 96, 93, 0, + 106, 0, 115, 109, 117, 0, 118, 0, 94, 125, + 0, 99, 144, 130, 0, 175, 1, 546, 172, 0, + 141, 139, 0, 137, 468, 0, 0, 97, 0, 0, + 551, 110, 114, 116, 112, 120, 111, 0, 126, 102, + 0, 100, 0, 2, 12, 13, 10, 11, 4, 5, + 6, 7, 8, 9, 15, 14, 0, 0, 0, 176, + 42, 41, 43, 40, 3, 17, 36, 19, 24, 25, + 0, 0, 29, 0, 44, 0, 48, 51, 54, 59, + 62, 64, 66, 68, 70, 72, 74, 0, 35, 33, + 0, 170, 0, 0, 136, 0, 0, 0, 0, 0, + 472, 95, 98, 0, 0, 530, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 496, 505, 509, 44, 77, + 90, 0, 485, 0, 151, 129, 488, 507, 487, 486, + 0, 489, 490, 511, 491, 518, 492, 493, 526, 494, + 0, 113, 0, 121, 0, 480, 128, 0, 0, 104, + 0, 101, 37, 38, 0, 21, 22, 0, 0, 27, + 26, 0, 180, 30, 32, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 69, 168, 169, 0, 164, - 86, 133, 131, 0, 0, 355, 0, 353, 348, 350, - 412, 411, 0, 403, 0, 415, 413, 0, 0, 0, - 398, 399, 372, 0, 74, 75, 77, 76, 79, 80, - 81, 82, 83, 78, 73, 0, 0, 387, 383, 385, - 117, 0, 360, 0, 121, 0, 99, 11, 0, 18, - 15, 26, 39, 40, 41, 44, 43, 46, 47, 51, - 52, 49, 50, 54, 55, 57, 59, 61, 63, 65, - 67, 0, 170, 346, 0, 356, 0, 351, 0, 0, - 0, 414, 0, 397, 0, 374, 72, 85, 116, 358, - 0, 97, 13, 0, 352, 354, 0, 406, 405, 408, - 380, 393, 391, 0, 0, 0, 0, 359, 361, 0, - 0, 407, 0, 0, 390, 0, 0, 388, 0, 0, - 0, 375, 70, 0, 409, 0, 380, 379, 381, 395, - 0, 377, 400, 376, 0, 410, 404, 389, 396, 0, - 392, 402, 394 + 0, 0, 0, 0, 0, 75, 177, 178, 0, 173, + 92, 140, 138, 0, 0, 478, 0, 476, 471, 473, + 541, 540, 0, 532, 0, 544, 542, 0, 0, 0, + 525, 528, 0, 495, 0, 80, 81, 83, 82, 85, + 86, 87, 88, 89, 84, 79, 0, 0, 510, 506, + 508, 512, 519, 527, 123, 0, 483, 0, 127, 0, + 105, 16, 0, 23, 20, 31, 45, 46, 47, 50, + 49, 52, 53, 57, 58, 55, 56, 60, 61, 63, + 65, 67, 69, 71, 73, 0, 179, 469, 0, 479, + 0, 474, 0, 0, 0, 543, 0, 524, 0, 555, + 0, 553, 497, 78, 91, 122, 481, 0, 103, 18, + 0, 475, 477, 0, 535, 534, 537, 503, 520, 516, + 0, 0, 0, 0, 0, 0, 0, 482, 484, 0, + 0, 536, 0, 0, 515, 0, 0, 513, 0, 0, + 0, 0, 552, 554, 498, 76, 0, 538, 0, 503, + 502, 504, 522, 0, 500, 529, 499, 556, 0, 539, + 533, 514, 523, 0, 517, 531, 521 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -496, -496, -496, -496, -496, -496, -496, -496, -496, -496, - -496, -496, -53, -496, -237, -288, -286, -243, -183, -179, - -184, -177, -168, -185, -496, -234, -496, -266, -496, -280, - -496, 4, -496, -496, -496, 6, -496, -496, -496, -15, - -10, -9, -496, -496, -475, -496, -496, -496, -496, -83, - -496, -204, -211, -496, -496, 0, -221, -496, 33, -496, - -496, -496, -308, -314, -178, -247, -349, -496, -248, -346, - -495, -283, -496, -496, -292, -291, -496, -496, 13, -423, - -242, -496, -496, -263, -496, -496, -496, -496, -496, -496, - -496, -496, -496, -496, -496, -496, -496, 28, -496, -496 + -634, -634, -634, -634, -634, -634, -634, -634, -634, -634, + -634, -634, -289, -634, -358, -355, -401, -364, -279, -307, + -276, -280, -273, -281, -634, -354, -634, -378, -634, -367, + -397, 1, -634, -634, -634, 2, -634, -634, -634, -98, + -93, -92, -634, -634, -600, -634, -634, -634, -634, -181, + -634, -319, -326, -634, 6, -634, 0, -332, -634, -54, + -634, -634, -634, -428, -433, -272, -353, -477, -634, -357, + -467, -633, -400, -634, -634, -410, -408, -634, -634, -80, + -545, -350, -634, -216, -634, -371, -634, -214, -634, -634, + -634, -634, -212, -634, -634, -634, -634, -634, -634, -634, + -634, -61, -634, -634, -634, -634, -375 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 291, 292, 293, 458, 294, 295, 296, 297, 298, - 299, 300, 343, 302, 303, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 344, 481, 345, 445, 346, - 411, 347, 201, 368, 274, 348, 203, 204, 205, 234, - 235, 236, 206, 207, 208, 209, 210, 211, 254, 255, - 212, 213, 214, 215, 251, 315, 247, 217, 218, 219, - 322, 257, 325, 326, 416, 417, 366, 453, 350, 351, - 352, 353, 433, 516, 542, 524, 525, 526, 543, 354, - 355, 356, 527, 515, 357, 528, 549, 358, 359, 494, - 422, 489, 509, 522, 523, 360, 220, 221, 222, 231 + -1, 414, 415, 416, 592, 417, 418, 419, 420, 421, + 422, 423, 468, 425, 426, 427, 428, 429, 430, 431, + 432, 433, 434, 435, 436, 469, 615, 470, 576, 471, + 541, 472, 318, 498, 392, 473, 320, 321, 322, 352, + 353, 354, 323, 324, 325, 326, 327, 328, 372, 373, + 329, 330, 331, 332, 438, 369, 439, 365, 335, 336, + 337, 446, 375, 449, 450, 546, 547, 496, 587, 476, + 477, 478, 479, 564, 656, 685, 664, 665, 666, 686, + 480, 481, 482, 483, 667, 652, 484, 485, 668, 693, + 486, 487, 488, 628, 552, 623, 646, 662, 663, 489, + 338, 339, 340, 349, 490, 630, 631 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If @@ -1132,64 +1334,79 @@ static const yytype_int16 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { - 216, 237, 244, 365, 200, 374, 202, 260, 449, 252, - 495, 419, 314, 450, 413, 452, 228, 404, 454, 513, - 270, 391, 392, 393, 394, 246, 244, 225, 268, 237, - 246, 538, 362, 383, 513, 541, 317, 269, 223, 246, - 541, 316, 318, 375, 376, 361, 363, 259, 271, 328, - 224, 272, 405, 323, 273, 427, 229, 429, 395, 396, - 455, 226, -29, 316, 377, 316, 230, 320, 378, 380, - 367, 457, 451, 321, 510, 381, 488, 446, 511, 389, - 446, 390, 408, 232, 446, 410, 434, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 365, 459, 365, 419, - 544, 365, 498, 467, 468, 444, 446, 469, 470, 471, - 472, 239, 244, 233, 240, 461, 548, 370, 323, 446, - 371, 323, 447, 486, 446, 486, 487, 491, 504, 196, - 197, 198, 397, 398, 386, 387, 388, 499, 241, 500, - 250, 419, 446, 493, 490, 446, 519, 246, 492, 449, - 256, 518, 465, 466, 473, 474, 261, 266, 267, 316, - 319, 369, 253, 327, 323, 379, 384, 402, 403, 401, - 399, 400, 409, 406, 415, 420, 423, 421, 424, 496, - 497, 425, 428, 430, 456, 365, 431, 460, 432, -28, - 506, 550, 446, 301, 485, -23, 482, 520, 502, 529, - -378, 503, 449, 530, 531, 238, 535, 536, 534, 323, - 340, 539, 540, 245, 512, 552, 475, 477, 551, 480, - 216, 476, 264, 263, 200, 478, 202, 258, 265, 512, - 372, 373, 227, 238, 365, 479, 484, 238, 412, 505, - 533, 507, 537, 546, 262, 547, 521, 508, 249, 385, - 0, 323, 0, 532, 545, 0, 0, 324, 0, 0, - 0, 349, 0, 301, 0, 0, 301, 0, 0, 0, - 0, 0, 0, 0, 365, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 244, 0, 514, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 324, 414, 0, 324, 0, 0, 0, 0, - 0, 0, 0, 462, 463, 464, 301, 301, 301, 301, - 301, 301, 301, 301, 301, 301, 301, 301, 301, 301, - 301, 301, 0, 0, 349, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 324, 0, + 334, 317, 319, 355, 362, 455, 333, 456, 457, 495, + 437, 460, 370, 580, 378, 584, 549, 586, 543, 632, + 588, 346, 343, 523, 524, 534, 348, 388, 650, 362, + 505, 506, 355, 681, 386, 364, 364, 684, 521, 522, + 364, 504, 492, 387, 513, 684, 650, 341, 377, -34, + 440, 507, 491, 493, 440, 508, 447, 497, 525, 526, + 535, 344, 452, 342, 440, 357, 347, 441, 358, 350, + 589, 585, 444, 442, 389, 424, 510, 390, 445, 654, + 391, 591, 511, 655, 647, 622, 538, 577, 500, 540, + 577, 501, 557, 636, 559, 637, 565, 566, 567, 568, + 569, 570, 571, 572, 573, 574, 648, 519, 635, 520, + 549, 351, 577, 359, 495, 575, 495, 502, 503, 495, + 688, 362, 603, 604, 605, 606, 577, 447, 577, 620, + 447, 578, 621, 595, 368, 577, 515, 692, 625, 620, + 593, 364, 641, 313, 314, 315, 516, 517, 518, 527, + 528, 424, 577, 627, 424, 374, 549, 577, 659, 379, + 658, 599, 600, 607, 608, 580, 601, 602, 384, 385, + 440, 443, 499, 451, 509, 514, 529, 530, 531, 447, + 532, 533, 536, 539, 545, 553, 550, 624, 551, 554, + 555, 626, 560, 562, 558, 561, 590, -35, 633, 634, + -33, 563, 594, -28, 616, 629, 694, 495, 639, 643, + 653, 660, 669, 619, 670, 577, -501, 672, 678, 677, + 674, 679, 687, 610, 447, 580, 465, 596, 597, 598, + 424, 424, 424, 424, 424, 424, 424, 424, 424, 424, + 424, 424, 424, 424, 424, 424, 682, 683, 640, 695, + 609, 696, 612, 614, 371, 611, 671, 382, 381, 495, + 613, 649, 345, 383, 542, 680, 644, 642, 690, 380, + 447, 691, 618, 645, 581, 661, 582, 367, 583, 649, + 673, 675, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 676, 0, 0, 0, 0, 0, 540, + 0, 0, 0, 463, 0, 495, 0, 0, 0, 651, + 689, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 356, 0, 0, 362, 0, 651, 333, 0, + 363, 0, 0, 0, 0, 0, 333, 0, 334, 317, + 319, 0, 0, 0, 333, 376, 0, 0, 0, 0, + 0, 356, 0, 0, 0, 356, 0, 333, 0, 0, + 0, 333, 0, 0, 424, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 448, 0, 0, 0, 475, + 0, 333, 0, 0, 0, 474, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 324, 0, 0, 0, 0, 0, 0, - 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 324, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 448, 544, 0, 448, + 0, 0, 333, 333, 0, 333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 349, - 0, 0, 0, 0, 349, 349, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 349, - 0, 0, 0, 0, 245, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 349, 0, 0, 0, - 349, 0, 0, 0, 0, 349, 0, 0, 0, 349, - 0, 0, 0, 0, 0, 0, 248, 0, 349, 1, - 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, + 475, 0, 0, 0, 0, 0, 474, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 448, 0, + 0, 0, 0, 0, 333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 448, 0, 0, 0, 0, 0, 333, + 0, 0, 475, 0, 0, 0, 0, 0, 474, 0, + 0, 0, 0, 0, 475, 0, 0, 0, 0, 0, + 474, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 448, + 0, 0, 0, 0, 0, 333, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 475, 0, 0, 0, 0, 475, 474, + 0, 0, 475, 0, 474, 0, 0, 0, 474, 0, + 0, 0, 0, 0, 0, 0, 475, 0, 0, 0, + 0, 363, 474, 0, 0, 0, 0, 333, 0, 0, + 0, 0, 0, 0, 0, 0, 475, 0, 0, 0, + 475, 0, 474, 0, 0, 0, 474, 0, 475, 0, + 0, 0, 475, 0, 474, 0, 0, 0, 474, 0, + 0, 0, 475, 0, 0, 0, 366, 0, 474, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, @@ -1207,640 +1424,28 @@ static const yytype_int16 yytable[] = 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192, 0, 0, 193, 0, 0, 0, 0, 0, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 0, 0, + 309, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 194, 195, 196, - 197, 198, 199, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 329, 330, 331, 0, 332, 333, 334, - 335, 336, 337, 338, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 339, 275, 193, 276, - 277, 278, 279, 280, 281, 282, 0, 0, 283, 284, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 285, 0, 0, - 0, 340, 341, 0, 0, 0, 0, 342, 287, 288, - 289, 290, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 194, 195, 196, 197, 198, 199, 1, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 329, 330, 331, - 0, 332, 333, 334, 335, 336, 337, 338, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, - 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, - 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, - 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, - 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, - 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, - 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, - 339, 275, 193, 276, 277, 278, 279, 280, 281, 282, - 0, 0, 283, 284, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 285, 0, 0, 0, 340, 448, 0, 0, 0, - 0, 342, 287, 288, 289, 290, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 194, 195, 196, 197, 198, - 199, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 329, 330, 331, 0, 332, 333, 334, 335, 336, - 337, 338, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 339, 275, 193, 276, 277, 278, - 279, 280, 281, 282, 0, 0, 283, 284, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 285, 0, 0, 0, 340, - 0, 0, 0, 0, 0, 342, 287, 288, 289, 290, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 194, - 195, 196, 197, 198, 199, 1, 2, 3, 4, 5, - 6, 7, 8, 9, 10, 329, 330, 331, 0, 332, - 333, 334, 335, 336, 337, 338, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, - 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, - 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, - 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, - 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, - 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, - 185, 186, 187, 188, 189, 190, 191, 192, 339, 275, - 193, 276, 277, 278, 279, 280, 281, 282, 0, 0, - 283, 284, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 285, - 0, 0, 0, 261, 0, 0, 0, 0, 0, 342, - 287, 288, 289, 290, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 194, 195, 196, 197, 198, 199, 1, - 2, 3, 4, 5, 6, 7, 8, 9, 10, 329, - 330, 331, 0, 332, 333, 334, 335, 336, 337, 338, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192, 339, 275, 193, 276, 277, 278, 279, 280, - 281, 282, 0, 0, 283, 284, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 285, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 342, 287, 288, 289, 290, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 194, 195, 196, - 197, 198, 199, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 0, 275, 193, 276, - 277, 278, 279, 280, 281, 282, 0, 0, 283, 284, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 285, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 342, 287, 288, - 289, 290, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 194, 195, 196, 197, 198, 199, 1, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, - 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, - 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, - 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, - 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, - 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, - 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, - 0, 0, 193, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 0, 0, 0, 0, 0, 194, 195, 196, 197, 198, - 199, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 0, 275, 193, 276, 277, 278, 279, - 280, 281, 282, 0, 0, 283, 284, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 285, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 287, 288, 289, 290, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 194, 195, - 196, 197, 198, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 0, 242, 193, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 243, 1, 2, - 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, - 0, 194, 195, 196, 197, 198, 0, 0, 0, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 0, 0, 193, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 418, 0, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 0, 0, 0, 0, 0, 0, 194, 195, 196, 197, - 198, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 0, 0, 193, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 483, - 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, - 9, 10, 0, 0, 0, 0, 0, 0, 194, 195, - 196, 197, 198, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, - 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, - 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, - 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 0, 0, 193, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 501, 0, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 0, 0, 0, 0, 0, 0, - 194, 195, 196, 197, 198, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 0, 0, 193, - 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 194, 195, 196, 197, 198, 47, 48, 49, - 50, 51, 52, 0, 0, 0, 0, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 0, 275, 193, 276, 277, 278, 279, - 280, 281, 282, 0, 0, 283, 284, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 285, 0, 0, 0, 364, 517, - 0, 0, 0, 0, 0, 287, 288, 289, 290, 4, - 5, 6, 7, 8, 9, 10, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 47, 48, 49, 50, 51, 52, 0, - 0, 0, 0, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, - 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, - 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, - 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, - 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 192, 0, - 275, 193, 276, 277, 278, 279, 280, 281, 282, 0, - 0, 283, 284, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 285, 0, 0, 286, 4, 5, 6, 7, 8, 9, - 10, 287, 288, 289, 290, 0, 0, 0, 0, 0, - 0, 0, 0, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 47, 48, - 49, 50, 51, 52, 0, 0, 0, 0, 57, 58, - 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 0, 275, 193, 276, 277, 278, - 279, 280, 281, 282, 0, 0, 283, 284, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 285, 0, 0, 0, 364, - 0, 0, 0, 0, 0, 0, 287, 288, 289, 290, - 4, 5, 6, 7, 8, 9, 10, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 47, 48, 49, 50, 51, 52, - 0, 0, 0, 0, 57, 58, 59, 60, 61, 62, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, - 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, - 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, - 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, - 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, - 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, - 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, - 0, 275, 193, 276, 277, 278, 279, 280, 281, 282, - 0, 0, 283, 284, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 285, 0, 0, 407, 4, 5, 6, 7, 8, - 9, 10, 287, 288, 289, 290, 0, 0, 0, 0, - 0, 0, 0, 0, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, - 48, 49, 50, 51, 52, 0, 0, 0, 0, 57, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, - 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, - 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, - 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 0, 275, 193, 276, 277, - 278, 279, 280, 281, 282, 0, 0, 283, 284, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 285, 4, 5, 6, - 7, 8, 9, 10, 0, 0, 426, 287, 288, 289, - 290, 0, 0, 0, 0, 0, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 47, 48, 49, 50, 51, 52, 0, 0, 0, - 0, 57, 58, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 0, 275, 193, - 276, 277, 278, 279, 280, 281, 282, 0, 0, 283, - 284, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 285, 4, - 5, 6, 7, 8, 9, 10, 0, 0, 0, 287, - 288, 289, 290, 0, 0, 0, 0, 0, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 47, 48, 49, 50, 51, 52, 0, - 0, 0, 0, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, - 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, - 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, - 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, - 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 382, 0, - 275, 193, 276, 277, 278, 279, 280, 281, 282, 0, - 0, 283, 284, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 285, 4, 5, 6, 7, 8, 9, 10, 0, 0, - 0, 287, 288, 289, 290, 0, 0, 0, 0, 0, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 47, 48, 49, 50, 51, - 52, 0, 0, 0, 0, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 0, 0, 193 -}; - -static const yytype_int16 yycheck[] = -{ - 0, 205, 213, 269, 0, 285, 0, 228, 354, 54, - 433, 325, 246, 362, 322, 364, 207, 225, 367, 494, - 241, 216, 217, 220, 221, 239, 237, 207, 237, 233, - 239, 526, 246, 299, 509, 530, 238, 246, 237, 239, - 535, 239, 244, 218, 219, 266, 267, 247, 241, 247, - 237, 244, 260, 257, 247, 335, 247, 337, 255, 256, - 368, 241, 237, 239, 239, 239, 247, 238, 243, 238, - 246, 238, 246, 244, 238, 244, 422, 244, 238, 249, - 244, 251, 316, 238, 244, 319, 227, 228, 229, 230, - 231, 232, 233, 234, 235, 236, 362, 377, 364, 413, - 238, 367, 451, 391, 392, 246, 244, 393, 394, 395, - 396, 244, 323, 244, 247, 381, 539, 244, 322, 244, - 247, 325, 247, 244, 244, 244, 247, 247, 247, 263, - 264, 265, 222, 223, 252, 253, 254, 242, 207, 244, - 208, 455, 244, 245, 424, 244, 245, 239, 428, 495, - 241, 500, 389, 390, 397, 398, 241, 207, 207, 239, - 246, 207, 207, 247, 368, 238, 237, 224, 226, 257, - 259, 258, 208, 240, 207, 247, 237, 247, 237, 445, - 446, 247, 237, 245, 207, 451, 237, 207, 242, 237, - 206, 540, 244, 246, 415, 238, 240, 237, 240, 207, - 241, 481, 548, 238, 242, 205, 238, 16, 247, 413, - 241, 241, 246, 213, 494, 242, 399, 401, 247, 404, - 220, 400, 237, 233, 220, 402, 220, 227, 237, 509, - 283, 284, 199, 233, 500, 403, 414, 237, 321, 486, - 520, 489, 525, 535, 231, 536, 509, 489, 220, 302, - -1, 455, -1, 519, 534, -1, -1, 257, -1, -1, - -1, 261, -1, 316, -1, -1, 319, -1, -1, -1, - -1, -1, -1, -1, 540, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 494, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 514, -1, 509, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 322, 323, -1, 325, -1, -1, -1, -1, - -1, -1, -1, 386, 387, 388, 389, 390, 391, 392, - 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, - 403, 404, -1, -1, 354, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 368, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 413, -1, -1, -1, -1, -1, -1, - -1, -1, 422, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 433, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 455, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 489, - -1, -1, -1, -1, 494, 495, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 509, - -1, -1, -1, -1, 514, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 526, -1, -1, -1, - 530, -1, -1, -1, -1, 535, -1, -1, -1, 539, - -1, -1, -1, -1, -1, -1, 0, -1, 548, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 12, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, - 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, - 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, - 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, - 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, - 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, - 204, 205, -1, -1, 208, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 261, 262, 263, - 264, 265, 266, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, -1, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, -1, -1, 218, 219, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 237, -1, -1, - -1, 241, 242, -1, -1, -1, -1, 247, 248, 249, - 250, 251, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 261, 262, 263, 264, 265, 266, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - -1, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 0, 0, 0, 0, 310, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 311, 312, + 313, 314, 315, 316, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 453, 454, 455, 0, 456, 457, 458, + 459, 460, 461, 462, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, @@ -1860,119 +1465,64 @@ static const yytype_int16 yycheck[] = 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, - -1, -1, 218, 219, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 237, -1, -1, -1, 241, 242, -1, -1, -1, - -1, 247, 248, 249, 250, 251, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 261, 262, 263, 264, 265, - 266, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, -1, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, - 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, - 212, 213, 214, 215, -1, -1, 218, 219, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 237, -1, -1, -1, 241, - -1, -1, -1, -1, -1, 247, 248, 249, 250, 251, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 261, - 262, 263, 264, 265, 266, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, -1, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, - 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, - 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, - 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, -1, -1, - 218, 219, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 237, - -1, -1, -1, 241, -1, -1, -1, -1, -1, 247, - 248, 249, 250, 251, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 261, 262, 263, 264, 265, 266, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, -1, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, - 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, - 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, - 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, - 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, - 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, - 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, - 214, 215, -1, -1, 218, 219, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 237, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 247, 248, 249, 250, 251, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 261, 262, 263, - 264, 265, 266, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, -1, 207, 208, 209, - 210, 211, 212, 213, 214, 215, -1, -1, 218, 219, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 237, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 247, 248, 249, - 250, 251, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 261, 262, 263, 264, 265, 266, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 24, 25, + 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, + 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, + 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, + 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, + 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, + 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 306, 307, 308, 463, 393, 309, 394, 395, 396, 397, + 398, 399, 400, 401, 402, 403, 404, 405, 0, 0, + 406, 407, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 408, + 0, 464, 0, 465, 466, 0, 0, 0, 0, 467, + 410, 411, 412, 413, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 311, 312, 313, 314, 315, 316, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 453, 454, + 455, 0, 456, 457, 458, 459, 460, 461, 462, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 463, 393, + 309, 394, 395, 396, 397, 398, 399, 400, 401, 402, + 403, 404, 405, 0, 0, 406, 407, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 408, 0, 464, 0, 465, 579, + 0, 0, 0, 0, 467, 410, 411, 412, 413, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 311, 312, + 313, 314, 315, 316, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 453, 454, 455, 0, 456, 457, 458, + 459, 460, 461, 462, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, @@ -1991,13 +1541,258 @@ static const yytype_int16 yycheck[] = 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, - -1, -1, 208, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - -1, -1, -1, -1, -1, 261, 262, 263, 264, 265, - 266, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, + 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, + 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, + 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, + 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, + 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 306, 307, 308, 463, 393, 309, 394, 395, 396, 397, + 398, 399, 400, 401, 402, 403, 404, 405, 0, 0, + 406, 407, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 408, + 0, 464, 0, 465, 0, 0, 0, 0, 0, 467, + 410, 411, 412, 413, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 311, 312, 313, 314, 315, 316, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 453, 454, + 455, 0, 456, 457, 458, 459, 460, 461, 462, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 463, 393, + 309, 394, 395, 396, 397, 398, 399, 400, 401, 402, + 403, 404, 405, 0, 0, 406, 407, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 408, 0, 464, 0, 379, 0, + 0, 0, 0, 0, 467, 410, 411, 412, 413, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 311, 312, + 313, 314, 315, 316, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 453, 454, 455, 0, 456, 457, 458, + 459, 460, 461, 462, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, + 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, + 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, + 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, + 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, + 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, + 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, + 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, + 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 306, 307, 308, 463, 393, 309, 394, 395, 396, 397, + 398, 399, 400, 401, 402, 403, 404, 405, 0, 0, + 406, 407, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 408, + 0, 464, 0, 0, 0, 0, 0, 0, 0, 467, + 410, 411, 412, 413, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 311, 312, 313, 314, 315, 316, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 0, 393, + 309, 394, 395, 396, 397, 398, 399, 400, 401, 402, + 403, 404, 405, 0, 0, 406, 407, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 408, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 467, 410, 411, 412, 413, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 311, 312, + 313, 314, 315, 316, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, + 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, + 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, + 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, + 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, + 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, + 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, + 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, + 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 306, 307, 308, 0, 0, 309, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 310, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 311, 312, 313, 314, 315, 316, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 0, 393, + 309, 394, 395, 396, 397, 398, 399, 400, 401, 402, + 403, 404, 405, 0, 0, 406, 407, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 408, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 410, 411, 412, 413, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 311, 312, + 313, 314, 315, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 0, 360, 309, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 361, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 311, 312, 313, 314, 315, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, @@ -2015,39 +1810,65 @@ static const yytype_int16 yycheck[] = 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, - 203, 204, 205, -1, 207, 208, 209, 210, 211, 212, - 213, 214, 215, -1, -1, 218, 219, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 237, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 248, 249, 250, 251, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 261, 262, - 263, 264, 265, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, -1, 207, 208, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 247, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, -1, -1, - -1, 261, 262, 263, 264, 265, -1, -1, -1, 24, + 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, + 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 308, 0, 0, 309, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 548, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 311, 312, 313, 314, + 315, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 0, 0, 309, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 617, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 311, 312, 313, 314, 315, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, @@ -2066,37 +1887,27 @@ static const yytype_int16 yycheck[] = 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, - 205, -1, -1, 208, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 242, -1, -1, - 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - -1, -1, -1, -1, -1, -1, 261, 262, 263, 264, - 265, 24, 25, 26, 27, 28, 29, 30, 31, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, - 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, - 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, - 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, - 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, - 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, - 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, - 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, - 203, 204, 205, -1, -1, 208, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 242, - -1, -1, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, -1, -1, -1, -1, -1, -1, 261, 262, - 263, 264, 265, 24, 25, 26, 27, 28, 29, 30, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 0, 0, 309, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 638, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 311, 312, 313, 314, 315, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, @@ -2114,13 +1925,425 @@ static const yytype_int16 yycheck[] = 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, -1, -1, 208, -1, -1, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 0, 0, + 309, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 4, 5, 6, 7, 0, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 0, 0, 0, 0, 0, 0, 0, 311, 312, + 313, 314, 315, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 69, 0, 0, 0, 0, 0, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 0, 0, 0, 0, 0, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, + 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, + 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, + 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, + 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, + 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, + 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, + 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, + 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, + 308, 0, 393, 309, 394, 395, 396, 397, 398, 399, + 400, 401, 402, 403, 404, 405, 0, 0, 406, 407, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 408, 0, 0, + 0, 494, 657, 0, 0, 0, 0, 0, 410, 411, + 412, 413, 3, 4, 5, 6, 7, 0, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, + 0, 0, 0, 0, 0, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 0, + 0, 0, 0, 0, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, + 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, + 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, + 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, + 300, 301, 302, 303, 304, 305, 306, 307, 308, 0, + 393, 309, 394, 395, 396, 397, 398, 399, 400, 401, + 402, 403, 404, 405, 0, 0, 406, 407, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 408, 0, 0, 409, 0, + 0, 0, 0, 0, 0, 0, 410, 411, 412, 413, + 3, 4, 5, 6, 7, 0, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, + 0, 0, 0, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 0, 0, 0, + 0, 0, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, + 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, + 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, + 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, + 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, + 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, + 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 307, 308, 0, 393, 309, + 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, + 404, 405, 0, 0, 406, 407, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 408, 0, 0, 0, 494, 0, 0, + 0, 0, 0, 0, 410, 411, 412, 413, 3, 4, + 5, 6, 7, 0, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, + 0, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 0, 0, 0, 0, 0, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, + 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, + 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, + 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, + 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, + 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, + 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, + 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, + 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 0, 393, 309, 394, 395, + 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, + 0, 0, 406, 407, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 408, 0, 0, 537, 0, 0, 0, 0, 0, + 0, 0, 410, 411, 412, 413, 3, 4, 5, 6, + 7, 0, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 69, 0, 0, 0, 0, 0, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 0, 0, 0, 0, 0, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, + 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, + 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, + 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, + 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, + 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, + 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, + 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, + 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 306, 307, 308, 0, 393, 309, 394, 395, 396, 397, + 398, 399, 400, 401, 402, 403, 404, 405, 0, 0, + 406, 407, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 408, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 556, + 410, 411, 412, 413, 3, 4, 5, 6, 7, 0, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 69, 0, 0, 0, 0, 0, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 0, 0, 0, 0, 0, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, + 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, + 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, + 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, + 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, + 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, + 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, + 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, + 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, + 308, 0, 393, 309, 394, 395, 396, 397, 398, 399, + 400, 401, 402, 403, 404, 405, 0, 0, 406, 407, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 408, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 410, 411, + 412, 413, 3, 4, 5, 6, 7, 0, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, + 0, 0, 0, 0, 0, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 0, + 0, 0, 0, 0, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, + 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, + 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, + 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, + 300, 301, 302, 303, 304, 305, 306, 307, 512, 0, + 393, 309, 394, 395, 396, 397, 398, 399, 400, 401, + 402, 403, 404, 405, 0, 0, 406, 407, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 408, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 410, 411, 412, 413, + 3, 4, 5, 6, 7, 0, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 0, 0, 0, + 0, 0, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, + 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, + 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, + 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, + 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, + 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, + 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 307, 308, 0, 0, 309 +}; + +static const yytype_int16 yycheck[] = +{ + 0, 0, 0, 322, 330, 24, 0, 26, 27, 387, + 364, 30, 81, 480, 346, 492, 449, 494, 446, 564, + 497, 323, 323, 341, 342, 346, 368, 359, 628, 355, + 339, 340, 351, 666, 358, 360, 360, 670, 337, 338, + 360, 408, 367, 367, 422, 678, 646, 358, 368, 358, + 360, 360, 384, 385, 360, 364, 375, 367, 376, 377, + 381, 362, 368, 358, 360, 365, 368, 359, 368, 359, + 498, 367, 359, 365, 362, 364, 359, 365, 365, 361, + 368, 359, 365, 365, 359, 552, 440, 365, 365, 443, + 365, 368, 459, 363, 461, 365, 348, 349, 350, 351, + 352, 353, 354, 355, 356, 357, 359, 370, 585, 372, + 543, 365, 365, 323, 492, 367, 494, 406, 407, 497, + 359, 447, 523, 524, 525, 526, 365, 446, 365, 365, + 449, 368, 368, 511, 323, 365, 425, 682, 368, 365, + 507, 360, 368, 384, 385, 386, 373, 374, 375, 343, + 344, 440, 365, 366, 443, 362, 589, 365, 366, 362, + 637, 519, 520, 527, 528, 632, 521, 522, 323, 323, + 360, 367, 323, 368, 359, 358, 380, 379, 378, 498, + 345, 347, 361, 323, 323, 358, 368, 554, 368, 358, + 368, 558, 366, 360, 358, 358, 323, 358, 576, 577, + 358, 363, 323, 359, 361, 323, 683, 585, 361, 322, + 358, 358, 323, 545, 359, 365, 362, 361, 359, 368, + 363, 25, 359, 530, 543, 692, 362, 516, 517, 518, + 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, + 529, 530, 531, 532, 533, 534, 362, 367, 615, 368, + 529, 363, 532, 534, 323, 531, 653, 355, 351, 637, + 533, 628, 316, 355, 445, 665, 623, 620, 678, 349, + 589, 679, 544, 623, 490, 646, 490, 338, 490, 646, + 655, 659, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 660, -1, -1, -1, -1, -1, 653, + -1, -1, -1, 322, -1, 683, -1, -1, -1, 628, + 677, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 322, -1, -1, 651, -1, 646, 322, -1, + 330, -1, -1, -1, -1, -1, 330, -1, 338, 338, + 338, -1, -1, -1, 338, 345, -1, -1, -1, -1, + -1, 351, -1, -1, -1, 355, -1, 351, -1, -1, + -1, 355, -1, -1, 653, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 375, -1, -1, -1, 379, + -1, 375, -1, -1, -1, 379, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 242, -1, -1, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 12, -1, -1, -1, -1, -1, -1, - 261, 262, 263, 264, 265, 24, 25, 26, 27, 28, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 446, 447, -1, 449, + -1, -1, 446, 447, -1, 449, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 480, -1, -1, -1, -1, -1, 480, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 498, -1, + -1, -1, -1, -1, 498, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 543, -1, -1, -1, -1, -1, 543, + -1, -1, 552, -1, -1, -1, -1, -1, 552, -1, + -1, -1, -1, -1, 564, -1, -1, -1, -1, -1, + 564, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 589, + -1, -1, -1, -1, -1, 589, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 623, -1, -1, -1, -1, 628, 623, + -1, -1, 632, -1, 628, -1, -1, -1, 632, -1, + -1, -1, -1, -1, -1, -1, 646, -1, -1, -1, + -1, 651, 646, -1, -1, -1, -1, 651, -1, -1, + -1, -1, -1, -1, -1, -1, 666, -1, -1, -1, + 670, -1, 666, -1, -1, -1, 670, -1, 678, -1, + -1, -1, 682, -1, 678, -1, -1, -1, 682, -1, + -1, -1, 692, -1, -1, -1, 0, -1, 692, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, + 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, + 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, + 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, + 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, + 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, + 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, + 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, + 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, -1, -1, + 324, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 368, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 382, 383, + 384, 385, 386, 387, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, @@ -2138,87 +2361,340 @@ static const yytype_int16 yycheck[] = 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 202, 203, 204, 205, -1, -1, 208, - -1, -1, -1, 6, 7, 8, 9, 10, 11, 12, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + 329, 330, 331, 332, 333, 334, 335, 336, -1, -1, + 339, 340, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 358, + -1, 360, -1, 362, 363, -1, -1, -1, -1, 368, + 369, 370, 371, 372, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 382, 383, 384, 385, 386, 387, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, -1, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, + 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, + 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, + 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, + 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, + 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, + 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, + 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, + 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, + 334, 335, 336, -1, -1, 339, 340, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 25, 26, 27, 28, 29, 30, 31, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 261, 262, 263, 264, 265, 60, 61, 62, - 63, 64, 65, -1, -1, -1, -1, 70, 71, 72, - 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, - 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, - 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, - 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, - 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, - 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, - 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, - 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, - 203, 204, 205, -1, 207, 208, 209, 210, 211, 212, - 213, 214, 215, -1, -1, 218, 219, -1, -1, -1, + -1, -1, -1, -1, 358, -1, 360, -1, 362, 363, + -1, -1, -1, -1, 368, 369, 370, 371, 372, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 382, 383, + 384, 385, 386, 387, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, -1, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + 329, 330, 331, 332, 333, 334, 335, 336, -1, -1, + 339, 340, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 358, + -1, 360, -1, 362, -1, -1, -1, -1, -1, 368, + 369, 370, 371, 372, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 382, 383, 384, 385, 386, 387, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, -1, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, + 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, + 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, + 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, + 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, + 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, + 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, + 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, + 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, + 334, 335, 336, -1, -1, 339, 340, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 237, -1, -1, -1, 241, 242, - -1, -1, -1, -1, -1, 248, 249, 250, 251, 6, - 7, 8, 9, 10, 11, 12, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, -1, + -1, -1, -1, -1, 358, -1, 360, -1, 362, -1, + -1, -1, -1, -1, 368, 369, 370, 371, 372, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 382, 383, + 384, 385, 386, 387, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, -1, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + 329, 330, 331, 332, 333, 334, 335, 336, -1, -1, + 339, 340, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 358, + -1, 360, -1, -1, -1, -1, -1, -1, -1, 368, + 369, 370, 371, 372, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 382, 383, 384, 385, 386, 387, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, + 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, + 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, + 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, + 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, + 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, + 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, + 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, + 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, -1, 323, + 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, + 334, 335, 336, -1, -1, 339, 340, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 60, 61, 62, 63, 64, 65, -1, - -1, -1, -1, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 199, 200, 201, 202, 203, 204, 205, -1, - 207, 208, 209, 210, 211, 212, 213, 214, 215, -1, - -1, 218, 219, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 358, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 368, 369, 370, 371, 372, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 382, 383, + 384, 385, 386, 387, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, -1, -1, 324, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 237, -1, -1, 240, 6, 7, 8, 9, 10, 11, - 12, 248, 249, 250, 251, -1, -1, -1, -1, -1, - -1, -1, -1, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 60, 61, - 62, 63, 64, 65, -1, -1, -1, -1, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, - 202, 203, 204, 205, -1, 207, 208, 209, 210, 211, - 212, 213, 214, 215, -1, -1, 218, 219, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 237, -1, -1, -1, 241, - -1, -1, -1, -1, -1, -1, 248, 249, 250, 251, - 6, 7, 8, 9, 10, 11, 12, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 368, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 382, 383, 384, 385, 386, 387, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, + 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, + 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, + 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, + 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, + 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, + 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, + 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, + 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, -1, 323, + 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, + 334, 335, 336, -1, -1, 339, 340, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 358, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 369, 370, 371, 372, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 382, 383, + 384, 385, 386, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, + 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, + 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, + 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, + 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, -1, 323, 324, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 368, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 382, 383, 384, 385, 386, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 60, 61, 62, 63, 64, 65, - -1, -1, -1, -1, 70, 71, 72, 73, 74, 75, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, @@ -2232,21 +2708,148 @@ static const yytype_int16 yycheck[] = 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, - -1, 207, 208, 209, 210, 211, 212, 213, 214, 215, - -1, -1, 218, 219, -1, -1, -1, -1, -1, -1, + 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, + 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, + 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, + 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, + 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, + 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, -1, -1, 324, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 237, -1, -1, 240, 6, 7, 8, 9, 10, - 11, 12, 248, 249, 250, 251, -1, -1, -1, -1, - -1, -1, -1, -1, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 60, - 61, 62, 63, 64, 65, -1, -1, -1, -1, 70, - 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 363, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 382, 383, 384, 385, + 386, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, + 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, + 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, + 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, + 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, + 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, + 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + -1, -1, 324, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 363, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 382, 383, 384, 385, 386, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, + 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, + 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, + 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, + 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, + 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, + 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, + 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, + 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, -1, -1, 324, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 363, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 382, 383, 384, 385, 386, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, + 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, + 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, + 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, + 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, + 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, + 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, + 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, + 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, -1, -1, + 324, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 5, 6, 7, 8, 9, -1, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, -1, -1, -1, -1, -1, -1, -1, 382, 383, + 384, 385, 386, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 82, -1, -1, -1, -1, -1, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 111, -1, -1, -1, -1, -1, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, @@ -2255,68 +2858,72 @@ static const yytype_int16 yycheck[] = 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, -1, 207, 208, 209, 210, - 211, 212, 213, 214, 215, -1, -1, 218, 219, -1, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, -1, 323, 324, 325, 326, 327, 328, 329, 330, + 331, 332, 333, 334, 335, 336, -1, -1, 339, 340, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 237, 6, 7, 8, - 9, 10, 11, 12, -1, -1, 247, 248, 249, 250, - 251, -1, -1, -1, -1, -1, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 358, -1, -1, + -1, 362, 363, -1, -1, -1, -1, -1, 369, 370, + 371, 372, 5, 6, 7, 8, 9, -1, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 60, 61, 62, 63, 64, 65, -1, -1, -1, - -1, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 202, 203, 204, 205, -1, 207, 208, - 209, 210, 211, 212, 213, 214, 215, -1, -1, 218, - 219, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 237, 6, - 7, 8, 9, 10, 11, 12, -1, -1, -1, 248, - 249, 250, 251, -1, -1, -1, -1, -1, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, -1, + -1, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 82, + -1, -1, -1, -1, -1, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, -1, + -1, -1, -1, -1, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, + 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, + 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, + 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, -1, + 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, + 333, 334, 335, 336, -1, -1, 339, 340, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 60, 61, 62, 63, 64, 65, -1, - -1, -1, -1, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 199, 200, 201, 202, 203, 204, 205, -1, - 207, 208, 209, 210, 211, 212, 213, 214, 215, -1, - -1, 218, 219, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 237, 6, 7, 8, 9, 10, 11, 12, -1, -1, - -1, 248, 249, 250, 251, -1, -1, -1, -1, -1, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + -1, -1, -1, -1, -1, 358, -1, -1, 361, -1, + -1, -1, -1, -1, -1, -1, 369, 370, 371, 372, + 5, 6, 7, 8, 9, -1, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 60, 61, 62, 63, 64, - 65, -1, -1, -1, -1, 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 82, -1, -1, + -1, -1, -1, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 105, 106, 107, 108, 109, 110, 111, -1, -1, -1, + -1, -1, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, @@ -2325,7 +2932,202 @@ static const yytype_int16 yycheck[] = 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, - 205, -1, -1, 208 + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, -1, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, -1, -1, 339, 340, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 358, -1, -1, -1, 362, -1, -1, + -1, -1, -1, -1, 369, 370, 371, 372, 5, 6, + 7, 8, 9, -1, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 82, -1, -1, -1, -1, + -1, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, -1, -1, -1, -1, -1, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, -1, 323, 324, 325, 326, + 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, + -1, -1, 339, 340, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 358, -1, -1, 361, -1, -1, -1, -1, -1, + -1, -1, 369, 370, 371, 372, 5, 6, 7, 8, + 9, -1, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 82, -1, -1, -1, -1, -1, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, -1, -1, -1, -1, -1, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, -1, 323, 324, 325, 326, 327, 328, + 329, 330, 331, 332, 333, 334, 335, 336, -1, -1, + 339, 340, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 358, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 368, + 369, 370, 371, 372, 5, 6, 7, 8, 9, -1, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 82, -1, -1, -1, -1, -1, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, -1, -1, -1, -1, -1, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, -1, 323, 324, 325, 326, 327, 328, 329, 330, + 331, 332, 333, 334, 335, 336, -1, -1, 339, 340, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 358, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 369, 370, + 371, 372, 5, 6, 7, 8, 9, -1, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 82, + -1, -1, -1, -1, -1, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, -1, + -1, -1, -1, -1, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, + 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, + 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, + 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, -1, + 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, + 333, 334, 335, 336, -1, -1, 339, 340, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 358, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 369, 370, 371, 372, + 5, 6, 7, 8, 9, -1, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, -1, -1, -1, + -1, -1, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, -1, -1, 324 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -2333,7 +3135,7 @@ static const yytype_int16 yycheck[] = static const yytype_uint16 yystos[] = { 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, @@ -2351,114 +3153,141 @@ static const yytype_uint16 yystos[] = 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, - 203, 204, 205, 208, 261, 262, 263, 264, 265, 266, - 301, 302, 305, 306, 307, 308, 312, 313, 314, 315, - 316, 317, 320, 321, 322, 323, 325, 327, 328, 329, - 366, 367, 368, 237, 237, 207, 241, 328, 207, 247, - 247, 369, 238, 244, 309, 310, 311, 321, 325, 244, - 247, 207, 207, 247, 322, 325, 239, 326, 0, 367, - 208, 324, 54, 207, 318, 319, 241, 331, 325, 247, - 326, 241, 348, 310, 309, 311, 207, 207, 237, 246, - 326, 241, 244, 247, 304, 207, 209, 210, 211, 212, - 213, 214, 215, 218, 219, 237, 240, 248, 249, 250, - 251, 271, 272, 273, 275, 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, - 291, 292, 293, 294, 295, 325, 239, 238, 244, 246, - 238, 244, 330, 321, 325, 332, 333, 247, 247, 13, - 14, 15, 17, 18, 19, 20, 21, 22, 23, 206, - 241, 242, 247, 282, 295, 297, 299, 301, 305, 325, - 338, 339, 340, 341, 349, 350, 351, 354, 357, 358, - 365, 326, 246, 326, 241, 297, 336, 246, 303, 207, - 244, 247, 282, 282, 299, 218, 219, 239, 243, 238, - 238, 244, 205, 297, 237, 282, 252, 253, 254, 249, - 251, 216, 217, 220, 221, 255, 256, 222, 223, 259, - 258, 257, 224, 226, 225, 260, 240, 240, 295, 208, - 295, 300, 319, 332, 325, 207, 334, 335, 242, 333, - 247, 247, 360, 237, 237, 247, 247, 299, 237, 299, - 245, 237, 242, 342, 227, 228, 229, 230, 231, 232, - 233, 234, 235, 236, 246, 298, 244, 247, 242, 339, - 336, 246, 336, 337, 336, 332, 207, 238, 274, 299, - 207, 297, 282, 282, 282, 284, 284, 285, 285, 286, - 286, 286, 286, 287, 287, 288, 289, 290, 291, 292, - 293, 296, 240, 242, 334, 326, 244, 247, 339, 361, - 299, 247, 299, 245, 359, 349, 297, 297, 336, 242, - 244, 242, 240, 299, 247, 335, 206, 338, 350, 362, - 238, 238, 299, 314, 321, 353, 343, 242, 336, 245, - 237, 353, 363, 364, 345, 346, 347, 352, 355, 207, - 238, 242, 297, 299, 247, 238, 16, 341, 340, 241, - 246, 340, 344, 348, 238, 299, 344, 345, 349, 356, - 336, 247, 242 + 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, + 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 324, + 368, 382, 383, 384, 385, 386, 387, 422, 423, 426, + 427, 428, 429, 433, 434, 435, 436, 437, 438, 441, + 442, 443, 444, 445, 447, 449, 450, 451, 491, 492, + 493, 358, 358, 323, 362, 450, 323, 368, 368, 494, + 359, 365, 430, 431, 432, 442, 447, 365, 368, 323, + 323, 368, 443, 447, 360, 448, 0, 492, 323, 446, + 81, 323, 439, 440, 362, 453, 447, 368, 448, 362, + 470, 431, 430, 432, 323, 323, 358, 367, 448, 362, + 365, 368, 425, 323, 325, 326, 327, 328, 329, 330, + 331, 332, 333, 334, 335, 336, 339, 340, 358, 361, + 369, 370, 371, 372, 392, 393, 394, 396, 397, 398, + 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, 415, 416, 445, 447, + 360, 359, 365, 367, 359, 365, 452, 442, 447, 454, + 455, 368, 368, 22, 23, 24, 26, 27, 28, 29, + 30, 31, 32, 322, 360, 362, 363, 368, 403, 416, + 418, 420, 422, 426, 445, 447, 460, 461, 462, 463, + 471, 472, 473, 474, 477, 478, 481, 482, 483, 490, + 495, 448, 367, 448, 362, 418, 458, 367, 424, 323, + 365, 368, 403, 403, 420, 339, 340, 360, 364, 359, + 359, 365, 321, 418, 358, 403, 373, 374, 375, 370, + 372, 337, 338, 341, 342, 376, 377, 343, 344, 380, + 379, 378, 345, 347, 346, 381, 361, 361, 416, 323, + 416, 421, 440, 454, 447, 323, 456, 457, 363, 455, + 368, 368, 485, 358, 358, 368, 368, 420, 358, 420, + 366, 358, 360, 363, 464, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 367, 419, 365, 368, 363, + 461, 474, 478, 483, 458, 367, 458, 459, 458, 454, + 323, 359, 395, 420, 323, 418, 403, 403, 403, 405, + 405, 406, 406, 407, 407, 407, 407, 408, 408, 409, + 410, 411, 412, 413, 414, 417, 361, 363, 456, 448, + 365, 368, 461, 486, 420, 368, 420, 366, 484, 323, + 496, 497, 471, 418, 418, 458, 363, 365, 363, 361, + 420, 368, 457, 322, 460, 472, 487, 359, 359, 420, + 435, 442, 476, 358, 361, 365, 465, 363, 458, 366, + 358, 476, 488, 489, 467, 468, 469, 475, 479, 323, + 359, 421, 361, 497, 363, 418, 420, 368, 359, 25, + 463, 462, 362, 367, 462, 466, 470, 359, 359, 420, + 466, 467, 471, 480, 458, 368, 363 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint16 yyr1[] = { - 0, 270, 271, 272, 272, 272, 272, 272, 272, 272, - 272, 272, 273, 273, 273, 273, 273, 273, 274, 275, - 276, 277, 277, 278, 278, 279, 279, 280, 281, 281, - 282, 282, 282, 282, 283, 283, 283, 283, 284, 284, - 284, 284, 285, 285, 285, 286, 286, 286, 287, 287, - 287, 287, 287, 288, 288, 288, 289, 289, 290, 290, - 291, 291, 292, 292, 293, 293, 294, 294, 295, 296, - 295, 297, 297, 298, 298, 298, 298, 298, 298, 298, - 298, 298, 298, 298, 299, 299, 300, 301, 301, 301, - 301, 301, 301, 301, 301, 301, 303, 302, 304, 304, - 305, 306, 306, 307, 307, 308, 309, 309, 310, 310, - 310, 310, 311, 312, 312, 312, 312, 312, 313, 313, - 313, 313, 313, 314, 314, 315, 316, 316, 316, 317, - 318, 318, 319, 319, 319, 320, 321, 321, 322, 322, - 322, 322, 322, 322, 323, 323, 323, 323, 323, 323, - 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - 323, 323, 323, 324, 324, 325, 325, 326, 326, 326, - 326, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 327, 327, 328, 328, 328, 330, 329, 331, 329, 332, - 332, 333, 333, 334, 334, 335, 335, 336, 336, 336, - 337, 337, 338, 339, 339, 340, 340, 340, 340, 340, - 340, 340, 341, 342, 343, 341, 344, 344, 346, 345, - 347, 345, 348, 348, 349, 349, 350, 350, 351, 352, - 352, 353, 353, 355, 354, 356, 356, 357, 357, 359, - 358, 360, 358, 361, 358, 362, 362, 363, 363, 364, - 364, 365, 365, 365, 365, 365, 366, 366, 367, 367, - 369, 368 + 0, 391, 392, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 394, 394, 394, + 394, 394, 394, 395, 396, 397, 398, 398, 399, 399, + 400, 400, 401, 402, 402, 402, 403, 403, 403, 403, + 404, 404, 404, 404, 405, 405, 405, 405, 406, 406, + 406, 407, 407, 407, 408, 408, 408, 408, 408, 409, + 409, 409, 410, 410, 411, 411, 412, 412, 413, 413, + 414, 414, 415, 415, 416, 417, 416, 418, 418, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 420, 420, 421, 422, 422, 422, 422, 422, 422, 422, + 422, 422, 424, 423, 425, 425, 426, 427, 427, 428, + 428, 429, 430, 430, 431, 431, 431, 431, 432, 433, + 433, 433, 433, 433, 434, 434, 434, 434, 434, 435, + 435, 436, 437, 437, 437, 437, 438, 439, 439, 440, + 440, 440, 441, 442, 442, 443, 443, 443, 443, 443, + 443, 443, 444, 444, 444, 444, 444, 444, 444, 444, + 444, 444, 444, 444, 444, 444, 444, 444, 444, 444, + 444, 445, 446, 446, 447, 447, 448, 448, 448, 448, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 450, 450, 450, 452, 451, + 453, 451, 454, 454, 455, 455, 456, 456, 457, 457, + 458, 458, 458, 459, 459, 460, 461, 461, 462, 462, + 462, 462, 462, 462, 462, 463, 464, 465, 463, 466, + 466, 468, 467, 469, 467, 470, 470, 471, 471, 472, + 472, 473, 473, 474, 475, 475, 476, 476, 477, 477, + 479, 478, 480, 480, 481, 481, 482, 482, 484, 483, + 485, 483, 486, 483, 487, 487, 488, 488, 489, 489, + 490, 490, 490, 490, 490, 491, 491, 492, 492, 492, + 494, 493, 495, 496, 496, 497, 497 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 3, 1, 4, 1, 3, 2, 2, 1, 1, - 1, 2, 2, 2, 1, 2, 3, 2, 1, 1, - 1, 2, 2, 2, 1, 1, 1, 1, 1, 3, - 3, 3, 1, 3, 3, 1, 3, 3, 1, 3, - 3, 3, 3, 1, 3, 3, 1, 3, 1, 3, - 1, 3, 1, 3, 1, 3, 1, 3, 1, 0, - 6, 1, 3, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 3, 1, 2, 2, 4, - 2, 3, 4, 2, 3, 4, 0, 6, 2, 3, - 2, 1, 1, 2, 3, 3, 2, 3, 2, 1, - 2, 1, 1, 1, 3, 4, 6, 5, 1, 2, - 3, 5, 4, 1, 2, 1, 1, 1, 1, 4, - 1, 3, 1, 3, 1, 1, 1, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 1, 4, 1, + 3, 2, 2, 1, 1, 1, 2, 2, 2, 1, + 2, 3, 2, 1, 1, 1, 1, 2, 2, 2, + 1, 1, 1, 1, 1, 3, 3, 3, 1, 3, + 3, 1, 3, 3, 1, 3, 3, 3, 3, 1, + 3, 3, 1, 3, 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 0, 6, 1, 3, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 1, 2, 2, 4, 2, 3, 4, 2, + 3, 4, 0, 6, 2, 3, 2, 1, 1, 2, + 3, 3, 2, 3, 2, 1, 2, 1, 1, 1, + 3, 4, 6, 5, 1, 2, 3, 5, 4, 1, + 2, 1, 1, 1, 1, 1, 4, 1, 3, 1, + 3, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 4, 1, 3, 1, 2, 2, 3, 3, - 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 4, 1, 1, 3, 1, 2, 2, 3, 3, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -2475,15 +3304,28 @@ static const yytype_uint8 yyr2[] = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 0, 6, 0, 5, 1, - 2, 3, 4, 1, 3, 1, 2, 1, 3, 4, - 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 2, 0, 0, 5, 1, 1, 0, 2, - 0, 2, 2, 3, 1, 2, 1, 2, 5, 3, - 1, 1, 4, 0, 8, 0, 1, 3, 2, 0, - 6, 0, 8, 0, 7, 1, 1, 1, 0, 2, - 3, 2, 2, 2, 3, 2, 1, 2, 1, 1, - 0, 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 6, + 0, 5, 1, 2, 3, 4, 1, 3, 1, 2, + 1, 3, 4, 1, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 0, 0, 5, 1, + 1, 0, 2, 0, 2, 2, 3, 1, 2, 1, + 2, 1, 2, 5, 3, 1, 1, 4, 1, 2, + 0, 8, 0, 1, 3, 2, 1, 2, 0, 6, + 0, 8, 0, 7, 1, 1, 1, 0, 2, 3, + 2, 2, 2, 3, 2, 1, 2, 1, 1, 1, + 0, 3, 5, 1, 3, 1, 4 }; @@ -2768,11 +3610,11 @@ static int yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, yytype_int16 *yyssp, int yytoken) { - YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]); YYSIZE_T yysize = yysize0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ - const char *yyformat = YY_NULLPTR; + const char *yyformat = YY_NULL; /* Arguments of yyformat. */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; /* Number of reported tokens (one for the "unexpected", one per @@ -2829,7 +3671,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, } yyarg[yycount++] = yytname[yyx]; { - YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; @@ -3166,205 +4008,250 @@ yyreduce: switch (yyn) { case 2: -#line 246 "MachineIndependent/glslang.y" /* yacc.c:1646 */ +#line 293 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.handleVariable((yyvsp[0].lex).loc, (yyvsp[0].lex).symbol, (yyvsp[0].lex).string); } -#line 3174 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4016 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; case 3: -#line 252 "MachineIndependent/glslang.y" /* yacc.c:1646 */ +#line 299 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3182 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4024 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; case 4: -#line 255 "MachineIndependent/glslang.y" /* yacc.c:1646 */ +#line 302 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed literal"); (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i, (yyvsp[0].lex).loc, true); } -#line 3190 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4033 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; case 5: -#line 258 "MachineIndependent/glslang.y" /* yacc.c:1646 */ +#line 306 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed literal"); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).u, (yyvsp[0].lex).loc, true); + } +#line 4042 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 6: +#line 310 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i, (yyvsp[0].lex).loc, true); + } +#line 4050 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 7: +#line 313 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned literal"); (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).u, (yyvsp[0].lex).loc, true); } -#line 3199 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4059 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 6: -#line 262 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 8: +#line 317 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer literal"); (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i64, (yyvsp[0].lex).loc, true); } -#line 3208 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4068 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 7: -#line 266 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 9: +#line 321 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer literal"); (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).u64, (yyvsp[0].lex).loc, true); } -#line 3217 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4077 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 8: -#line 270 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 10: +#line 325 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt16Check((yyvsp[0].lex).loc, "16-bit integer literal"); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((short)(yyvsp[0].lex).i, (yyvsp[0].lex).loc, true); + } +#line 4086 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 11: +#line 329 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt16Check((yyvsp[0].lex).loc, "16-bit unsigned integer literal"); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((unsigned short)(yyvsp[0].lex).u, (yyvsp[0].lex).loc, true); + } +#line 4095 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 12: +#line 333 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtFloat, (yyvsp[0].lex).loc, true); } -#line 3225 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4103 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 9: -#line 273 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 13: +#line 336 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.doubleCheck((yyvsp[0].lex).loc, "double literal"); (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtDouble, (yyvsp[0].lex).loc, true); } -#line 3234 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4112 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 10: -#line 277 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 14: +#line 340 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float literal"); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtFloat16, (yyvsp[0].lex).loc, true); + } +#line 4121 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 15: +#line 344 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).b, (yyvsp[0].lex).loc, true); } -#line 3242 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4129 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 11: -#line 280 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 16: +#line 347 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[-1].interm.intermTypedNode); if ((yyval.interm.intermTypedNode)->getAsConstantUnion()) (yyval.interm.intermTypedNode)->getAsConstantUnion()->setExpression(); } -#line 3252 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4139 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 12: -#line 288 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 17: +#line 355 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3260 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4147 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 13: -#line 291 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 18: +#line 358 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.handleBracketDereference((yyvsp[-2].lex).loc, (yyvsp[-3].interm.intermTypedNode), (yyvsp[-1].interm.intermTypedNode)); } -#line 3268 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4155 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 14: -#line 294 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 19: +#line 361 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3276 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4163 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 15: -#line 297 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 20: +#line 364 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.handleDotDereference((yyvsp[0].lex).loc, (yyvsp[-2].interm.intermTypedNode), *(yyvsp[0].lex).string); } -#line 3284 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4171 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 16: -#line 300 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 21: +#line 367 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.variableCheck((yyvsp[-1].interm.intermTypedNode)); parseContext.lValueErrorCheck((yyvsp[0].lex).loc, "++", (yyvsp[-1].interm.intermTypedNode)); (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[0].lex).loc, "++", EOpPostIncrement, (yyvsp[-1].interm.intermTypedNode)); } -#line 3294 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4181 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 17: -#line 305 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 22: +#line 372 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.variableCheck((yyvsp[-1].interm.intermTypedNode)); parseContext.lValueErrorCheck((yyvsp[0].lex).loc, "--", (yyvsp[-1].interm.intermTypedNode)); (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[0].lex).loc, "--", EOpPostDecrement, (yyvsp[-1].interm.intermTypedNode)); } -#line 3304 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4191 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 18: -#line 313 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 23: +#line 380 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.integerCheck((yyvsp[0].interm.intermTypedNode), "[]"); (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3313 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4200 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 19: -#line 320 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 24: +#line 387 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.handleFunctionCall((yyvsp[0].interm).loc, (yyvsp[0].interm).function, (yyvsp[0].interm).intermNode); delete (yyvsp[0].interm).function; } -#line 3322 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 20: -#line 327 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[0].interm); - } -#line 3330 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 21: -#line 333 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[-1].interm); - (yyval.interm).loc = (yyvsp[0].lex).loc; - } -#line 3339 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 22: -#line 337 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[-1].interm); - (yyval.interm).loc = (yyvsp[0].lex).loc; - } -#line 3348 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 23: -#line 344 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[-1].interm); - } -#line 3356 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 24: -#line 347 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[0].interm); - } -#line 3364 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4209 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; case 25: -#line 353 "MachineIndependent/glslang.y" /* yacc.c:1646 */ +#line 394 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[0].interm); + } +#line 4217 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 26: +#line 400 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[-1].interm); + (yyval.interm).loc = (yyvsp[0].lex).loc; + } +#line 4226 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 27: +#line 404 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[-1].interm); + (yyval.interm).loc = (yyvsp[0].lex).loc; + } +#line 4235 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 28: +#line 411 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[-1].interm); + } +#line 4243 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 29: +#line 414 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[0].interm); + } +#line 4251 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 30: +#line 420 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { TParameter param = { 0, new TType }; param.type->shallowCopy((yyvsp[0].interm.intermTypedNode)->getType()); @@ -3372,11 +4259,11 @@ yyreduce: (yyval.interm).function = (yyvsp[-1].interm).function; (yyval.interm).intermNode = (yyvsp[0].interm.intermTypedNode); } -#line 3376 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4263 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 26: -#line 360 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 31: +#line 427 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { TParameter param = { 0, new TType }; param.type->shallowCopy((yyvsp[0].interm.intermTypedNode)->getType()); @@ -3384,29 +4271,29 @@ yyreduce: (yyval.interm).function = (yyvsp[-2].interm).function; (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[-2].interm).intermNode, (yyvsp[0].interm.intermTypedNode), (yyvsp[-1].lex).loc); } -#line 3388 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4275 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 27: -#line 370 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 32: +#line 437 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm) = (yyvsp[-1].interm); } -#line 3396 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4283 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 28: -#line 378 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 33: +#line 445 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { // Constructor (yyval.interm).intermNode = 0; (yyval.interm).function = parseContext.handleConstructorCall((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type)); } -#line 3406 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4293 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 29: -#line 383 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 34: +#line 450 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { // // Should be a method or subroutine call, but we haven't recognized the arguments yet. @@ -3434,40 +4321,50 @@ yyreduce: (yyval.interm).function = new TFunction(&empty, TType(EbtVoid), EOpNull); } } -#line 3438 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4325 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 30: -#line 413 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 35: +#line 477 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + // Constructor + (yyval.interm).intermNode = 0; + (yyval.interm).function = parseContext.handleConstructorCall((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type)); + } +#line 4335 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 36: +#line 485 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.variableCheck((yyvsp[0].interm.intermTypedNode)); (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); if (TIntermMethod* method = (yyvsp[0].interm.intermTypedNode)->getAsMethodNode()) parseContext.error((yyvsp[0].interm.intermTypedNode)->getLoc(), "incomplete method syntax", method->getMethodName().c_str(), ""); } -#line 3449 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4346 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 31: -#line 419 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 37: +#line 491 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.lValueErrorCheck((yyvsp[-1].lex).loc, "++", (yyvsp[0].interm.intermTypedNode)); (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[-1].lex).loc, "++", EOpPreIncrement, (yyvsp[0].interm.intermTypedNode)); } -#line 3458 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4355 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 32: -#line 423 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 38: +#line 495 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.lValueErrorCheck((yyvsp[-1].lex).loc, "--", (yyvsp[0].interm.intermTypedNode)); (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[-1].lex).loc, "--", EOpPreDecrement, (yyvsp[0].interm.intermTypedNode)); } -#line 3467 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4364 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 33: -#line 427 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 39: +#line 499 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { if ((yyvsp[-1].interm).op != EOpNull) { char errorOp[2] = {0, 0}; @@ -3484,179 +4381,179 @@ yyreduce: (yyval.interm.intermTypedNode)->getAsConstantUnion()->setExpression(); } } -#line 3488 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4385 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 34: -#line 447 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 40: +#line 519 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpNull; } -#line 3494 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4391 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 35: -#line 448 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 41: +#line 520 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpNegative; } -#line 3500 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4397 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 36: -#line 449 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 42: +#line 521 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpLogicalNot; } -#line 3506 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4403 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 37: -#line 450 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 43: +#line 522 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpBitwiseNot; parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise not"); } -#line 3513 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4410 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 38: -#line 456 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 44: +#line 528 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3519 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4416 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 39: -#line 457 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 45: +#line 529 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "*", EOpMul, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 3529 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4426 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 40: -#line 462 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 46: +#line 534 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "/", EOpDiv, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 3539 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4436 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 41: -#line 467 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 47: +#line 539 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "%"); (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "%", EOpMod, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 3550 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4447 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 42: -#line 476 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 48: +#line 548 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3556 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4453 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 43: -#line 477 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 49: +#line 549 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "+", EOpAdd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 3566 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4463 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 44: -#line 482 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 50: +#line 554 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "-", EOpSub, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 3576 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4473 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 45: -#line 490 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 51: +#line 562 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3582 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4479 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 46: -#line 491 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 52: +#line 563 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bit shift left"); (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "<<", EOpLeftShift, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 3593 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4490 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 47: -#line 497 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 53: +#line 569 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bit shift right"); (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, ">>", EOpRightShift, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 3604 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4501 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 48: -#line 506 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 54: +#line 578 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3610 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4507 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 49: -#line 507 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 55: +#line 579 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "<", EOpLessThan, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); } -#line 3620 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4517 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 50: -#line 512 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 56: +#line 584 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, ">", EOpGreaterThan, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); } -#line 3630 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4527 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 51: -#line 517 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 57: +#line 589 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "<=", EOpLessThanEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); } -#line 3640 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4537 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 52: -#line 522 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 58: +#line 594 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, ">=", EOpGreaterThanEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); } -#line 3650 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4547 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 53: -#line 530 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 59: +#line 602 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3656 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4553 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 54: -#line 531 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 60: +#line 603 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.arrayObjectCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "array comparison"); parseContext.opaqueCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "=="); @@ -3665,11 +4562,11 @@ yyreduce: if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); } -#line 3669 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4566 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 55: -#line 539 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 61: +#line 611 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.arrayObjectCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "array comparison"); parseContext.opaqueCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "!="); @@ -3678,124 +4575,124 @@ yyreduce: if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); } -#line 3682 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4579 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 56: -#line 550 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 62: +#line 622 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3688 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4585 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 57: -#line 551 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 63: +#line 623 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bitwise and"); (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "&", EOpAnd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 3699 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4596 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 58: -#line 560 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 64: +#line 632 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3705 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4602 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 59: -#line 561 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 65: +#line 633 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bitwise exclusive or"); (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "^", EOpExclusiveOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 3716 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4613 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 60: -#line 570 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 66: +#line 642 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3722 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4619 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 61: -#line 571 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 67: +#line 643 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bitwise inclusive or"); (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "|", EOpInclusiveOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 3733 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4630 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 62: -#line 580 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 68: +#line 652 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3739 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4636 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 63: -#line 581 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 69: +#line 653 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "&&", EOpLogicalAnd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); } -#line 3749 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4646 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 64: -#line 589 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 70: +#line 661 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3755 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4652 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 65: -#line 590 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 71: +#line 662 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "^^", EOpLogicalXor, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); } -#line 3765 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4662 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 66: -#line 598 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 72: +#line 670 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3771 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4668 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 67: -#line 599 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 73: +#line 671 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "||", EOpLogicalOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); } -#line 3781 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4678 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 68: -#line 607 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 74: +#line 679 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3787 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4684 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 69: -#line 608 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 75: +#line 680 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { ++parseContext.controlFlowNestingLevel; } -#line 3795 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4692 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 70: -#line 611 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 76: +#line 683 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { --parseContext.controlFlowNestingLevel; parseContext.boolCheck((yyvsp[-4].lex).loc, (yyvsp[-5].interm.intermTypedNode)); @@ -3808,17 +4705,17 @@ yyreduce: (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } } -#line 3812 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4709 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 71: -#line 626 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 77: +#line 698 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3818 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4715 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 72: -#line 627 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 78: +#line 699 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.arrayObjectCheck((yyvsp[-1].interm).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "array assignment"); parseContext.opaqueCheck((yyvsp[-1].interm).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "="); @@ -3831,160 +4728,161 @@ yyreduce: (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } } -#line 3835 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4732 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 73: -#line 642 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 79: +#line 714 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpAssign; } -#line 3844 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4741 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 74: -#line 646 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 80: +#line 718 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpMulAssign; } -#line 3853 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4750 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 75: -#line 650 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 81: +#line 722 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpDivAssign; } -#line 3862 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4759 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 76: -#line 654 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 82: +#line 726 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "%="); (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpModAssign; } -#line 3872 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4769 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 77: -#line 659 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 83: +#line 731 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpAddAssign; } -#line 3881 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4778 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 78: -#line 663 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 84: +#line 735 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpSubAssign; } -#line 3890 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4787 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 79: -#line 667 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 85: +#line 739 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bit-shift left assign"); (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpLeftShiftAssign; } -#line 3899 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4796 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 80: -#line 671 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 86: +#line 743 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bit-shift right assign"); (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpRightShiftAssign; } -#line 3908 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4805 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 81: -#line 675 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 87: +#line 747 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise-and assign"); (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpAndAssign; } -#line 3917 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4814 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 82: -#line 679 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 88: +#line 751 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise-xor assign"); (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpExclusiveOrAssign; } -#line 3926 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4823 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 83: -#line 683 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 89: +#line 755 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise-or assign"); (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpInclusiveOrAssign; } -#line 3935 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4832 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 84: -#line 690 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 90: +#line 762 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3943 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4840 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 85: -#line 693 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 91: +#line 765 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { + parseContext.samplerConstructorLocationCheck((yyvsp[-1].lex).loc, ",", (yyvsp[0].interm.intermTypedNode)); (yyval.interm.intermTypedNode) = parseContext.intermediate.addComma((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yyvsp[-1].lex).loc); if ((yyval.interm.intermTypedNode) == 0) { parseContext.binaryOpError((yyvsp[-1].lex).loc, ",", (yyvsp[-2].interm.intermTypedNode)->getCompleteString(), (yyvsp[0].interm.intermTypedNode)->getCompleteString()); (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } } -#line 3955 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4853 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 86: -#line 703 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 92: +#line 776 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.constantValueCheck((yyvsp[0].interm.intermTypedNode), ""); (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 3964 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4862 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 87: -#line 710 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 93: +#line 783 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.handleFunctionDeclarator((yyvsp[-1].interm).loc, *(yyvsp[-1].interm).function, true /* prototype */); (yyval.interm.intermNode) = 0; // TODO: 4.0 functionality: subroutines: make the identifier a user type for this signature } -#line 3974 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4872 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 88: -#line 715 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 94: +#line 788 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { if ((yyvsp[-1].interm).intermNode && (yyvsp[-1].interm).intermNode->getAsAggregate()) (yyvsp[-1].interm).intermNode->getAsAggregate()->setOperator(EOpSequence); (yyval.interm.intermNode) = (yyvsp[-1].interm).intermNode; } -#line 3984 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4882 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 89: -#line 720 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 95: +#line 793 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.profileRequires((yyvsp[-3].lex).loc, ENoProfile, 130, 0, "precision statement"); @@ -3993,75 +4891,75 @@ yyreduce: parseContext.setDefaultPrecision((yyvsp[-3].lex).loc, (yyvsp[-1].interm.type), (yyvsp[-2].interm.type).qualifier.precision); (yyval.interm.intermNode) = 0; } -#line 3997 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4895 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 90: -#line 728 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 96: +#line 801 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.declareBlock((yyvsp[-1].interm).loc, *(yyvsp[-1].interm).typeList); (yyval.interm.intermNode) = 0; } -#line 4006 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4904 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 91: -#line 732 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 97: +#line 805 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.declareBlock((yyvsp[-2].interm).loc, *(yyvsp[-2].interm).typeList, (yyvsp[-1].lex).string); (yyval.interm.intermNode) = 0; } -#line 4015 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4913 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 92: -#line 736 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 98: +#line 809 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.declareBlock((yyvsp[-3].interm).loc, *(yyvsp[-3].interm).typeList, (yyvsp[-2].lex).string, (yyvsp[-1].interm).arraySizes); (yyval.interm.intermNode) = 0; } -#line 4024 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4922 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 93: -#line 740 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 99: +#line 813 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.globalQualifierFixCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier); parseContext.updateStandaloneQualifierDefaults((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type)); (yyval.interm.intermNode) = 0; } -#line 4034 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4932 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 94: -#line 745 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 100: +#line 818 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.checkNoShaderLayouts((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).shaderQualifiers); parseContext.addQualifierToExisting((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).qualifier, *(yyvsp[-1].lex).string); (yyval.interm.intermNode) = 0; } -#line 4044 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4942 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 95: -#line 750 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 101: +#line 823 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.checkNoShaderLayouts((yyvsp[-3].interm.type).loc, (yyvsp[-3].interm.type).shaderQualifiers); (yyvsp[-1].interm.identifierList)->push_back((yyvsp[-2].lex).string); parseContext.addQualifierToExisting((yyvsp[-3].interm.type).loc, (yyvsp[-3].interm.type).qualifier, *(yyvsp[-1].interm.identifierList)); (yyval.interm.intermNode) = 0; } -#line 4055 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4953 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 96: -#line 759 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 102: +#line 832 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.nestedBlockCheck((yyvsp[-2].interm.type).loc); } -#line 4061 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4959 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 97: -#line 759 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 103: +#line 832 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { --parseContext.structNestingLevel; parseContext.blockName = (yyvsp[-4].lex).string; @@ -4071,54 +4969,54 @@ yyreduce: (yyval.interm).loc = (yyvsp[-5].interm.type).loc; (yyval.interm).typeList = (yyvsp[-1].interm.typeList); } -#line 4075 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4973 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 98: -#line 770 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 104: +#line 843 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.identifierList) = new TIdentifierList; (yyval.interm.identifierList)->push_back((yyvsp[0].lex).string); } -#line 4084 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4982 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 99: -#line 774 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 105: +#line 847 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.identifierList) = (yyvsp[-2].interm.identifierList); (yyval.interm.identifierList)->push_back((yyvsp[0].lex).string); } -#line 4093 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 4991 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 100: -#line 781 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 106: +#line 854 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).function = (yyvsp[-1].interm.function); (yyval.interm).loc = (yyvsp[0].lex).loc; } -#line 4102 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5000 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 101: -#line 788 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 107: +#line 861 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.function) = (yyvsp[0].interm.function); } -#line 4110 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5008 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 102: -#line 791 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 108: +#line 864 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.function) = (yyvsp[0].interm.function); } -#line 4118 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5016 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 103: -#line 798 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 109: +#line 871 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { // Add the parameter (yyval.interm.function) = (yyvsp[-1].interm.function); @@ -4127,11 +5025,11 @@ yyreduce: else delete (yyvsp[0].interm).param.type; } -#line 4131 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5029 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 104: -#line 806 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 110: +#line 879 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { // // Only first parameter of one-parameter functions can be void @@ -4149,11 +5047,11 @@ yyreduce: (yyvsp[-2].interm.function)->addParameter((yyvsp[0].interm).param); } } -#line 4153 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5051 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 105: -#line 826 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 111: +#line 899 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { if ((yyvsp[-2].interm.type).qualifier.storage != EvqGlobal && (yyvsp[-2].interm.type).qualifier.storage != EvqTemporary) { parseContext.error((yyvsp[-1].lex).loc, "no qualifiers allowed for function return", @@ -4165,14 +5063,19 @@ yyreduce: // Add the function as a prototype after parsing it (we do not support recursion) TFunction *function; TType type((yyvsp[-2].interm.type)); + + // Potentially rename shader entry point function. No-op most of the time. + parseContext.renameShaderFunction((yyvsp[-1].lex).string); + + // Make the function function = new TFunction((yyvsp[-1].lex).string, type); (yyval.interm.function) = function; } -#line 4172 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5075 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 106: -#line 844 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 112: +#line 922 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { if ((yyvsp[-1].interm.type).arraySizes) { parseContext.profileRequires((yyvsp[-1].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); @@ -4188,33 +5091,35 @@ yyreduce: (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).param = param; } -#line 4192 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5095 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 107: -#line 859 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 113: +#line 937 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { if ((yyvsp[-2].interm.type).arraySizes) { parseContext.profileRequires((yyvsp[-2].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); parseContext.profileRequires((yyvsp[-2].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); parseContext.arraySizeRequiredCheck((yyvsp[-2].interm.type).loc, *(yyvsp[-2].interm.type).arraySizes); } - parseContext.arrayDimCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.type).arraySizes, (yyvsp[0].interm).arraySizes); + TType* type = new TType((yyvsp[-2].interm.type)); + type->transferArraySizes((yyvsp[0].interm).arraySizes); + type->copyArrayInnerSizes((yyvsp[-2].interm.type).arraySizes); + parseContext.arrayOfArrayVersionCheck((yyvsp[-1].lex).loc, type->getArraySizes()); parseContext.arraySizeRequiredCheck((yyvsp[0].interm).loc, *(yyvsp[0].interm).arraySizes); parseContext.reservedErrorCheck((yyvsp[-1].lex).loc, *(yyvsp[-1].lex).string); - (yyvsp[-2].interm.type).arraySizes = (yyvsp[0].interm).arraySizes; + TParameter param = { (yyvsp[-1].lex).string, type }; - TParameter param = { (yyvsp[-1].lex).string, new TType((yyvsp[-2].interm.type))}; (yyval.interm).loc = (yyvsp[-1].lex).loc; (yyval.interm).param = param; } -#line 4214 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5119 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 108: -#line 882 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 114: +#line 962 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm) = (yyvsp[0].interm); if ((yyvsp[-1].interm.type).qualifier.precision != EpqNone) @@ -4226,23 +5131,23 @@ yyreduce: parseContext.paramCheckFix((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier, *(yyval.interm).param.type); } -#line 4230 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5135 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 109: -#line 893 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 115: +#line 973 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm) = (yyvsp[0].interm); parseContext.parameterTypeCheck((yyvsp[0].interm).loc, EvqIn, *(yyvsp[0].interm).param.type); - parseContext.paramCheckFix((yyvsp[0].interm).loc, EvqTemporary, *(yyval.interm).param.type); + parseContext.paramCheckFixStorage((yyvsp[0].interm).loc, EvqTemporary, *(yyval.interm).param.type); parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier()); } -#line 4242 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5147 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 110: -#line 903 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 116: +#line 983 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm) = (yyvsp[0].interm); if ((yyvsp[-1].interm.type).qualifier.precision != EpqNone) @@ -4253,130 +5158,130 @@ yyreduce: parseContext.parameterTypeCheck((yyvsp[0].interm).loc, (yyvsp[-1].interm.type).qualifier.storage, *(yyval.interm).param.type); parseContext.paramCheckFix((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier, *(yyval.interm).param.type); } -#line 4257 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5162 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 111: -#line 913 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 117: +#line 993 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm) = (yyvsp[0].interm); parseContext.parameterTypeCheck((yyvsp[0].interm).loc, EvqIn, *(yyvsp[0].interm).param.type); - parseContext.paramCheckFix((yyvsp[0].interm).loc, EvqTemporary, *(yyval.interm).param.type); + parseContext.paramCheckFixStorage((yyvsp[0].interm).loc, EvqTemporary, *(yyval.interm).param.type); parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier()); } -#line 4269 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5174 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 112: -#line 923 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 118: +#line 1003 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { TParameter param = { 0, new TType((yyvsp[0].interm.type)) }; (yyval.interm).param = param; if ((yyvsp[0].interm.type).arraySizes) parseContext.arraySizeRequiredCheck((yyvsp[0].interm.type).loc, *(yyvsp[0].interm.type).arraySizes); } -#line 4280 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5185 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 113: -#line 932 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 119: +#line 1012 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm) = (yyvsp[0].interm); } -#line 4288 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5193 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 114: -#line 935 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 120: +#line 1015 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm) = (yyvsp[-2].interm); parseContext.declareVariable((yyvsp[0].lex).loc, *(yyvsp[0].lex).string, (yyvsp[-2].interm).type); } -#line 4297 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5202 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 115: -#line 939 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 121: +#line 1019 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm) = (yyvsp[-3].interm); parseContext.declareVariable((yyvsp[-1].lex).loc, *(yyvsp[-1].lex).string, (yyvsp[-3].interm).type, (yyvsp[0].interm).arraySizes); } -#line 4306 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5211 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 116: -#line 943 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 122: +#line 1023 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).type = (yyvsp[-5].interm).type; TIntermNode* initNode = parseContext.declareVariable((yyvsp[-3].lex).loc, *(yyvsp[-3].lex).string, (yyvsp[-5].interm).type, (yyvsp[-2].interm).arraySizes, (yyvsp[0].interm.intermTypedNode)); (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[-5].interm).intermNode, initNode, (yyvsp[-1].lex).loc); } -#line 4316 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5221 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 117: -#line 948 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 123: +#line 1028 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).type = (yyvsp[-4].interm).type; TIntermNode* initNode = parseContext.declareVariable((yyvsp[-2].lex).loc, *(yyvsp[-2].lex).string, (yyvsp[-4].interm).type, 0, (yyvsp[0].interm.intermTypedNode)); (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[-4].interm).intermNode, initNode, (yyvsp[-1].lex).loc); } -#line 4326 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5231 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 118: -#line 956 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 124: +#line 1036 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).type = (yyvsp[0].interm.type); (yyval.interm).intermNode = 0; parseContext.declareTypeDefaults((yyval.interm).loc, (yyval.interm).type); } -#line 4336 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5241 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 119: -#line 961 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 125: +#line 1041 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).type = (yyvsp[-1].interm.type); (yyval.interm).intermNode = 0; parseContext.declareVariable((yyvsp[0].lex).loc, *(yyvsp[0].lex).string, (yyvsp[-1].interm.type)); } -#line 4346 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5251 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 120: -#line 966 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 126: +#line 1046 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).type = (yyvsp[-2].interm.type); (yyval.interm).intermNode = 0; parseContext.declareVariable((yyvsp[-1].lex).loc, *(yyvsp[-1].lex).string, (yyvsp[-2].interm.type), (yyvsp[0].interm).arraySizes); } -#line 4356 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5261 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 121: -#line 971 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 127: +#line 1051 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).type = (yyvsp[-4].interm.type); TIntermNode* initNode = parseContext.declareVariable((yyvsp[-3].lex).loc, *(yyvsp[-3].lex).string, (yyvsp[-4].interm.type), (yyvsp[-2].interm).arraySizes, (yyvsp[0].interm.intermTypedNode)); (yyval.interm).intermNode = parseContext.intermediate.growAggregate(0, initNode, (yyvsp[-1].lex).loc); } -#line 4366 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5271 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 122: -#line 976 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 128: +#line 1056 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).type = (yyvsp[-3].interm.type); TIntermNode* initNode = parseContext.declareVariable((yyvsp[-2].lex).loc, *(yyvsp[-2].lex).string, (yyvsp[-3].interm.type), 0, (yyvsp[0].interm.intermTypedNode)); (yyval.interm).intermNode = parseContext.intermediate.growAggregate(0, initNode, (yyvsp[-1].lex).loc); } -#line 4376 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5281 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 123: -#line 985 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 129: +#line 1065 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type) = (yyvsp[0].interm.type); @@ -4388,11 +5293,11 @@ yyreduce: parseContext.precisionQualifierCheck((yyval.interm.type).loc, (yyval.interm.type).basicType, (yyval.interm.type).qualifier); } -#line 4392 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5297 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 124: -#line 996 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 130: +#line 1076 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.globalQualifierFixCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier); parseContext.globalQualifierTypeCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier, (yyvsp[0].interm.type)); @@ -4403,7 +5308,7 @@ yyreduce: } if ((yyvsp[0].interm.type).arraySizes && parseContext.arrayQualifierError((yyvsp[0].interm.type).loc, (yyvsp[-1].interm.type).qualifier)) - (yyvsp[0].interm.type).arraySizes = 0; + (yyvsp[0].interm.type).arraySizes = nullptr; parseContext.checkNoShaderLayouts((yyvsp[0].interm.type).loc, (yyvsp[-1].interm.type).shaderQualifiers); (yyvsp[0].interm.type).shaderQualifiers.merge((yyvsp[-1].interm.type).shaderQualifiers); @@ -4417,22 +5322,22 @@ yyreduce: (parseContext.language == EShLangFragment && (yyval.interm.type).qualifier.storage == EvqVaryingIn))) (yyval.interm.type).qualifier.smooth = true; } -#line 4421 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5326 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 125: -#line 1023 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 131: +#line 1103 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.globalCheck((yyvsp[0].lex).loc, "invariant"); parseContext.profileRequires((yyval.interm.type).loc, ENoProfile, 120, 0, "invariant"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.invariant = true; } -#line 4432 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5337 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 126: -#line 1032 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 132: +#line 1112 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.globalCheck((yyvsp[0].lex).loc, "smooth"); parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "smooth"); @@ -4440,11 +5345,11 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.smooth = true; } -#line 4444 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5349 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 127: -#line 1039 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 133: +#line 1119 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.globalCheck((yyvsp[0].lex).loc, "flat"); parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "flat"); @@ -4452,96 +5357,114 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.flat = true; } -#line 4456 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5361 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 128: -#line 1046 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 134: +#line 1126 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.globalCheck((yyvsp[0].lex).loc, "noperspective"); +#ifdef NV_EXTENSIONS + parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 0, E_GL_NV_shader_noperspective_interpolation, "noperspective"); +#else parseContext.requireProfile((yyvsp[0].lex).loc, ~EEsProfile, "noperspective"); +#endif parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "noperspective"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.nopersp = true; } -#line 4468 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5377 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 129: -#line 1056 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 135: +#line 1137 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.globalCheck((yyvsp[0].lex).loc, "__explicitInterpAMD"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 450, E_GL_AMD_shader_explicit_vertex_parameter, "explicit interpolation"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECompatibilityProfile, 450, E_GL_AMD_shader_explicit_vertex_parameter, "explicit interpolation"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.explicitInterp = true; +#endif + } +#line 5391 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 136: +#line 1149 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type) = (yyvsp[-1].interm.type); } -#line 4476 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5399 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 130: -#line 1062 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 137: +#line 1155 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 4484 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5407 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 131: -#line 1065 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 138: +#line 1158 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type) = (yyvsp[-2].interm.type); (yyval.interm.type).shaderQualifiers.merge((yyvsp[0].interm.type).shaderQualifiers); parseContext.mergeObjectLayoutQualifiers((yyval.interm.type).qualifier, (yyvsp[0].interm.type).qualifier, false); } -#line 4494 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5417 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 132: -#line 1072 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 139: +#line 1165 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc); parseContext.setLayoutQualifier((yyvsp[0].lex).loc, (yyval.interm.type), *(yyvsp[0].lex).string); } -#line 4503 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5426 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 133: -#line 1076 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 140: +#line 1169 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[-2].lex).loc); parseContext.setLayoutQualifier((yyvsp[-2].lex).loc, (yyval.interm.type), *(yyvsp[-2].lex).string, (yyvsp[0].interm.intermTypedNode)); } -#line 4512 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5435 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 134: -#line 1080 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 141: +#line 1173 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { // because "shared" is both an identifier and a keyword (yyval.interm.type).init((yyvsp[0].lex).loc); TString strShared("shared"); parseContext.setLayoutQualifier((yyvsp[0].lex).loc, (yyval.interm.type), strShared); } -#line 4522 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5445 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 135: -#line 1088 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 142: +#line 1181 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.profileRequires((yyval.interm.type).loc, ECoreProfile | ECompatibilityProfile, 400, E_GL_ARB_gpu_shader5, "precise"); parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 320, Num_AEP_gpu_shader5, AEP_gpu_shader5, "precise"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.noContraction = true; } -#line 4533 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5456 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 136: -#line 1097 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 143: +#line 1190 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 4541 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5464 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 137: -#line 1100 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 144: +#line 1193 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type) = (yyvsp[-1].interm.type); if ((yyval.interm.type).basicType == EbtVoid) @@ -4550,71 +5473,80 @@ yyreduce: (yyval.interm.type).shaderQualifiers.merge((yyvsp[0].interm.type).shaderQualifiers); parseContext.mergeQualifiers((yyval.interm.type).loc, (yyval.interm.type).qualifier, (yyvsp[0].interm.type).qualifier, false); } -#line 4554 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5477 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 138: -#line 1111 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 145: +#line 1204 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 4562 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5485 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 139: -#line 1114 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 146: +#line 1207 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 4570 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5493 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 140: -#line 1117 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 147: +#line 1210 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { + parseContext.checkPrecisionQualifier((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type).qualifier.precision); (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 4578 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5502 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 141: -#line 1120 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 148: +#line 1214 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { // allow inheritance of storage qualifier from block declaration (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 4587 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5511 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 142: -#line 1124 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 149: +#line 1218 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { // allow inheritance of storage qualifier from block declaration (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 4596 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5520 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 143: -#line 1128 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 150: +#line 1222 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { // allow inheritance of storage qualifier from block declaration (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 4605 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5529 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 144: -#line 1135 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 151: +#line 1226 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 5537 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 152: +#line 1232 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqConst; // will later turn into EvqConstReadOnly, if the initializer is not constant } -#line 4614 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5546 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 145: -#line 1139 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 153: +#line 1236 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.requireStage((yyvsp[0].lex).loc, EShLangVertex, "attribute"); parseContext.checkDeprecated((yyvsp[0].lex).loc, ECoreProfile, 130, "attribute"); @@ -4627,11 +5559,11 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqVaryingIn; } -#line 4631 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5563 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 146: -#line 1151 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 154: +#line 1248 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.checkDeprecated((yyvsp[0].lex).loc, ENoProfile, 130, "varying"); parseContext.checkDeprecated((yyvsp[0].lex).loc, ECoreProfile, 130, "varying"); @@ -4646,43 +5578,43 @@ yyreduce: else (yyval.interm.type).qualifier.storage = EvqVaryingIn; } -#line 4650 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5582 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 147: -#line 1165 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 155: +#line 1262 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.globalCheck((yyvsp[0].lex).loc, "inout"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqInOut; } -#line 4660 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5592 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 148: -#line 1170 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 156: +#line 1267 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.globalCheck((yyvsp[0].lex).loc, "in"); (yyval.interm.type).init((yyvsp[0].lex).loc); // whether this is a parameter "in" or a pipeline "in" will get sorted out a bit later (yyval.interm.type).qualifier.storage = EvqIn; } -#line 4671 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5603 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 149: -#line 1176 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 157: +#line 1273 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.globalCheck((yyvsp[0].lex).loc, "out"); (yyval.interm.type).init((yyvsp[0].lex).loc); // whether this is a parameter "out" or a pipeline "out" will get sorted out a bit later (yyval.interm.type).qualifier.storage = EvqOut; } -#line 4682 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5614 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 150: -#line 1182 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 158: +#line 1279 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 120, 0, "centroid"); parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 300, 0, "centroid"); @@ -4690,179 +5622,189 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.centroid = true; } -#line 4694 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5626 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 151: -#line 1189 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 159: +#line 1286 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.globalCheck((yyvsp[0].lex).loc, "patch"); parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangTessControlMask | EShLangTessEvaluationMask), "patch"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.patch = true; } -#line 4705 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5637 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 152: -#line 1195 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 160: +#line 1292 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.globalCheck((yyvsp[0].lex).loc, "sample"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.sample = true; } -#line 4715 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5647 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 153: -#line 1200 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 161: +#line 1297 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.globalCheck((yyvsp[0].lex).loc, "uniform"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqUniform; } -#line 4725 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5657 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 154: -#line 1205 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 162: +#line 1302 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.globalCheck((yyvsp[0].lex).loc, "buffer"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqBuffer; } -#line 4735 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5667 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 155: -#line 1210 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 163: +#line 1307 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { + parseContext.globalCheck((yyvsp[0].lex).loc, "shared"); parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, 430, E_GL_ARB_compute_shader, "shared"); parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 310, 0, "shared"); parseContext.requireStage((yyvsp[0].lex).loc, EShLangCompute, "shared"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqShared; } -#line 4747 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5680 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 156: -#line 1217 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 164: +#line 1315 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.coherent = true; } -#line 4756 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5689 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 157: -#line 1221 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 165: +#line 1319 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.volatil = true; } -#line 4765 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5698 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 158: -#line 1225 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 166: +#line 1323 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.restrict = true; } -#line 4774 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5707 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 159: -#line 1229 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 167: +#line 1327 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.readonly = true; } -#line 4783 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5716 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 160: -#line 1233 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 168: +#line 1331 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.writeonly = true; } -#line 4792 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5725 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 161: -#line 1237 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 169: +#line 1335 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.spvRemoved((yyvsp[0].lex).loc, "subroutine"); parseContext.globalCheck((yyvsp[0].lex).loc, "subroutine"); + parseContext.unimplemented((yyvsp[0].lex).loc, "subroutine"); (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.storage = EvqUniform; } -#line 4803 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5736 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 162: -#line 1243 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 170: +#line 1341 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.spvRemoved((yyvsp[-3].lex).loc, "subroutine"); parseContext.globalCheck((yyvsp[-3].lex).loc, "subroutine"); + parseContext.unimplemented((yyvsp[-3].lex).loc, "subroutine"); (yyval.interm.type).init((yyvsp[-3].lex).loc); - (yyval.interm.type).qualifier.storage = EvqUniform; + } +#line 5747 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 171: +#line 1350 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.nonUniform = true; + } +#line 5756 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 172: +#line 1357 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + // TODO + } +#line 5764 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 173: +#line 1360 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { // TODO: 4.0 semantics: subroutines // 1) make sure each identifier is a type declared earlier with SUBROUTINE // 2) save all of the identifiers for future comparison with the declared function } -#line 4817 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5774 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 163: -#line 1255 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - // TODO: 4.0 functionality: subroutine type to list - } -#line 4825 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 164: -#line 1258 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - } -#line 4832 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 165: -#line 1263 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 174: +#line 1368 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type) = (yyvsp[0].interm.type); (yyval.interm.type).qualifier.precision = parseContext.getDefaultPrecision((yyval.interm.type)); } -#line 4841 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5783 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 166: -#line 1267 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 175: +#line 1372 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { - parseContext.arrayDimCheck((yyvsp[0].interm).loc, (yyvsp[0].interm).arraySizes, 0); + parseContext.arrayOfArrayVersionCheck((yyvsp[0].interm).loc, (yyvsp[0].interm).arraySizes); (yyval.interm.type) = (yyvsp[-1].interm.type); (yyval.interm.type).qualifier.precision = parseContext.getDefaultPrecision((yyval.interm.type)); (yyval.interm.type).arraySizes = (yyvsp[0].interm).arraySizes; } -#line 4852 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5794 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 167: -#line 1276 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 176: +#line 1381 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).loc = (yyvsp[-1].lex).loc; (yyval.interm).arraySizes = new TArraySizes; (yyval.interm).arraySizes->addInnerSize(); } -#line 4862 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5804 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 168: -#line 1281 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 177: +#line 1386 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm).loc = (yyvsp[-2].lex).loc; (yyval.interm).arraySizes = new TArraySizes; @@ -4871,20 +5813,20 @@ yyreduce: parseContext.arraySizeCheck((yyvsp[-1].interm.intermTypedNode)->getLoc(), (yyvsp[-1].interm.intermTypedNode), size); (yyval.interm).arraySizes->addInnerSize(size); } -#line 4875 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5817 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 169: -#line 1289 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 178: +#line 1394 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm) = (yyvsp[-2].interm); (yyval.interm).arraySizes->addInnerSize(); } -#line 4884 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5826 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 170: -#line 1293 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 179: +#line 1398 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm) = (yyvsp[-3].interm); @@ -4892,1738 +5834,3069 @@ yyreduce: parseContext.arraySizeCheck((yyvsp[-1].interm.intermTypedNode)->getLoc(), (yyvsp[-1].interm.intermTypedNode), size); (yyval.interm).arraySizes->addInnerSize(size); } -#line 4896 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5838 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 171: -#line 1303 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 180: +#line 1408 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtVoid; } -#line 4905 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5847 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 172: -#line 1307 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 181: +#line 1412 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; } -#line 4914 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5856 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 173: -#line 1311 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 182: +#line 1416 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.doubleCheck((yyvsp[0].lex).loc, "double"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; } -#line 4924 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5866 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 174: -#line 1316 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 183: +#line 1421 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.float16Check((yyvsp[0].lex).loc, "float16_t", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + } +#line 5876 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 184: +#line 1426 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + } +#line 5886 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 185: +#line 1431 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + } +#line 5896 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 186: +#line 1436 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt; } -#line 4933 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5905 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 175: -#line 1320 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 187: +#line 1440 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtUint; } -#line 4943 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5915 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 176: -#line 1325 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 188: +#line 1445 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt8Check((yyvsp[0].lex).loc, "8-bit signed integer", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt8; + } +#line 5925 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 189: +#line 1450 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt8Check((yyvsp[0].lex).loc, "8-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint8; + } +#line 5935 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 190: +#line 1455 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt16Check((yyvsp[0].lex).loc, "16-bit signed integer", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt16; + } +#line 5945 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 191: +#line 1460 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt16Check((yyvsp[0].lex).loc, "16-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint16; + } +#line 5955 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 192: +#line 1465 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed integer", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + } +#line 5965 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 193: +#line 1470 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + } +#line 5975 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 194: +#line 1475 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt64; } -#line 4953 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5985 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 177: -#line 1330 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 195: +#line 1480 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtUint64; } -#line 4963 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 178: -#line 1335 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtBool; - } -#line 4972 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 179: -#line 1339 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setVector(2); - } -#line 4982 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 180: -#line 1344 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setVector(3); - } -#line 4992 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 181: -#line 1349 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setVector(4); - } -#line 5002 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 182: -#line 1354 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setVector(2); - } -#line 5013 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 183: -#line 1360 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setVector(3); - } -#line 5024 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 184: -#line 1366 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setVector(4); - } -#line 5035 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 185: -#line 1372 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtBool; - (yyval.interm.type).setVector(2); - } -#line 5045 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 186: -#line 1377 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtBool; - (yyval.interm.type).setVector(3); - } -#line 5055 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 187: -#line 1382 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtBool; - (yyval.interm.type).setVector(4); - } -#line 5065 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 188: -#line 1387 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt; - (yyval.interm.type).setVector(2); - } -#line 5075 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 189: -#line 1392 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt; - (yyval.interm.type).setVector(3); - } -#line 5085 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 190: -#line 1397 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt; - (yyval.interm.type).setVector(4); - } -#line 5095 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 191: -#line 1402 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt64; - (yyval.interm.type).setVector(2); - } -#line 5106 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 192: -#line 1408 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt64; - (yyval.interm.type).setVector(3); - } -#line 5117 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 193: -#line 1414 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt64; - (yyval.interm.type).setVector(4); - } -#line 5128 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 194: -#line 1420 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer vector"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint; - (yyval.interm.type).setVector(2); - } -#line 5139 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 195: -#line 1426 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer vector"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint; - (yyval.interm.type).setVector(3); - } -#line 5150 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 5995 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; case 196: -#line 1432 "MachineIndependent/glslang.y" /* yacc.c:1646 */ +#line 1485 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtBool; + } +#line 6004 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 197: +#line 1489 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(2); + } +#line 6014 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 198: +#line 1494 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(3); + } +#line 6024 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 199: +#line 1499 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(4); + } +#line 6034 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 200: +#line 1504 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(2); + } +#line 6045 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 201: +#line 1510 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(3); + } +#line 6056 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 202: +#line 1516 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(4); + } +#line 6067 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 203: +#line 1522 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setVector(2); + } +#line 6078 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 204: +#line 1528 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setVector(3); + } +#line 6089 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 205: +#line 1534 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setVector(4); + } +#line 6100 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 206: +#line 1540 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(2); + } +#line 6111 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 207: +#line 1546 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(3); + } +#line 6122 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 208: +#line 1552 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(4); + } +#line 6133 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 209: +#line 1558 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(2); + } +#line 6144 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 210: +#line 1564 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(3); + } +#line 6155 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 211: +#line 1570 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(4); + } +#line 6166 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 212: +#line 1576 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtBool; + (yyval.interm.type).setVector(2); + } +#line 6176 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 213: +#line 1581 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtBool; + (yyval.interm.type).setVector(3); + } +#line 6186 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 214: +#line 1586 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtBool; + (yyval.interm.type).setVector(4); + } +#line 6196 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 215: +#line 1591 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + (yyval.interm.type).setVector(2); + } +#line 6206 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 216: +#line 1596 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + (yyval.interm.type).setVector(3); + } +#line 6216 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 217: +#line 1601 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + (yyval.interm.type).setVector(4); + } +#line 6226 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 218: +#line 1606 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt8Check((yyvsp[0].lex).loc, "8-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt8; + (yyval.interm.type).setVector(2); + } +#line 6237 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 219: +#line 1612 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt8Check((yyvsp[0].lex).loc, "8-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt8; + (yyval.interm.type).setVector(3); + } +#line 6248 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 220: +#line 1618 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt8Check((yyvsp[0].lex).loc, "8-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt8; + (yyval.interm.type).setVector(4); + } +#line 6259 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 221: +#line 1624 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt16Check((yyvsp[0].lex).loc, "16-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt16; + (yyval.interm.type).setVector(2); + } +#line 6270 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 222: +#line 1630 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt16Check((yyvsp[0].lex).loc, "16-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt16; + (yyval.interm.type).setVector(3); + } +#line 6281 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 223: +#line 1636 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt16Check((yyvsp[0].lex).loc, "16-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt16; + (yyval.interm.type).setVector(4); + } +#line 6292 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 224: +#line 1642 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + (yyval.interm.type).setVector(2); + } +#line 6303 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 225: +#line 1648 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + (yyval.interm.type).setVector(3); + } +#line 6314 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 226: +#line 1654 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + (yyval.interm.type).setVector(4); + } +#line 6325 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 227: +#line 1660 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt64; + (yyval.interm.type).setVector(2); + } +#line 6336 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 228: +#line 1666 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt64; + (yyval.interm.type).setVector(3); + } +#line 6347 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 229: +#line 1672 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt64; + (yyval.interm.type).setVector(4); + } +#line 6358 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 230: +#line 1678 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + (yyval.interm.type).setVector(2); + } +#line 6369 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 231: +#line 1684 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + (yyval.interm.type).setVector(3); + } +#line 6380 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 232: +#line 1690 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer vector"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtUint; (yyval.interm.type).setVector(4); } -#line 5161 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6391 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 197: -#line 1438 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 233: +#line 1696 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt8Check((yyvsp[0].lex).loc, "8-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint8; + (yyval.interm.type).setVector(2); + } +#line 6402 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 234: +#line 1702 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt8Check((yyvsp[0].lex).loc, "8-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt8; + (yyval.interm.type).setVector(3); + } +#line 6413 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 235: +#line 1708 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt8Check((yyvsp[0].lex).loc, "8-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint8; + (yyval.interm.type).setVector(4); + } +#line 6424 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 236: +#line 1714 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt16Check((yyvsp[0].lex).loc, "16-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint16; + (yyval.interm.type).setVector(2); + } +#line 6435 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 237: +#line 1720 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt16Check((yyvsp[0].lex).loc, "16-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint16; + (yyval.interm.type).setVector(3); + } +#line 6446 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 238: +#line 1726 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt16Check((yyvsp[0].lex).loc, "16-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint16; + (yyval.interm.type).setVector(4); + } +#line 6457 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 239: +#line 1732 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + (yyval.interm.type).setVector(2); + } +#line 6468 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 240: +#line 1738 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + (yyval.interm.type).setVector(3); + } +#line 6479 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 241: +#line 1744 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + (yyval.interm.type).setVector(4); + } +#line 6490 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 242: +#line 1750 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtUint64; (yyval.interm.type).setVector(2); } -#line 5172 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6501 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 198: -#line 1444 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 243: +#line 1756 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtUint64; (yyval.interm.type).setVector(3); } -#line 5183 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6512 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 199: -#line 1450 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 244: +#line 1762 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtUint64; (yyval.interm.type).setVector(4); } -#line 5194 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6523 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 200: -#line 1456 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 245: +#line 1768 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(2, 2); } -#line 5204 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6533 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 201: -#line 1461 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 246: +#line 1773 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(3, 3); } -#line 5214 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6543 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 202: -#line 1466 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 247: +#line 1778 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(4, 4); } -#line 5224 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6553 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 203: -#line 1471 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 248: +#line 1783 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(2, 2); } -#line 5234 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6563 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 204: -#line 1476 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 249: +#line 1788 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(2, 3); } -#line 5244 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6573 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 205: -#line 1481 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 250: +#line 1793 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(2, 4); } -#line 5254 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6583 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 206: -#line 1486 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 251: +#line 1798 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(3, 2); } -#line 5264 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6593 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 207: -#line 1491 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 252: +#line 1803 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(3, 3); } -#line 5274 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6603 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 208: -#line 1496 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 253: +#line 1808 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(3, 4); } -#line 5284 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6613 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 209: -#line 1501 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 254: +#line 1813 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(4, 2); } -#line 5294 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6623 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 210: -#line 1506 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 255: +#line 1818 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(4, 3); } -#line 5304 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6633 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 211: -#line 1511 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 256: +#line 1823 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(4, 4); } -#line 5314 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6643 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 212: -#line 1516 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 257: +#line 1828 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(2, 2); } -#line 5325 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6654 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 213: -#line 1522 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 258: +#line 1834 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(3, 3); } -#line 5336 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6665 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 214: -#line 1528 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 259: +#line 1840 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(4, 4); } -#line 5347 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6676 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 215: -#line 1534 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 260: +#line 1846 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(2, 2); } -#line 5358 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6687 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 216: -#line 1540 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 261: +#line 1852 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(2, 3); } -#line 5369 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6698 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 217: -#line 1546 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 262: +#line 1858 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(2, 4); } -#line 5380 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6709 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 218: -#line 1552 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 263: +#line 1864 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(3, 2); } -#line 5391 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6720 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 219: -#line 1558 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 264: +#line 1870 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(3, 3); } -#line 5402 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6731 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 220: -#line 1564 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 265: +#line 1876 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(3, 4); } -#line 5413 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6742 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 221: -#line 1570 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 266: +#line 1882 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(4, 2); } -#line 5424 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6753 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 222: -#line 1576 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 267: +#line 1888 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(4, 3); } -#line 5435 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6764 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 223: -#line 1582 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 268: +#line 1894 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(4, 4); } -#line 5446 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 6775 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 224: -#line 1588 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 269: +#line 1900 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(2, 2); + } +#line 6786 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 270: +#line 1906 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(3, 3); + } +#line 6797 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 271: +#line 1912 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(4, 4); + } +#line 6808 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 272: +#line 1918 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(2, 2); + } +#line 6819 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 273: +#line 1924 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(2, 3); + } +#line 6830 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 274: +#line 1930 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(2, 4); + } +#line 6841 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 275: +#line 1936 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(3, 2); + } +#line 6852 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 276: +#line 1942 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(3, 3); + } +#line 6863 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 277: +#line 1948 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(3, 4); + } +#line 6874 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 278: +#line 1954 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(4, 2); + } +#line 6885 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 279: +#line 1960 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(4, 3); + } +#line 6896 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 280: +#line 1966 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(4, 4); + } +#line 6907 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 281: +#line 1972 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(2, 2); + } +#line 6918 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 282: +#line 1978 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(3, 3); + } +#line 6929 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 283: +#line 1984 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(4, 4); + } +#line 6940 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 284: +#line 1990 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(2, 2); + } +#line 6951 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 285: +#line 1996 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(2, 3); + } +#line 6962 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 286: +#line 2002 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(2, 4); + } +#line 6973 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 287: +#line 2008 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(3, 2); + } +#line 6984 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 288: +#line 2014 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(3, 3); + } +#line 6995 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 289: +#line 2020 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(3, 4); + } +#line 7006 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 290: +#line 2026 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(4, 2); + } +#line 7017 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 291: +#line 2032 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(4, 3); + } +#line 7028 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 292: +#line 2038 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(4, 4); + } +#line 7039 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 293: +#line 2044 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(2, 2); + } +#line 7050 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 294: +#line 2050 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(3, 3); + } +#line 7061 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 295: +#line 2056 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(4, 4); + } +#line 7072 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 296: +#line 2062 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(2, 2); + } +#line 7083 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 297: +#line 2068 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(2, 3); + } +#line 7094 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 298: +#line 2074 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(2, 4); + } +#line 7105 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 299: +#line 2080 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(3, 2); + } +#line 7116 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 300: +#line 2086 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(3, 3); + } +#line 7127 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 301: +#line 2092 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(3, 4); + } +#line 7138 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 302: +#line 2098 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(4, 2); + } +#line 7149 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 303: +#line 2104 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(4, 3); + } +#line 7160 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 304: +#line 2110 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(4, 4); + } +#line 7171 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 305: +#line 2116 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.vulkanRemoved((yyvsp[0].lex).loc, "atomic counter types"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtAtomicUint; } -#line 5456 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7181 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 225: -#line 1593 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 306: +#line 2121 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd1D); } -#line 5466 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7191 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 226: -#line 1598 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 307: +#line 2126 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd2D); } -#line 5476 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7201 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 227: -#line 1603 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 308: +#line 2131 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd3D); } -#line 5486 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7211 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 228: -#line 1608 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 309: +#line 2136 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, EsdCube); } -#line 5496 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7221 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 229: -#line 1613 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 310: +#line 2141 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd1D, false, true); } -#line 5506 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7231 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 230: -#line 1618 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 311: +#line 2146 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd2D, false, true); } -#line 5516 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7241 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 231: -#line 1623 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 312: +#line 2151 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, EsdCube, false, true); } -#line 5526 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7251 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 232: -#line 1628 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 313: +#line 2156 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd1D, true); } -#line 5536 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7261 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 233: -#line 1633 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 314: +#line 2161 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd2D, true); } -#line 5546 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7271 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 234: -#line 1638 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 315: +#line 2166 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd1D, true, true); } -#line 5556 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7281 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 235: -#line 1643 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 316: +#line 2171 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd2D, true, true); } -#line 5566 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7291 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 236: -#line 1648 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 317: +#line 2176 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, EsdCube, true); } -#line 5576 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7301 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 237: -#line 1653 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 318: +#line 2181 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, EsdCube, true, true); } -#line 5586 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7311 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 238: -#line 1658 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 319: +#line 2186 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd1D); +#endif + } +#line 7324 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 320: +#line 2194 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd2D); +#endif + } +#line 7337 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 321: +#line 2202 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd3D); +#endif + } +#line 7350 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 322: +#line 2210 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, EsdCube); +#endif + } +#line 7363 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 323: +#line 2218 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd1D, false, true); +#endif + } +#line 7376 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 324: +#line 2226 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, false, true); +#endif + } +#line 7389 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 325: +#line 2234 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, EsdCube, false, true); +#endif + } +#line 7402 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 326: +#line 2242 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd1D, true); +#endif + } +#line 7415 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 327: +#line 2250 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, true); +#endif + } +#line 7428 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 328: +#line 2258 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd1D, true, true); +#endif + } +#line 7441 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 329: +#line 2266 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, true, true); +#endif + } +#line 7454 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 330: +#line 2274 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, EsdCube, true); +#endif + } +#line 7467 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 331: +#line 2282 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, EsdCube, true, true); +#endif + } +#line 7480 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 332: +#line 2290 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, Esd1D); } -#line 5596 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7490 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 239: -#line 1663 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 333: +#line 2295 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, Esd2D); } -#line 5606 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7500 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 240: -#line 1668 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 334: +#line 2300 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, Esd3D); } -#line 5616 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7510 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 241: -#line 1673 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 335: +#line 2305 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, EsdCube); } -#line 5626 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7520 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 242: -#line 1678 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 336: +#line 2310 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, Esd1D, true); } -#line 5636 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7530 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 243: -#line 1683 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 337: +#line 2315 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, Esd2D, true); } -#line 5646 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7540 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 244: -#line 1688 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 338: +#line 2320 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, EsdCube, true); } -#line 5656 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7550 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 245: -#line 1693 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 339: +#line 2325 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, Esd1D); } -#line 5666 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7560 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 246: -#line 1698 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 340: +#line 2330 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, Esd2D); } -#line 5676 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7570 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 247: -#line 1703 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 341: +#line 2335 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, Esd3D); } -#line 5686 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7580 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 248: -#line 1708 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 342: +#line 2340 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, EsdCube); } -#line 5696 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7590 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 249: -#line 1713 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 343: +#line 2345 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, Esd1D, true); } -#line 5706 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7600 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 250: -#line 1718 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 344: +#line 2350 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, Esd2D, true); } -#line 5716 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7610 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 251: -#line 1723 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 345: +#line 2355 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, EsdCube, true); } -#line 5726 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7620 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 252: -#line 1728 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 346: +#line 2360 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, EsdRect); } -#line 5736 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7630 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 253: -#line 1733 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 347: +#line 2365 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, EsdRect, false, true); } -#line 5746 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7640 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 254: -#line 1738 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 348: +#line 2370 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, EsdRect); +#endif + } +#line 7653 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 349: +#line 2378 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, EsdRect, false, true); +#endif + } +#line 7666 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 350: +#line 2386 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, EsdRect); } -#line 5756 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7676 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 255: -#line 1743 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 351: +#line 2391 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, EsdRect); } -#line 5766 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7686 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 256: -#line 1748 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 352: +#line 2396 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, EsdBuffer); } -#line 5776 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7696 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 257: -#line 1753 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 353: +#line 2401 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, EsdBuffer); +#endif + } +#line 7709 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 354: +#line 2409 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, EsdBuffer); } -#line 5786 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7719 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 258: -#line 1758 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 355: +#line 2414 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, EsdBuffer); } -#line 5796 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7729 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 259: -#line 1763 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 356: +#line 2419 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd2D, false, false, true); } -#line 5806 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7739 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 260: -#line 1768 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 357: +#line 2424 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, false, false, true); +#endif + } +#line 7752 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 358: +#line 2432 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, Esd2D, false, false, true); } -#line 5816 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7762 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 261: -#line 1773 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 359: +#line 2437 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, Esd2D, false, false, true); } -#line 5826 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7772 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 262: -#line 1778 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 360: +#line 2442 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd2D, true, false, true); } -#line 5836 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7782 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 263: -#line 1783 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 361: +#line 2447 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, true, false, true); +#endif + } +#line 7795 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 362: +#line 2455 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, Esd2D, true, false, true); } -#line 5846 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7805 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 264: -#line 1788 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 363: +#line 2460 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, Esd2D, true, false, true); } -#line 5856 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7815 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 265: -#line 1793 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 364: +#line 2465 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setPureSampler(false); } -#line 5866 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7825 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 266: -#line 1798 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 365: +#line 2470 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setPureSampler(true); } -#line 5876 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7835 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 267: -#line 1803 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 366: +#line 2475 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, Esd1D); } -#line 5886 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7845 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 268: -#line 1808 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 367: +#line 2480 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd1D); +#endif + } +#line 7858 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 368: +#line 2488 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D); } -#line 5896 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7868 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 269: -#line 1813 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 369: +#line 2493 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd2D); +#endif + } +#line 7881 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 370: +#line 2501 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, Esd3D); } -#line 5906 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7891 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 270: -#line 1818 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 371: +#line 2506 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd3D); +#endif + } +#line 7904 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 372: +#line 2514 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, EsdCube); } -#line 5916 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7914 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 271: -#line 1823 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 373: +#line 2519 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, EsdCube); +#endif + } +#line 7927 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 374: +#line 2527 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, Esd1D, true); } -#line 5926 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7937 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 272: -#line 1828 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 375: +#line 2532 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd1D, true); +#endif + } +#line 7950 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 376: +#line 2540 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D, true); } -#line 5936 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7960 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 273: -#line 1833 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 377: +#line 2545 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd2D, true); +#endif + } +#line 7973 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 378: +#line 2553 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, EsdCube, true); } -#line 5946 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 7983 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 274: -#line 1838 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 379: +#line 2558 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, EsdCube, true); +#endif + } +#line 7996 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 380: +#line 2566 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, Esd1D); } -#line 5956 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8006 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 275: -#line 1843 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 381: +#line 2571 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D); } -#line 5966 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8016 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 276: -#line 1848 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 382: +#line 2576 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, Esd3D); } -#line 5976 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8026 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 277: -#line 1853 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 383: +#line 2581 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, EsdCube); } -#line 5986 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8036 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 278: -#line 1858 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 384: +#line 2586 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, Esd1D, true); } -#line 5996 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8046 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 279: -#line 1863 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 385: +#line 2591 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D, true); } -#line 6006 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8056 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 280: -#line 1868 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 386: +#line 2596 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, EsdCube, true); } -#line 6016 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8066 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 281: -#line 1873 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 387: +#line 2601 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, Esd1D); } -#line 6026 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8076 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 282: -#line 1878 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 388: +#line 2606 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D); } -#line 6036 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8086 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 283: -#line 1883 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 389: +#line 2611 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, Esd3D); } -#line 6046 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8096 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 284: -#line 1888 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 390: +#line 2616 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, EsdCube); } -#line 6056 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8106 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 285: -#line 1893 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 391: +#line 2621 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, Esd1D, true); } -#line 6066 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8116 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 286: -#line 1898 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 392: +#line 2626 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D, true); } -#line 6076 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8126 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 287: -#line 1903 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 393: +#line 2631 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, EsdCube, true); } -#line 6086 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8136 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 288: -#line 1908 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 394: +#line 2636 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, EsdRect); } -#line 6096 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8146 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 289: -#line 1913 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 395: +#line 2641 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, EsdRect); +#endif + } +#line 8159 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 396: +#line 2649 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, EsdRect); } -#line 6106 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8169 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 290: -#line 1918 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 397: +#line 2654 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, EsdRect); } -#line 6116 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8179 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 291: -#line 1923 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 398: +#line 2659 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, EsdBuffer); } -#line 6126 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8189 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 292: -#line 1928 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 399: +#line 2664 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, EsdBuffer); +#endif + } +#line 8202 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 400: +#line 2672 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, EsdBuffer); } -#line 6136 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8212 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 293: -#line 1933 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 401: +#line 2677 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, EsdBuffer); } -#line 6146 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8222 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 294: -#line 1938 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 402: +#line 2682 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D, false, false, true); } -#line 6156 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8232 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 295: -#line 1943 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 403: +#line 2687 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd2D, false, false, true); +#endif + } +#line 8245 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 404: +#line 2695 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D, false, false, true); } -#line 6166 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8255 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 296: -#line 1948 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 405: +#line 2700 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D, false, false, true); } -#line 6176 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8265 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 297: -#line 1953 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 406: +#line 2705 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D, true, false, true); } -#line 6186 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8275 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 298: -#line 1958 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 407: +#line 2710 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd2D, true, false, true); +#endif + } +#line 8288 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 408: +#line 2718 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D, true, false, true); } -#line 6196 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8298 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 299: -#line 1963 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 409: +#line 2723 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D, true, false, true); } -#line 6206 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8308 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 300: -#line 1968 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 410: +#line 2728 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, Esd1D); } -#line 6216 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8318 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 301: -#line 1973 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 411: +#line 2733 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, Esd1D); +#endif + } +#line 8331 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 412: +#line 2741 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, Esd1D); } -#line 6226 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8341 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 302: -#line 1978 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 413: +#line 2746 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, Esd1D); } -#line 6236 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8351 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 303: -#line 1983 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 414: +#line 2751 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D); } -#line 6246 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8361 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 304: -#line 1988 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 415: +#line 2756 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, Esd2D); +#endif + } +#line 8374 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 416: +#line 2764 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, Esd2D); } -#line 6256 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8384 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 305: -#line 1993 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 417: +#line 2769 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, Esd2D); } -#line 6266 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8394 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 306: -#line 1998 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 418: +#line 2774 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, Esd3D); } -#line 6276 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8404 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 307: -#line 2003 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 419: +#line 2779 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, Esd3D); +#endif + } +#line 8417 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 420: +#line 2787 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, Esd3D); } -#line 6286 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8427 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 308: -#line 2008 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 421: +#line 2792 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, Esd3D); } -#line 6296 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8437 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 309: -#line 2013 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 422: +#line 2797 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, EsdRect); } -#line 6306 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8447 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 310: -#line 2018 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 423: +#line 2802 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, EsdRect); +#endif + } +#line 8460 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 424: +#line 2810 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, EsdRect); } -#line 6316 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8470 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 311: -#line 2023 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 425: +#line 2815 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, EsdRect); } -#line 6326 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8480 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 312: -#line 2028 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 426: +#line 2820 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, EsdCube); } -#line 6336 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8490 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 313: -#line 2033 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 427: +#line 2825 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, EsdCube); +#endif + } +#line 8503 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 428: +#line 2833 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, EsdCube); } -#line 6346 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8513 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 314: -#line 2038 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 429: +#line 2838 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, EsdCube); } -#line 6356 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8523 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 315: -#line 2043 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 430: +#line 2843 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, EsdBuffer); } -#line 6366 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8533 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 316: -#line 2048 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 431: +#line 2848 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, EsdBuffer); +#endif + } +#line 8546 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 432: +#line 2856 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, EsdBuffer); } -#line 6376 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8556 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 317: -#line 2053 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 433: +#line 2861 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, EsdBuffer); } -#line 6386 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8566 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 318: -#line 2058 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 434: +#line 2866 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, Esd1D, true); } -#line 6396 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8576 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 319: -#line 2063 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 435: +#line 2871 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, Esd1D, true); +#endif + } +#line 8589 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 436: +#line 2879 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, Esd1D, true); } -#line 6406 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8599 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 320: -#line 2068 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 437: +#line 2884 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, Esd1D, true); } -#line 6416 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8609 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 321: -#line 2073 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 438: +#line 2889 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D, true); } -#line 6426 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8619 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 322: -#line 2078 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 439: +#line 2894 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, Esd2D, true); +#endif + } +#line 8632 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 440: +#line 2902 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, Esd2D, true); } -#line 6436 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8642 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 323: -#line 2083 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 441: +#line 2907 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, Esd2D, true); } -#line 6446 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8652 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 324: -#line 2088 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 442: +#line 2912 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, EsdCube, true); } -#line 6456 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8662 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 325: -#line 2093 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 443: +#line 2917 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, EsdCube, true); +#endif + } +#line 8675 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 444: +#line 2925 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, EsdCube, true); } -#line 6466 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8685 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 326: -#line 2098 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 445: +#line 2930 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, EsdCube, true); } -#line 6476 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8695 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 327: -#line 2103 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 446: +#line 2935 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D, false, false, true); } -#line 6486 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8705 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 328: -#line 2108 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 447: +#line 2940 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, Esd2D, false, false, true); +#endif + } +#line 8718 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 448: +#line 2948 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, Esd2D, false, false, true); } -#line 6496 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8728 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 329: -#line 2113 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 449: +#line 2953 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, Esd2D, false, false, true); } -#line 6506 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8738 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 330: -#line 2118 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 450: +#line 2958 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D, true, false, true); } -#line 6516 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8748 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 331: -#line 2123 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 451: +#line 2963 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, Esd2D, true, false, true); +#endif + } +#line 8761 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 452: +#line 2971 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, Esd2D, true, false, true); } -#line 6526 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8771 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 332: -#line 2128 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 453: +#line 2976 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, Esd2D, true, false, true); } -#line 6536 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8781 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 333: -#line 2133 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 454: +#line 2981 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { // GL_OES_EGL_image_external (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd2D); (yyval.interm.type).sampler.external = true; } -#line 6547 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8792 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 334: -#line 2139 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 455: +#line 2987 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setSubpass(EbtFloat); } -#line 6558 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8803 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 335: -#line 2145 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 456: +#line 2993 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setSubpass(EbtFloat, true); } -#line 6569 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8814 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 336: -#line 2151 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 457: +#line 2999 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float subpass input", parseContext.symbolTable.atBuiltInLevel()); + parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setSubpass(EbtFloat16); +#endif + } +#line 8828 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 458: +#line 3008 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { +#ifdef AMD_EXTENSIONS + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float subpass input", parseContext.symbolTable.atBuiltInLevel()); + parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setSubpass(EbtFloat16, true); +#endif + } +#line 8842 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 459: +#line 3017 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setSubpass(EbtInt); } -#line 6580 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8853 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 337: -#line 2157 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 460: +#line 3023 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setSubpass(EbtInt, true); } -#line 6591 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8864 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 338: -#line 2163 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 461: +#line 3029 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setSubpass(EbtUint); } -#line 6602 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8875 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 339: -#line 2169 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 462: +#line 3035 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setSubpass(EbtUint, true); } -#line 6613 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8886 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 340: -#line 2175 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 463: +#line 3041 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.type) = (yyvsp[0].interm.type); (yyval.interm.type).qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; parseContext.structTypeCheck((yyval.interm.type).loc, (yyval.interm.type)); } -#line 6623 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8896 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 341: -#line 2180 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 464: +#line 3046 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { // // This is for user defined type names. The lexical phase looked up the @@ -6637,50 +8910,47 @@ yyreduce: } else parseContext.error((yyvsp[0].lex).loc, "expected type name", (yyvsp[0].lex).string->c_str(), ""); } -#line 6641 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8914 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 342: -#line 2196 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 465: +#line 3062 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "highp precision qualifier"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - if (parseContext.profile == EEsProfile) - (yyval.interm.type).qualifier.precision = EpqHigh; + parseContext.handlePrecisionQualifier((yyvsp[0].lex).loc, (yyval.interm.type).qualifier, EpqHigh); } -#line 6652 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8924 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 343: -#line 2202 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 466: +#line 3067 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "mediump precision qualifier"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - if (parseContext.profile == EEsProfile) - (yyval.interm.type).qualifier.precision = EpqMedium; + parseContext.handlePrecisionQualifier((yyvsp[0].lex).loc, (yyval.interm.type).qualifier, EpqMedium); } -#line 6663 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8934 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 344: -#line 2208 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 467: +#line 3072 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "lowp precision qualifier"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - if (parseContext.profile == EEsProfile) - (yyval.interm.type).qualifier.precision = EpqLow; + parseContext.handlePrecisionQualifier((yyvsp[0].lex).loc, (yyval.interm.type).qualifier, EpqLow); } -#line 6674 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8944 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 345: -#line 2217 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 468: +#line 3080 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.nestedStructCheck((yyvsp[-2].lex).loc); } -#line 6680 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8950 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 346: -#line 2217 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 469: +#line 3080 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { TType* structure = new TType((yyvsp[-1].interm.typeList), *(yyvsp[-4].lex).string); parseContext.structArrayCheck((yyvsp[-4].lex).loc, *structure); @@ -6692,17 +8962,17 @@ yyreduce: (yyval.interm.type).userDef = structure; --parseContext.structNestingLevel; } -#line 6696 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8966 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 347: -#line 2228 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 470: +#line 3091 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.nestedStructCheck((yyvsp[-1].lex).loc); } -#line 6702 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8972 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 348: -#line 2228 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 471: +#line 3091 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { TType* structure = new TType((yyvsp[-1].interm.typeList), TString("")); (yyval.interm.type).init((yyvsp[-4].lex).loc); @@ -6710,19 +8980,19 @@ yyreduce: (yyval.interm.type).userDef = structure; --parseContext.structNestingLevel; } -#line 6714 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8984 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 349: -#line 2238 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 472: +#line 3101 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.typeList) = (yyvsp[0].interm.typeList); } -#line 6722 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 8992 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 350: -#line 2241 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 473: +#line 3104 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.typeList) = (yyvsp[-1].interm.typeList); for (unsigned int i = 0; i < (yyvsp[0].interm.typeList)->size(); ++i) { @@ -6733,11 +9003,11 @@ yyreduce: (yyval.interm.typeList)->push_back((*(yyvsp[0].interm.typeList))[i]); } } -#line 6737 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9007 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 351: -#line 2254 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 474: +#line 3117 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { if ((yyvsp[-2].interm.type).arraySizes) { parseContext.profileRequires((yyvsp[-2].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); @@ -6752,17 +9022,20 @@ yyreduce: parseContext.precisionQualifierCheck((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).basicType, (yyvsp[-2].interm.type).qualifier); for (unsigned int i = 0; i < (yyval.interm.typeList)->size(); ++i) { - parseContext.arrayDimCheck((yyvsp[-2].interm.type).loc, (*(yyval.interm.typeList))[i].type, (yyvsp[-2].interm.type).arraySizes); - (*(yyval.interm.typeList))[i].type->mergeType((yyvsp[-2].interm.type)); + TType type((yyvsp[-2].interm.type)); + type.setFieldName((*(yyval.interm.typeList))[i].type->getFieldName()); + type.transferArraySizes((*(yyval.interm.typeList))[i].type->getArraySizes()); + type.copyArrayInnerSizes((yyvsp[-2].interm.type).arraySizes); + parseContext.arrayOfArrayVersionCheck((*(yyval.interm.typeList))[i].loc, type.getArraySizes()); + (*(yyval.interm.typeList))[i].type->shallowCopy(type); } } -#line 6760 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9034 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 352: -#line 2272 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 475: +#line 3139 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { - parseContext.globalQualifierFixCheck((yyvsp[-3].interm.type).loc, (yyvsp[-3].interm.type).qualifier); if ((yyvsp[-2].interm.type).arraySizes) { parseContext.profileRequires((yyvsp[-2].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); parseContext.profileRequires((yyvsp[-2].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); @@ -6772,269 +9045,273 @@ yyreduce: (yyval.interm.typeList) = (yyvsp[-1].interm.typeList); - parseContext.checkNoShaderLayouts((yyvsp[-3].interm.type).loc, (yyvsp[-3].interm.type).shaderQualifiers); + parseContext.memberQualifierCheck((yyvsp[-3].interm.type)); parseContext.voidErrorCheck((yyvsp[-2].interm.type).loc, (*(yyvsp[-1].interm.typeList))[0].type->getFieldName(), (yyvsp[-2].interm.type).basicType); parseContext.mergeQualifiers((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).qualifier, (yyvsp[-3].interm.type).qualifier, true); parseContext.precisionQualifierCheck((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).basicType, (yyvsp[-2].interm.type).qualifier); for (unsigned int i = 0; i < (yyval.interm.typeList)->size(); ++i) { - parseContext.arrayDimCheck((yyvsp[-3].interm.type).loc, (*(yyval.interm.typeList))[i].type, (yyvsp[-2].interm.type).arraySizes); - (*(yyval.interm.typeList))[i].type->mergeType((yyvsp[-2].interm.type)); + TType type((yyvsp[-2].interm.type)); + type.setFieldName((*(yyval.interm.typeList))[i].type->getFieldName()); + type.transferArraySizes((*(yyval.interm.typeList))[i].type->getArraySizes()); + type.copyArrayInnerSizes((yyvsp[-2].interm.type).arraySizes); + parseContext.arrayOfArrayVersionCheck((*(yyval.interm.typeList))[i].loc, type.getArraySizes()); + (*(yyval.interm.typeList))[i].type->shallowCopy(type); } } -#line 6786 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9063 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 353: -#line 2296 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 476: +#line 3166 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.typeList) = new TTypeList; (yyval.interm.typeList)->push_back((yyvsp[0].interm.typeLine)); } -#line 6795 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9072 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 354: -#line 2300 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 477: +#line 3170 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.typeList)->push_back((yyvsp[0].interm.typeLine)); } -#line 6803 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9080 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 355: -#line 2306 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 478: +#line 3176 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.typeLine).type = new TType(EbtVoid); (yyval.interm.typeLine).loc = (yyvsp[0].lex).loc; (yyval.interm.typeLine).type->setFieldName(*(yyvsp[0].lex).string); } -#line 6813 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9090 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 356: -#line 2311 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 479: +#line 3181 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { - parseContext.arrayDimCheck((yyvsp[-1].lex).loc, (yyvsp[0].interm).arraySizes, 0); + parseContext.arrayOfArrayVersionCheck((yyvsp[-1].lex).loc, (yyvsp[0].interm).arraySizes); (yyval.interm.typeLine).type = new TType(EbtVoid); (yyval.interm.typeLine).loc = (yyvsp[-1].lex).loc; (yyval.interm.typeLine).type->setFieldName(*(yyvsp[-1].lex).string); - (yyval.interm.typeLine).type->newArraySizes(*(yyvsp[0].interm).arraySizes); + (yyval.interm.typeLine).type->transferArraySizes((yyvsp[0].interm).arraySizes); } -#line 6826 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9103 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 357: -#line 2322 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 480: +#line 3192 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 6834 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9111 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 358: -#line 2325 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 481: +#line 3195 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { const char* initFeature = "{ } style initializers"; parseContext.requireProfile((yyvsp[-2].lex).loc, ~EEsProfile, initFeature); parseContext.profileRequires((yyvsp[-2].lex).loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature); (yyval.interm.intermTypedNode) = (yyvsp[-1].interm.intermTypedNode); } -#line 6845 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9122 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 359: -#line 2331 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 482: +#line 3201 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { const char* initFeature = "{ } style initializers"; parseContext.requireProfile((yyvsp[-3].lex).loc, ~EEsProfile, initFeature); parseContext.profileRequires((yyvsp[-3].lex).loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature); (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 6856 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9133 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 360: -#line 2340 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 483: +#line 3210 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.intermediate.growAggregate(0, (yyvsp[0].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)->getLoc()); } -#line 6864 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9141 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 361: -#line 2343 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 484: +#line 3213 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); } -#line 6872 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9149 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 362: -#line 2349 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 485: +#line 3219 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 6878 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9155 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 363: -#line 2353 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 486: +#line 3223 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 6884 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9161 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 364: -#line 2354 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 487: +#line 3224 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 6890 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9167 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 365: -#line 2360 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 488: +#line 3230 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 6896 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9173 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 366: -#line 2361 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 489: +#line 3231 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 6902 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9179 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 367: -#line 2362 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 490: +#line 3232 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 6908 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9185 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 368: -#line 2363 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 491: +#line 3233 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 6914 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9191 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 369: -#line 2364 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 492: +#line 3234 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 6920 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9197 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 370: -#line 2365 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 493: +#line 3235 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 6926 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9203 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 371: -#line 2366 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 494: +#line 3236 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 6932 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9209 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 372: -#line 2370 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 495: +#line 3240 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = 0; } -#line 6938 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9215 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 373: -#line 2371 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 496: +#line 3241 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.symbolTable.push(); ++parseContext.statementNestingLevel; } -#line 6947 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9224 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 374: -#line 2375 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 497: +#line 3245 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); --parseContext.statementNestingLevel; } -#line 6956 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9233 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 375: -#line 2379 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 498: +#line 3249 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { if ((yyvsp[-2].interm.intermNode) && (yyvsp[-2].interm.intermNode)->getAsAggregate()) (yyvsp[-2].interm.intermNode)->getAsAggregate()->setOperator(EOpSequence); (yyval.interm.intermNode) = (yyvsp[-2].interm.intermNode); } -#line 6966 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9243 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 376: -#line 2387 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 499: +#line 3257 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 6972 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9249 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 377: -#line 2388 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 500: +#line 3258 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 6978 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9255 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 378: -#line 2392 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 501: +#line 3262 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { ++parseContext.controlFlowNestingLevel; } -#line 6986 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9263 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 379: -#line 2395 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 502: +#line 3265 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { --parseContext.controlFlowNestingLevel; (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 6995 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9272 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 380: -#line 2399 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 503: +#line 3269 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.symbolTable.push(); ++parseContext.statementNestingLevel; ++parseContext.controlFlowNestingLevel; } -#line 7005 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9282 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 381: -#line 2404 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 504: +#line 3274 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); --parseContext.statementNestingLevel; --parseContext.controlFlowNestingLevel; (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 7016 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9293 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 382: -#line 2413 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 505: +#line 3283 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = 0; } -#line 7024 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9301 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 383: -#line 2416 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 506: +#line 3286 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { if ((yyvsp[-1].interm.intermNode) && (yyvsp[-1].interm.intermNode)->getAsAggregate()) (yyvsp[-1].interm.intermNode)->getAsAggregate()->setOperator(EOpSequence); (yyval.interm.intermNode) = (yyvsp[-1].interm.intermNode); } -#line 7034 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9311 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 384: -#line 2424 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 507: +#line 3294 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[0].interm.intermNode)); if ((yyvsp[0].interm.intermNode) && (yyvsp[0].interm.intermNode)->getAsBranchNode() && ((yyvsp[0].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpCase || @@ -7043,11 +9320,11 @@ yyreduce: (yyval.interm.intermNode) = 0; // start a fresh subsequence for what's after this case } } -#line 7047 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9324 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 385: -#line 2432 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 508: +#line 3302 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { if ((yyvsp[0].interm.intermNode) && (yyvsp[0].interm.intermNode)->getAsBranchNode() && ((yyvsp[0].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpCase || (yyvsp[0].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpDefault)) { @@ -7056,59 +9333,76 @@ yyreduce: } else (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-1].interm.intermNode), (yyvsp[0].interm.intermNode)); } -#line 7060 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9337 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 386: -#line 2443 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 509: +#line 3313 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = 0; } -#line 7066 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9343 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 387: -#line 2444 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 510: +#line 3314 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = static_cast((yyvsp[-1].interm.intermTypedNode)); } -#line 7072 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9349 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 388: -#line 2448 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 511: +#line 3318 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 9357 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 512: +#line 3321 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.handleSelectionAttributes(*(yyvsp[-1].interm.attributes), (yyvsp[0].interm.intermNode)); + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 9366 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 513: +#line 3327 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.boolCheck((yyvsp[-4].lex).loc, (yyvsp[-2].interm.intermTypedNode)); (yyval.interm.intermNode) = parseContext.intermediate.addSelection((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.nodePair), (yyvsp[-4].lex).loc); } -#line 7081 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9375 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 389: -#line 2455 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 514: +#line 3334 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermNode); (yyval.interm.nodePair).node2 = (yyvsp[0].interm.intermNode); } -#line 7090 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9384 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 390: -#line 2459 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 515: +#line 3338 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.nodePair).node1 = (yyvsp[0].interm.intermNode); (yyval.interm.nodePair).node2 = 0; } -#line 7099 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9393 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 391: -#line 2467 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 516: +#line 3346 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); parseContext.boolCheck((yyvsp[0].interm.intermTypedNode)->getLoc(), (yyvsp[0].interm.intermTypedNode)); } -#line 7108 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9402 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 392: -#line 2471 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 517: +#line 3350 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.boolCheck((yyvsp[-2].lex).loc, (yyvsp[-3].interm.type)); @@ -7119,11 +9413,28 @@ yyreduce: else (yyval.interm.intermTypedNode) = 0; } -#line 7123 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9417 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 393: -#line 2484 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 518: +#line 3363 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 9425 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 519: +#line 3366 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.handleSwitchAttributes(*(yyvsp[-1].interm.attributes), (yyvsp[0].interm.intermNode)); + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 9434 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 520: +#line 3372 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { // start new switch sequence on the switch stack ++parseContext.controlFlowNestingLevel; @@ -7132,11 +9443,11 @@ yyreduce: parseContext.switchLevel.push_back(parseContext.statementNestingLevel); parseContext.symbolTable.push(); } -#line 7136 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9447 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 394: -#line 2492 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 521: +#line 3380 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = parseContext.addSwitch((yyvsp[-7].lex).loc, (yyvsp[-5].interm.intermTypedNode), (yyvsp[-1].interm.intermNode) ? (yyvsp[-1].interm.intermNode)->getAsAggregate() : 0); delete parseContext.switchSequenceStack.back(); @@ -7146,27 +9457,27 @@ yyreduce: --parseContext.statementNestingLevel; --parseContext.controlFlowNestingLevel; } -#line 7150 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9461 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 395: -#line 2504 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 522: +#line 3392 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = 0; } -#line 7158 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9469 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 396: -#line 2507 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 523: +#line 3395 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 7166 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9477 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 397: -#line 2513 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 524: +#line 3401 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = 0; if (parseContext.switchLevel.size() == 0) @@ -7179,11 +9490,11 @@ yyreduce: (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpCase, (yyvsp[-1].interm.intermTypedNode), (yyvsp[-2].lex).loc); } } -#line 7183 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9494 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 398: -#line 2525 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 525: +#line 3413 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = 0; if (parseContext.switchLevel.size() == 0) @@ -7193,11 +9504,28 @@ yyreduce: else (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpDefault, (yyvsp[-1].lex).loc); } -#line 7197 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9508 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 399: -#line 2537 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 526: +#line 3425 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 9516 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 527: +#line 3428 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.handleLoopAttributes(*(yyvsp[-1].interm.attributes), (yyvsp[0].interm.intermNode)); + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 9525 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 528: +#line 3434 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { if (! parseContext.limits.whileLoops) parseContext.error((yyvsp[-1].lex).loc, "while loops not available", "limitation", ""); @@ -7206,11 +9534,11 @@ yyreduce: ++parseContext.statementNestingLevel; ++parseContext.controlFlowNestingLevel; } -#line 7210 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9538 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 400: -#line 2545 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 529: +#line 3442 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); (yyval.interm.intermNode) = parseContext.intermediate.addLoop((yyvsp[0].interm.intermNode), (yyvsp[-2].interm.intermTypedNode), 0, true, (yyvsp[-5].lex).loc); @@ -7218,21 +9546,21 @@ yyreduce: --parseContext.statementNestingLevel; --parseContext.controlFlowNestingLevel; } -#line 7222 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9550 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 401: -#line 2552 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 530: +#line 3449 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { ++parseContext.loopNestingLevel; ++parseContext.statementNestingLevel; ++parseContext.controlFlowNestingLevel; } -#line 7232 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9560 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 402: -#line 2557 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 531: +#line 3454 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { if (! parseContext.limits.whileLoops) parseContext.error((yyvsp[-7].lex).loc, "do-while loops not available", "limitation", ""); @@ -7244,22 +9572,22 @@ yyreduce: --parseContext.statementNestingLevel; --parseContext.controlFlowNestingLevel; } -#line 7248 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9576 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 403: -#line 2568 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 532: +#line 3465 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.symbolTable.push(); ++parseContext.loopNestingLevel; ++parseContext.statementNestingLevel; ++parseContext.controlFlowNestingLevel; } -#line 7259 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9587 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 404: -#line 2574 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 533: +#line 3471 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[-3].interm.intermNode), (yyvsp[-5].lex).loc); @@ -7272,153 +9600,165 @@ yyreduce: --parseContext.statementNestingLevel; --parseContext.controlFlowNestingLevel; } -#line 7276 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9604 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 405: -#line 2589 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 534: +#line 3486 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 7284 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9612 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 406: -#line 2592 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 535: +#line 3489 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 7292 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9620 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 407: -#line 2598 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 536: +#line 3495 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 7300 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9628 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 408: -#line 2601 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 537: +#line 3498 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermTypedNode) = 0; } -#line 7308 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9636 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 409: -#line 2607 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 538: +#line 3504 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.nodePair).node1 = (yyvsp[-1].interm.intermTypedNode); (yyval.interm.nodePair).node2 = 0; } -#line 7317 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9645 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 410: -#line 2611 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 539: +#line 3508 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermTypedNode); (yyval.interm.nodePair).node2 = (yyvsp[0].interm.intermTypedNode); } -#line 7326 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9654 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 411: -#line 2618 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 540: +#line 3515 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { if (parseContext.loopNestingLevel <= 0) parseContext.error((yyvsp[-1].lex).loc, "continue statement only allowed in loops", "", ""); (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpContinue, (yyvsp[-1].lex).loc); } -#line 7336 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9664 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 412: -#line 2623 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 541: +#line 3520 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { if (parseContext.loopNestingLevel + parseContext.switchSequenceStack.size() <= 0) parseContext.error((yyvsp[-1].lex).loc, "break statement only allowed in switch and loops", "", ""); (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpBreak, (yyvsp[-1].lex).loc); } -#line 7346 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9674 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 413: -#line 2628 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 542: +#line 3525 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpReturn, (yyvsp[-1].lex).loc); if (parseContext.currentFunctionType->getBasicType() != EbtVoid) parseContext.error((yyvsp[-1].lex).loc, "non-void function must return a value", "return", ""); if (parseContext.inMain) - parseContext.postMainReturn = true; + parseContext.postEntryPointReturn = true; } -#line 7358 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9686 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 414: -#line 2635 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 543: +#line 3532 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = parseContext.handleReturnValue((yyvsp[-2].lex).loc, (yyvsp[-1].interm.intermTypedNode)); } -#line 7366 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9694 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 415: -#line 2638 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 544: +#line 3535 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { parseContext.requireStage((yyvsp[-1].lex).loc, EShLangFragment, "discard"); (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpKill, (yyvsp[-1].lex).loc); } -#line 7375 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9703 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 416: -#line 2647 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 545: +#line 3544 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); parseContext.intermediate.setTreeRoot((yyval.interm.intermNode)); } -#line 7384 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9712 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 417: -#line 2651 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 546: +#line 3548 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { - (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-1].interm.intermNode), (yyvsp[0].interm.intermNode)); - parseContext.intermediate.setTreeRoot((yyval.interm.intermNode)); + if ((yyvsp[0].interm.intermNode) != nullptr) { + (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-1].interm.intermNode), (yyvsp[0].interm.intermNode)); + parseContext.intermediate.setTreeRoot((yyval.interm.intermNode)); + } } -#line 7393 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9723 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 418: -#line 2658 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 547: +#line 3557 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 7401 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9731 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 419: -#line 2661 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 548: +#line 3560 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 7409 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9739 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 420: -#line 2667 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 549: +#line 3563 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.requireProfile((yyvsp[0].lex).loc, ~EEsProfile, "extraneous semicolon"); + parseContext.profileRequires((yyvsp[0].lex).loc, ~EEsProfile, 460, nullptr, "extraneous semicolon"); + (yyval.interm.intermNode) = nullptr; + } +#line 9749 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 550: +#line 3571 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { (yyvsp[0].interm).function = parseContext.handleFunctionDeclarator((yyvsp[0].interm).loc, *(yyvsp[0].interm).function, false /* not prototype */); (yyvsp[0].interm).intermNode = parseContext.handleFunctionDefinition((yyvsp[0].interm).loc, *(yyvsp[0].interm).function); } -#line 7418 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9758 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; - case 421: -#line 2671 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + case 551: +#line 3575 "MachineIndependent/glslang.y" /* yacc.c:1646 */ { // May be best done as post process phase on intermediate code if (parseContext.currentFunctionType->getBasicType() != EbtVoid && ! parseContext.functionReturnsValue) @@ -7432,13 +9772,54 @@ yyreduce: // information. This information can be queried from the parse tree (yyval.interm.intermNode)->getAsAggregate()->setOptimize(parseContext.contextPragma.optimize); (yyval.interm.intermNode)->getAsAggregate()->setDebug(parseContext.contextPragma.debug); - (yyval.interm.intermNode)->getAsAggregate()->addToPragmaTable(parseContext.contextPragma.pragmaTable); + (yyval.interm.intermNode)->getAsAggregate()->setPragmaTable(parseContext.contextPragma.pragmaTable); } -#line 7438 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9778 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 552: +#line 3593 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.attributes) = (yyvsp[-2].interm.attributes); + parseContext.requireExtensions((yyvsp[-4].lex).loc, 1, &E_GL_EXT_control_flow_attributes, "attribute"); + } +#line 9787 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 553: +#line 3599 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.attributes) = (yyvsp[0].interm.attributes); + } +#line 9795 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 554: +#line 3602 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.attributes) = parseContext.mergeAttributes((yyvsp[-2].interm.attributes), (yyvsp[0].interm.attributes)); + } +#line 9803 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 555: +#line 3607 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.attributes) = parseContext.makeAttributes(*(yyvsp[0].lex).string); + } +#line 9811 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 556: +#line 3610 "MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.attributes) = parseContext.makeAttributes(*(yyvsp[-3].lex).string, (yyvsp[-1].interm.intermTypedNode)); + } +#line 9819 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ break; -#line 7442 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ +#line 9823 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -7666,5 +10047,5 @@ yyreturn: #endif return yyresult; } -#line 2688 "MachineIndependent/glslang.y" /* yacc.c:1906 */ +#line 3614 "MachineIndependent/glslang.y" /* yacc.c:1906 */ diff --git a/Externals/glslang/glslang/MachineIndependent/glslang_tab.cpp.h b/Externals/glslang/glslang/MachineIndependent/glslang_tab.cpp.h index e7d8fae862..7cfb79766f 100644 --- a/Externals/glslang/glslang/MachineIndependent/glslang_tab.cpp.h +++ b/Externals/glslang/glslang/MachineIndependent/glslang_tab.cpp.h @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 3.0.4. */ +/* A Bison parser, made by GNU Bison 3.0. */ /* Bison interface for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -47,280 +47,401 @@ extern int yydebug; { ATTRIBUTE = 258, VARYING = 259, - CONST = 260, - BOOL = 261, - FLOAT = 262, + FLOAT16_T = 260, + FLOAT = 261, + FLOAT32_T = 262, DOUBLE = 263, - INT = 264, - UINT = 265, - INT64_T = 266, - UINT64_T = 267, - BREAK = 268, - CONTINUE = 269, - DO = 270, - ELSE = 271, - FOR = 272, - IF = 273, - DISCARD = 274, - RETURN = 275, - SWITCH = 276, - CASE = 277, - DEFAULT = 278, - SUBROUTINE = 279, - BVEC2 = 280, - BVEC3 = 281, - BVEC4 = 282, - IVEC2 = 283, - IVEC3 = 284, - IVEC4 = 285, - I64VEC2 = 286, - I64VEC3 = 287, - I64VEC4 = 288, - UVEC2 = 289, - UVEC3 = 290, - UVEC4 = 291, - U64VEC2 = 292, - U64VEC3 = 293, - U64VEC4 = 294, - VEC2 = 295, - VEC3 = 296, - VEC4 = 297, - MAT2 = 298, - MAT3 = 299, - MAT4 = 300, - CENTROID = 301, - IN = 302, - OUT = 303, - INOUT = 304, - UNIFORM = 305, - PATCH = 306, - SAMPLE = 307, - BUFFER = 308, - SHARED = 309, - COHERENT = 310, - VOLATILE = 311, - RESTRICT = 312, - READONLY = 313, - WRITEONLY = 314, - DVEC2 = 315, - DVEC3 = 316, - DVEC4 = 317, - DMAT2 = 318, - DMAT3 = 319, - DMAT4 = 320, - NOPERSPECTIVE = 321, - FLAT = 322, - SMOOTH = 323, - LAYOUT = 324, - MAT2X2 = 325, - MAT2X3 = 326, - MAT2X4 = 327, - MAT3X2 = 328, - MAT3X3 = 329, - MAT3X4 = 330, - MAT4X2 = 331, - MAT4X3 = 332, - MAT4X4 = 333, - DMAT2X2 = 334, - DMAT2X3 = 335, - DMAT2X4 = 336, - DMAT3X2 = 337, - DMAT3X3 = 338, - DMAT3X4 = 339, - DMAT4X2 = 340, - DMAT4X3 = 341, - DMAT4X4 = 342, - ATOMIC_UINT = 343, - SAMPLER1D = 344, - SAMPLER2D = 345, - SAMPLER3D = 346, - SAMPLERCUBE = 347, - SAMPLER1DSHADOW = 348, - SAMPLER2DSHADOW = 349, - SAMPLERCUBESHADOW = 350, - SAMPLER1DARRAY = 351, - SAMPLER2DARRAY = 352, - SAMPLER1DARRAYSHADOW = 353, - SAMPLER2DARRAYSHADOW = 354, - ISAMPLER1D = 355, - ISAMPLER2D = 356, - ISAMPLER3D = 357, - ISAMPLERCUBE = 358, - ISAMPLER1DARRAY = 359, - ISAMPLER2DARRAY = 360, - USAMPLER1D = 361, - USAMPLER2D = 362, - USAMPLER3D = 363, - USAMPLERCUBE = 364, - USAMPLER1DARRAY = 365, - USAMPLER2DARRAY = 366, - SAMPLER2DRECT = 367, - SAMPLER2DRECTSHADOW = 368, - ISAMPLER2DRECT = 369, - USAMPLER2DRECT = 370, - SAMPLERBUFFER = 371, - ISAMPLERBUFFER = 372, - USAMPLERBUFFER = 373, - SAMPLERCUBEARRAY = 374, - SAMPLERCUBEARRAYSHADOW = 375, - ISAMPLERCUBEARRAY = 376, - USAMPLERCUBEARRAY = 377, - SAMPLER2DMS = 378, - ISAMPLER2DMS = 379, - USAMPLER2DMS = 380, - SAMPLER2DMSARRAY = 381, - ISAMPLER2DMSARRAY = 382, - USAMPLER2DMSARRAY = 383, - SAMPLEREXTERNALOES = 384, - SAMPLER = 385, - SAMPLERSHADOW = 386, - TEXTURE1D = 387, - TEXTURE2D = 388, - TEXTURE3D = 389, - TEXTURECUBE = 390, - TEXTURE1DARRAY = 391, - TEXTURE2DARRAY = 392, - ITEXTURE1D = 393, - ITEXTURE2D = 394, - ITEXTURE3D = 395, - ITEXTURECUBE = 396, - ITEXTURE1DARRAY = 397, - ITEXTURE2DARRAY = 398, - UTEXTURE1D = 399, - UTEXTURE2D = 400, - UTEXTURE3D = 401, - UTEXTURECUBE = 402, - UTEXTURE1DARRAY = 403, - UTEXTURE2DARRAY = 404, - TEXTURE2DRECT = 405, - ITEXTURE2DRECT = 406, - UTEXTURE2DRECT = 407, - TEXTUREBUFFER = 408, - ITEXTUREBUFFER = 409, - UTEXTUREBUFFER = 410, - TEXTURECUBEARRAY = 411, - ITEXTURECUBEARRAY = 412, - UTEXTURECUBEARRAY = 413, - TEXTURE2DMS = 414, - ITEXTURE2DMS = 415, - UTEXTURE2DMS = 416, - TEXTURE2DMSARRAY = 417, - ITEXTURE2DMSARRAY = 418, - UTEXTURE2DMSARRAY = 419, - SUBPASSINPUT = 420, - SUBPASSINPUTMS = 421, - ISUBPASSINPUT = 422, - ISUBPASSINPUTMS = 423, - USUBPASSINPUT = 424, - USUBPASSINPUTMS = 425, - IMAGE1D = 426, - IIMAGE1D = 427, - UIMAGE1D = 428, - IMAGE2D = 429, - IIMAGE2D = 430, - UIMAGE2D = 431, - IMAGE3D = 432, - IIMAGE3D = 433, - UIMAGE3D = 434, - IMAGE2DRECT = 435, - IIMAGE2DRECT = 436, - UIMAGE2DRECT = 437, - IMAGECUBE = 438, - IIMAGECUBE = 439, - UIMAGECUBE = 440, - IMAGEBUFFER = 441, - IIMAGEBUFFER = 442, - UIMAGEBUFFER = 443, - IMAGE1DARRAY = 444, - IIMAGE1DARRAY = 445, - UIMAGE1DARRAY = 446, - IMAGE2DARRAY = 447, - IIMAGE2DARRAY = 448, - UIMAGE2DARRAY = 449, - IMAGECUBEARRAY = 450, - IIMAGECUBEARRAY = 451, - UIMAGECUBEARRAY = 452, - IMAGE2DMS = 453, - IIMAGE2DMS = 454, - UIMAGE2DMS = 455, - IMAGE2DMSARRAY = 456, - IIMAGE2DMSARRAY = 457, - UIMAGE2DMSARRAY = 458, - STRUCT = 459, - VOID = 460, - WHILE = 461, - IDENTIFIER = 462, - TYPE_NAME = 463, - FLOATCONSTANT = 464, - DOUBLECONSTANT = 465, - INTCONSTANT = 466, - UINTCONSTANT = 467, - INT64CONSTANT = 468, - UINT64CONSTANT = 469, - BOOLCONSTANT = 470, - LEFT_OP = 471, - RIGHT_OP = 472, - INC_OP = 473, - DEC_OP = 474, - LE_OP = 475, - GE_OP = 476, - EQ_OP = 477, - NE_OP = 478, - AND_OP = 479, - OR_OP = 480, - XOR_OP = 481, - MUL_ASSIGN = 482, - DIV_ASSIGN = 483, - ADD_ASSIGN = 484, - MOD_ASSIGN = 485, - LEFT_ASSIGN = 486, - RIGHT_ASSIGN = 487, - AND_ASSIGN = 488, - XOR_ASSIGN = 489, - OR_ASSIGN = 490, - SUB_ASSIGN = 491, - LEFT_PAREN = 492, - RIGHT_PAREN = 493, - LEFT_BRACKET = 494, - RIGHT_BRACKET = 495, - LEFT_BRACE = 496, - RIGHT_BRACE = 497, - DOT = 498, - COMMA = 499, - COLON = 500, - EQUAL = 501, - SEMICOLON = 502, - BANG = 503, - DASH = 504, - TILDE = 505, - PLUS = 506, - STAR = 507, - SLASH = 508, - PERCENT = 509, - LEFT_ANGLE = 510, - RIGHT_ANGLE = 511, - VERTICAL_BAR = 512, - CARET = 513, - AMPERSAND = 514, - QUESTION = 515, - INVARIANT = 516, - PRECISE = 517, - HIGH_PRECISION = 518, - MEDIUM_PRECISION = 519, - LOW_PRECISION = 520, - PRECISION = 521, - PACKED = 522, - RESOURCE = 523, - SUPERP = 524 + FLOAT64_T = 264, + CONST = 265, + BOOL = 266, + INT = 267, + UINT = 268, + INT64_T = 269, + UINT64_T = 270, + INT32_T = 271, + UINT32_T = 272, + INT16_T = 273, + UINT16_T = 274, + INT8_T = 275, + UINT8_T = 276, + BREAK = 277, + CONTINUE = 278, + DO = 279, + ELSE = 280, + FOR = 281, + IF = 282, + DISCARD = 283, + RETURN = 284, + SWITCH = 285, + CASE = 286, + DEFAULT = 287, + SUBROUTINE = 288, + BVEC2 = 289, + BVEC3 = 290, + BVEC4 = 291, + IVEC2 = 292, + IVEC3 = 293, + IVEC4 = 294, + UVEC2 = 295, + UVEC3 = 296, + UVEC4 = 297, + I64VEC2 = 298, + I64VEC3 = 299, + I64VEC4 = 300, + U64VEC2 = 301, + U64VEC3 = 302, + U64VEC4 = 303, + I32VEC2 = 304, + I32VEC3 = 305, + I32VEC4 = 306, + U32VEC2 = 307, + U32VEC3 = 308, + U32VEC4 = 309, + I16VEC2 = 310, + I16VEC3 = 311, + I16VEC4 = 312, + U16VEC2 = 313, + U16VEC3 = 314, + U16VEC4 = 315, + I8VEC2 = 316, + I8VEC3 = 317, + I8VEC4 = 318, + U8VEC2 = 319, + U8VEC3 = 320, + U8VEC4 = 321, + VEC2 = 322, + VEC3 = 323, + VEC4 = 324, + MAT2 = 325, + MAT3 = 326, + MAT4 = 327, + CENTROID = 328, + IN = 329, + OUT = 330, + INOUT = 331, + UNIFORM = 332, + PATCH = 333, + SAMPLE = 334, + BUFFER = 335, + SHARED = 336, + NONUNIFORM = 337, + COHERENT = 338, + VOLATILE = 339, + RESTRICT = 340, + READONLY = 341, + WRITEONLY = 342, + DVEC2 = 343, + DVEC3 = 344, + DVEC4 = 345, + DMAT2 = 346, + DMAT3 = 347, + DMAT4 = 348, + F16VEC2 = 349, + F16VEC3 = 350, + F16VEC4 = 351, + F16MAT2 = 352, + F16MAT3 = 353, + F16MAT4 = 354, + F32VEC2 = 355, + F32VEC3 = 356, + F32VEC4 = 357, + F32MAT2 = 358, + F32MAT3 = 359, + F32MAT4 = 360, + F64VEC2 = 361, + F64VEC3 = 362, + F64VEC4 = 363, + F64MAT2 = 364, + F64MAT3 = 365, + F64MAT4 = 366, + NOPERSPECTIVE = 367, + FLAT = 368, + SMOOTH = 369, + LAYOUT = 370, + __EXPLICITINTERPAMD = 371, + MAT2X2 = 372, + MAT2X3 = 373, + MAT2X4 = 374, + MAT3X2 = 375, + MAT3X3 = 376, + MAT3X4 = 377, + MAT4X2 = 378, + MAT4X3 = 379, + MAT4X4 = 380, + DMAT2X2 = 381, + DMAT2X3 = 382, + DMAT2X4 = 383, + DMAT3X2 = 384, + DMAT3X3 = 385, + DMAT3X4 = 386, + DMAT4X2 = 387, + DMAT4X3 = 388, + DMAT4X4 = 389, + F16MAT2X2 = 390, + F16MAT2X3 = 391, + F16MAT2X4 = 392, + F16MAT3X2 = 393, + F16MAT3X3 = 394, + F16MAT3X4 = 395, + F16MAT4X2 = 396, + F16MAT4X3 = 397, + F16MAT4X4 = 398, + F32MAT2X2 = 399, + F32MAT2X3 = 400, + F32MAT2X4 = 401, + F32MAT3X2 = 402, + F32MAT3X3 = 403, + F32MAT3X4 = 404, + F32MAT4X2 = 405, + F32MAT4X3 = 406, + F32MAT4X4 = 407, + F64MAT2X2 = 408, + F64MAT2X3 = 409, + F64MAT2X4 = 410, + F64MAT3X2 = 411, + F64MAT3X3 = 412, + F64MAT3X4 = 413, + F64MAT4X2 = 414, + F64MAT4X3 = 415, + F64MAT4X4 = 416, + ATOMIC_UINT = 417, + SAMPLER1D = 418, + SAMPLER2D = 419, + SAMPLER3D = 420, + SAMPLERCUBE = 421, + SAMPLER1DSHADOW = 422, + SAMPLER2DSHADOW = 423, + SAMPLERCUBESHADOW = 424, + SAMPLER1DARRAY = 425, + SAMPLER2DARRAY = 426, + SAMPLER1DARRAYSHADOW = 427, + SAMPLER2DARRAYSHADOW = 428, + ISAMPLER1D = 429, + ISAMPLER2D = 430, + ISAMPLER3D = 431, + ISAMPLERCUBE = 432, + ISAMPLER1DARRAY = 433, + ISAMPLER2DARRAY = 434, + USAMPLER1D = 435, + USAMPLER2D = 436, + USAMPLER3D = 437, + USAMPLERCUBE = 438, + USAMPLER1DARRAY = 439, + USAMPLER2DARRAY = 440, + SAMPLER2DRECT = 441, + SAMPLER2DRECTSHADOW = 442, + ISAMPLER2DRECT = 443, + USAMPLER2DRECT = 444, + SAMPLERBUFFER = 445, + ISAMPLERBUFFER = 446, + USAMPLERBUFFER = 447, + SAMPLERCUBEARRAY = 448, + SAMPLERCUBEARRAYSHADOW = 449, + ISAMPLERCUBEARRAY = 450, + USAMPLERCUBEARRAY = 451, + SAMPLER2DMS = 452, + ISAMPLER2DMS = 453, + USAMPLER2DMS = 454, + SAMPLER2DMSARRAY = 455, + ISAMPLER2DMSARRAY = 456, + USAMPLER2DMSARRAY = 457, + SAMPLEREXTERNALOES = 458, + F16SAMPLER1D = 459, + F16SAMPLER2D = 460, + F16SAMPLER3D = 461, + F16SAMPLER2DRECT = 462, + F16SAMPLERCUBE = 463, + F16SAMPLER1DARRAY = 464, + F16SAMPLER2DARRAY = 465, + F16SAMPLERCUBEARRAY = 466, + F16SAMPLERBUFFER = 467, + F16SAMPLER2DMS = 468, + F16SAMPLER2DMSARRAY = 469, + F16SAMPLER1DSHADOW = 470, + F16SAMPLER2DSHADOW = 471, + F16SAMPLER1DARRAYSHADOW = 472, + F16SAMPLER2DARRAYSHADOW = 473, + F16SAMPLER2DRECTSHADOW = 474, + F16SAMPLERCUBESHADOW = 475, + F16SAMPLERCUBEARRAYSHADOW = 476, + SAMPLER = 477, + SAMPLERSHADOW = 478, + TEXTURE1D = 479, + TEXTURE2D = 480, + TEXTURE3D = 481, + TEXTURECUBE = 482, + TEXTURE1DARRAY = 483, + TEXTURE2DARRAY = 484, + ITEXTURE1D = 485, + ITEXTURE2D = 486, + ITEXTURE3D = 487, + ITEXTURECUBE = 488, + ITEXTURE1DARRAY = 489, + ITEXTURE2DARRAY = 490, + UTEXTURE1D = 491, + UTEXTURE2D = 492, + UTEXTURE3D = 493, + UTEXTURECUBE = 494, + UTEXTURE1DARRAY = 495, + UTEXTURE2DARRAY = 496, + TEXTURE2DRECT = 497, + ITEXTURE2DRECT = 498, + UTEXTURE2DRECT = 499, + TEXTUREBUFFER = 500, + ITEXTUREBUFFER = 501, + UTEXTUREBUFFER = 502, + TEXTURECUBEARRAY = 503, + ITEXTURECUBEARRAY = 504, + UTEXTURECUBEARRAY = 505, + TEXTURE2DMS = 506, + ITEXTURE2DMS = 507, + UTEXTURE2DMS = 508, + TEXTURE2DMSARRAY = 509, + ITEXTURE2DMSARRAY = 510, + UTEXTURE2DMSARRAY = 511, + F16TEXTURE1D = 512, + F16TEXTURE2D = 513, + F16TEXTURE3D = 514, + F16TEXTURE2DRECT = 515, + F16TEXTURECUBE = 516, + F16TEXTURE1DARRAY = 517, + F16TEXTURE2DARRAY = 518, + F16TEXTURECUBEARRAY = 519, + F16TEXTUREBUFFER = 520, + F16TEXTURE2DMS = 521, + F16TEXTURE2DMSARRAY = 522, + SUBPASSINPUT = 523, + SUBPASSINPUTMS = 524, + ISUBPASSINPUT = 525, + ISUBPASSINPUTMS = 526, + USUBPASSINPUT = 527, + USUBPASSINPUTMS = 528, + F16SUBPASSINPUT = 529, + F16SUBPASSINPUTMS = 530, + IMAGE1D = 531, + IIMAGE1D = 532, + UIMAGE1D = 533, + IMAGE2D = 534, + IIMAGE2D = 535, + UIMAGE2D = 536, + IMAGE3D = 537, + IIMAGE3D = 538, + UIMAGE3D = 539, + IMAGE2DRECT = 540, + IIMAGE2DRECT = 541, + UIMAGE2DRECT = 542, + IMAGECUBE = 543, + IIMAGECUBE = 544, + UIMAGECUBE = 545, + IMAGEBUFFER = 546, + IIMAGEBUFFER = 547, + UIMAGEBUFFER = 548, + IMAGE1DARRAY = 549, + IIMAGE1DARRAY = 550, + UIMAGE1DARRAY = 551, + IMAGE2DARRAY = 552, + IIMAGE2DARRAY = 553, + UIMAGE2DARRAY = 554, + IMAGECUBEARRAY = 555, + IIMAGECUBEARRAY = 556, + UIMAGECUBEARRAY = 557, + IMAGE2DMS = 558, + IIMAGE2DMS = 559, + UIMAGE2DMS = 560, + IMAGE2DMSARRAY = 561, + IIMAGE2DMSARRAY = 562, + UIMAGE2DMSARRAY = 563, + F16IMAGE1D = 564, + F16IMAGE2D = 565, + F16IMAGE3D = 566, + F16IMAGE2DRECT = 567, + F16IMAGECUBE = 568, + F16IMAGE1DARRAY = 569, + F16IMAGE2DARRAY = 570, + F16IMAGECUBEARRAY = 571, + F16IMAGEBUFFER = 572, + F16IMAGE2DMS = 573, + F16IMAGE2DMSARRAY = 574, + STRUCT = 575, + VOID = 576, + WHILE = 577, + IDENTIFIER = 578, + TYPE_NAME = 579, + FLOATCONSTANT = 580, + DOUBLECONSTANT = 581, + INT16CONSTANT = 582, + UINT16CONSTANT = 583, + INT32CONSTANT = 584, + UINT32CONSTANT = 585, + INTCONSTANT = 586, + UINTCONSTANT = 587, + INT64CONSTANT = 588, + UINT64CONSTANT = 589, + BOOLCONSTANT = 590, + FLOAT16CONSTANT = 591, + LEFT_OP = 592, + RIGHT_OP = 593, + INC_OP = 594, + DEC_OP = 595, + LE_OP = 596, + GE_OP = 597, + EQ_OP = 598, + NE_OP = 599, + AND_OP = 600, + OR_OP = 601, + XOR_OP = 602, + MUL_ASSIGN = 603, + DIV_ASSIGN = 604, + ADD_ASSIGN = 605, + MOD_ASSIGN = 606, + LEFT_ASSIGN = 607, + RIGHT_ASSIGN = 608, + AND_ASSIGN = 609, + XOR_ASSIGN = 610, + OR_ASSIGN = 611, + SUB_ASSIGN = 612, + LEFT_PAREN = 613, + RIGHT_PAREN = 614, + LEFT_BRACKET = 615, + RIGHT_BRACKET = 616, + LEFT_BRACE = 617, + RIGHT_BRACE = 618, + DOT = 619, + COMMA = 620, + COLON = 621, + EQUAL = 622, + SEMICOLON = 623, + BANG = 624, + DASH = 625, + TILDE = 626, + PLUS = 627, + STAR = 628, + SLASH = 629, + PERCENT = 630, + LEFT_ANGLE = 631, + RIGHT_ANGLE = 632, + VERTICAL_BAR = 633, + CARET = 634, + AMPERSAND = 635, + QUESTION = 636, + INVARIANT = 637, + PRECISE = 638, + HIGH_PRECISION = 639, + MEDIUM_PRECISION = 640, + LOW_PRECISION = 641, + PRECISION = 642, + PACKED = 643, + RESOURCE = 644, + SUPERP = 645 }; #endif /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED - +typedef union YYSTYPE YYSTYPE; union YYSTYPE { -#line 66 "MachineIndependent/glslang.y" /* yacc.c:1909 */ +#line 70 "MachineIndependent/glslang.y" /* yacc.c:1909 */ struct { glslang::TSourceLoc loc; @@ -342,6 +463,7 @@ union YYSTYPE TIntermNode* intermNode; glslang::TIntermNodePair nodePair; glslang::TIntermTyped* intermTypedNode; + glslang::TAttributes* attributes; }; union { glslang::TPublicType type; @@ -354,10 +476,8 @@ union YYSTYPE }; } interm; -#line 358 "MachineIndependent/glslang_tab.cpp.h" /* yacc.c:1909 */ +#line 480 "MachineIndependent/glslang_tab.cpp.h" /* yacc.c:1909 */ }; - -typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif diff --git a/Externals/glslang/glslang/MachineIndependent/intermOut.cpp b/Externals/glslang/glslang/MachineIndependent/intermOut.cpp old mode 100644 new mode 100755 index 03519bc9a0..17c5b42a33 --- a/Externals/glslang/glslang/MachineIndependent/intermOut.cpp +++ b/Externals/glslang/glslang/MachineIndependent/intermOut.cpp @@ -1,12 +1,13 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2012-2016 LunarG, Inc. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2012-2016 LunarG, Inc. +// Copyright (C) 2017 ARM Limited. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,40 +21,56 @@ // 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. +// 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. // #include "localintermediate.h" #include "../Include/InfoSink.h" #ifdef _MSC_VER -#include -#elif defined __ANDROID__ || defined __linux__ || __MINGW32__ || __MINGW64__ -#include +#include #else -#include +#include #endif namespace { -bool is_positive_infinity(double x) { +bool IsInfinity(double x) { #ifdef _MSC_VER - return _fpclass(x) == _FPCLASS_PINF; -#elif defined __ANDROID__ || defined __linux__ || __MINGW32__ || __MINGW64__ - return std::isinf(x) && (x >= 0); + switch (_fpclass(x)) { + case _FPCLASS_NINF: + case _FPCLASS_PINF: + return true; + default: + return false; + } #else - return isinf(x) && (x >= 0); + return std::isinf(x); +#endif +} + +bool IsNan(double x) { +#ifdef _MSC_VER + switch (_fpclass(x)) { + case _FPCLASS_SNAN: + case _FPCLASS_QNAN: + return true; + default: + return false; + } +#else + return std::isnan(x); #endif } @@ -76,7 +93,13 @@ namespace glslang { // class TOutputTraverser : public TIntermTraverser { public: - TOutputTraverser(TInfoSink& i) : infoSink(i) { } + TOutputTraverser(TInfoSink& i) : infoSink(i), extraOutput(NoExtraOutput) { } + + enum EExtraOutput { + NoExtraOutput, + BinaryDoubleOutput + }; + void setDoubleOutput(EExtraOutput extra) { extraOutput = extra; } virtual bool visitBinary(TVisit, TIntermBinary* node); virtual bool visitUnary(TVisit, TIntermUnary* node); @@ -92,6 +115,8 @@ public: protected: TOutputTraverser(TOutputTraverser&); TOutputTraverser& operator=(TOutputTraverser&); + + EExtraOutput extraOutput; }; // @@ -150,6 +175,7 @@ bool TOutputTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node) out.debug << (*node->getLeft()->getType().getStruct())[node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst()].type->getFieldName(); out.debug << ": direct index for structure"; break; case EOpVectorSwizzle: out.debug << "vector swizzle"; break; + case EOpMatrixSwizzle: out.debug << "matrix swizzle"; break; case EOpAdd: out.debug << "add"; break; case EOpSub: out.debug << "subtract"; break; @@ -167,6 +193,8 @@ bool TOutputTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node) case EOpGreaterThan: out.debug << "Compare Greater Than"; break; case EOpLessThanEqual: out.debug << "Compare Less Than or Equal"; break; case EOpGreaterThanEqual: out.debug << "Compare Greater Than or Equal"; break; + case EOpVectorEqual: out.debug << "Equal"; break; + case EOpVectorNotEqual: out.debug << "NotEqual"; break; case EOpVectorTimesScalar: out.debug << "vector-scale"; break; case EOpVectorTimesMatrix: out.debug << "vector-times-matrix"; break; @@ -177,6 +205,7 @@ bool TOutputTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node) case EOpLogicalOr: out.debug << "logical-or"; break; case EOpLogicalXor: out.debug << "logical-xor"; break; case EOpLogicalAnd: out.debug << "logical-and"; break; + default: out.debug << ""; } @@ -204,48 +233,192 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node) case EOpPreIncrement: out.debug << "Pre-Increment"; break; case EOpPreDecrement: out.debug << "Pre-Decrement"; 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 EOpConvFloatToBool: out.debug << "Convert float to bool"; break; - case EOpConvDoubleToBool: out.debug << "Convert double to bool"; break; case EOpConvInt64ToBool: out.debug << "Convert int64 to bool"; break; case EOpConvUint64ToBool: out.debug << "Convert uint64 to bool"; break; - case EOpConvIntToFloat: out.debug << "Convert int to float"; break; - case EOpConvUintToFloat: out.debug << "Convert uint to float"; break; - case EOpConvDoubleToFloat: out.debug << "Convert double to float"; break; - case EOpConvInt64ToFloat: out.debug << "Convert int64 to float"; break; - case EOpConvUint64ToFloat: out.debug << "Convert uint64 to float"; break; - case EOpConvBoolToFloat: out.debug << "Convert bool to float"; break; - case EOpConvUintToInt: out.debug << "Convert uint to int"; break; - case EOpConvFloatToInt: out.debug << "Convert float to int"; break; - case EOpConvDoubleToInt: out.debug << "Convert double to int"; break; - case EOpConvBoolToInt: out.debug << "Convert bool to int"; break; - case EOpConvInt64ToInt: out.debug << "Convert int64 to int"; break; - case EOpConvUint64ToInt: out.debug << "Convert uint64 to int"; break; - case EOpConvIntToUint: out.debug << "Convert int to uint"; break; - case EOpConvFloatToUint: out.debug << "Convert float to uint"; break; - case EOpConvDoubleToUint: out.debug << "Convert double to uint"; 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 EOpConvInt64ToUint: out.debug << "Convert int64 to uint"; break; - case EOpConvUint64ToUint: out.debug << "Convert uint64 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; - case EOpConvUintToDouble: out.debug << "Convert uint to double"; break; - case EOpConvFloatToDouble: out.debug << "Convert float to double"; break; - case EOpConvBoolToDouble: out.debug << "Convert bool to double"; break; - case EOpConvInt64ToDouble: out.debug << "Convert int64 to double"; break; - case EOpConvUint64ToDouble: out.debug << "Convert uint64 to double"; break; - case EOpConvBoolToInt64: out.debug << "Convert bool to int64"; break; - case EOpConvIntToInt64: out.debug << "Convert int to int64"; 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 EOpConvFloatToInt64: out.debug << "Convert float to int64"; break; - case EOpConvDoubleToInt64: out.debug << "Convert double to int64"; break; - case EOpConvUint64ToInt64: out.debug << "Convert uint64 to int64"; break; - case EOpConvBoolToUint64: out.debug << "Convert bool to uint64"; break; - case EOpConvIntToUint64: out.debug << "Convert int to uint64"; break; - case EOpConvUintToUint64: out.debug << "Convert uint to uint64"; 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 EOpConvInt64ToUint64: out.debug << "Convert uint64 to uint64"; break; + case EOpRadians: out.debug << "radians"; break; case EOpDegrees: out.debug << "degrees"; break; @@ -289,12 +462,23 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node) case EOpDoubleBitsToUint64: out.debug << "doubleBitsToUint64"; break; case EOpInt64BitsToDouble: out.debug << "int64BitsToDouble"; break; case EOpUint64BitsToDouble: out.debug << "uint64BitsToDouble"; break; + case EOpFloat16BitsToInt16: out.debug << "float16BitsToInt16"; break; + case EOpFloat16BitsToUint16: out.debug << "float16BitsToUint16"; break; + case EOpInt16BitsToFloat16: out.debug << "int16BitsToFloat16"; break; + case EOpUint16BitsToFloat16: out.debug << "uint16BitsToFloat16"; break; + case EOpPackSnorm2x16: out.debug << "packSnorm2x16"; break; case EOpUnpackSnorm2x16:out.debug << "unpackSnorm2x16"; break; case EOpPackUnorm2x16: out.debug << "packUnorm2x16"; break; case EOpUnpackUnorm2x16:out.debug << "unpackUnorm2x16"; break; case EOpPackHalf2x16: out.debug << "packHalf2x16"; break; case EOpUnpackHalf2x16: out.debug << "unpackHalf2x16"; break; + case EOpPack16: out.debug << "pack16"; break; + case EOpPack32: out.debug << "pack32"; break; + case EOpPack64: out.debug << "pack64"; break; + case EOpUnpack32: out.debug << "unpack32"; break; + case EOpUnpack16: out.debug << "unpack16"; break; + case EOpUnpack8: out.debug << "unpack8"; break; case EOpPackSnorm4x8: out.debug << "PackSnorm4x8"; break; case EOpUnpackSnorm4x8: out.debug << "UnpackSnorm4x8"; break; @@ -308,6 +492,18 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node) case EOpPackUint2x32: out.debug << "packUint2x32"; break; case EOpUnpackUint2x32: out.debug << "unpackUint2x32"; break; + case EOpPackInt2x16: out.debug << "packInt2x16"; break; + case EOpUnpackInt2x16: out.debug << "unpackInt2x16"; break; + case EOpPackUint2x16: out.debug << "packUint2x16"; break; + case EOpUnpackUint2x16: out.debug << "unpackUint2x16"; break; + + case EOpPackInt4x16: out.debug << "packInt4x16"; break; + case EOpUnpackInt4x16: out.debug << "unpackInt4x16"; break; + case EOpPackUint4x16: out.debug << "packUint4x16"; break; + case EOpUnpackUint4x16: out.debug << "unpackUint4x16"; break; + case EOpPackFloat2x16: out.debug << "packFloat2x16"; break; + case EOpUnpackFloat2x16: out.debug << "unpackFloat2x16"; break; + case EOpLength: out.debug << "length"; break; case EOpNormalize: out.debug << "normalize"; break; case EOpDPdx: out.debug << "dPdx"; break; @@ -355,16 +551,129 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node) case EOpBallot: out.debug << "ballot"; break; case EOpReadFirstInvocation: out.debug << "readFirstInvocation"; break; + case EOpAnyInvocation: out.debug << "anyInvocation"; break; case EOpAllInvocations: out.debug << "allInvocations"; break; case EOpAllInvocationsEqual: out.debug << "allInvocationsEqual"; break; + case EOpSubgroupElect: out.debug << "subgroupElect"; break; + case EOpSubgroupAll: out.debug << "subgroupAll"; break; + case EOpSubgroupAny: out.debug << "subgroupAny"; break; + case EOpSubgroupAllEqual: out.debug << "subgroupAllEqual"; break; + case EOpSubgroupBroadcast: out.debug << "subgroupBroadcast"; break; + case EOpSubgroupBroadcastFirst: out.debug << "subgroupBroadcastFirst"; break; + case EOpSubgroupBallot: out.debug << "subgroupBallot"; break; + case EOpSubgroupInverseBallot: out.debug << "subgroupInverseBallot"; break; + case EOpSubgroupBallotBitExtract: out.debug << "subgroupBallotBitExtract"; break; + case EOpSubgroupBallotBitCount: out.debug << "subgroupBallotBitCount"; break; + case EOpSubgroupBallotInclusiveBitCount: out.debug << "subgroupBallotInclusiveBitCount"; break; + case EOpSubgroupBallotExclusiveBitCount: out.debug << "subgroupBallotExclusiveBitCount"; break; + case EOpSubgroupBallotFindLSB: out.debug << "subgroupBallotFindLSB"; break; + case EOpSubgroupBallotFindMSB: out.debug << "subgroupBallotFindMSB"; break; + case EOpSubgroupShuffle: out.debug << "subgroupShuffle"; break; + case EOpSubgroupShuffleXor: out.debug << "subgroupShuffleXor"; break; + case EOpSubgroupShuffleUp: out.debug << "subgroupShuffleUp"; break; + case EOpSubgroupShuffleDown: out.debug << "subgroupShuffleDown"; break; + case EOpSubgroupAdd: out.debug << "subgroupAdd"; break; + case EOpSubgroupMul: out.debug << "subgroupMul"; break; + case EOpSubgroupMin: out.debug << "subgroupMin"; break; + case EOpSubgroupMax: out.debug << "subgroupMax"; break; + case EOpSubgroupAnd: out.debug << "subgroupAnd"; break; + case EOpSubgroupOr: out.debug << "subgroupOr"; break; + case EOpSubgroupXor: out.debug << "subgroupXor"; break; + case EOpSubgroupInclusiveAdd: out.debug << "subgroupInclusiveAdd"; break; + case EOpSubgroupInclusiveMul: out.debug << "subgroupInclusiveMul"; break; + case EOpSubgroupInclusiveMin: out.debug << "subgroupInclusiveMin"; break; + case EOpSubgroupInclusiveMax: out.debug << "subgroupInclusiveMax"; break; + case EOpSubgroupInclusiveAnd: out.debug << "subgroupInclusiveAnd"; break; + case EOpSubgroupInclusiveOr: out.debug << "subgroupInclusiveOr"; break; + case EOpSubgroupInclusiveXor: out.debug << "subgroupInclusiveXor"; break; + case EOpSubgroupExclusiveAdd: out.debug << "subgroupExclusiveAdd"; break; + case EOpSubgroupExclusiveMul: out.debug << "subgroupExclusiveMul"; break; + case EOpSubgroupExclusiveMin: out.debug << "subgroupExclusiveMin"; break; + case EOpSubgroupExclusiveMax: out.debug << "subgroupExclusiveMax"; break; + case EOpSubgroupExclusiveAnd: out.debug << "subgroupExclusiveAnd"; break; + case EOpSubgroupExclusiveOr: out.debug << "subgroupExclusiveOr"; break; + case EOpSubgroupExclusiveXor: out.debug << "subgroupExclusiveXor"; break; + case EOpSubgroupClusteredAdd: out.debug << "subgroupClusteredAdd"; break; + case EOpSubgroupClusteredMul: out.debug << "subgroupClusteredMul"; break; + case EOpSubgroupClusteredMin: out.debug << "subgroupClusteredMin"; break; + case EOpSubgroupClusteredMax: out.debug << "subgroupClusteredMax"; break; + case EOpSubgroupClusteredAnd: out.debug << "subgroupClusteredAnd"; break; + case EOpSubgroupClusteredOr: out.debug << "subgroupClusteredOr"; break; + case EOpSubgroupClusteredXor: out.debug << "subgroupClusteredXor"; break; + case EOpSubgroupQuadBroadcast: out.debug << "subgroupQuadBroadcast"; break; + case EOpSubgroupQuadSwapHorizontal: out.debug << "subgroupQuadSwapHorizontal"; break; + case EOpSubgroupQuadSwapVertical: out.debug << "subgroupQuadSwapVertical"; break; + case EOpSubgroupQuadSwapDiagonal: out.debug << "subgroupQuadSwapDiagonal"; break; + +#ifdef NV_EXTENSIONS + case EOpSubgroupPartition: out.debug << "subgroupPartitionNV"; break; + case EOpSubgroupPartitionedAdd: out.debug << "subgroupPartitionedAddNV"; break; + case EOpSubgroupPartitionedMul: out.debug << "subgroupPartitionedMulNV"; break; + case EOpSubgroupPartitionedMin: out.debug << "subgroupPartitionedMinNV"; break; + case EOpSubgroupPartitionedMax: out.debug << "subgroupPartitionedMaxNV"; break; + case EOpSubgroupPartitionedAnd: out.debug << "subgroupPartitionedAndNV"; break; + case EOpSubgroupPartitionedOr: out.debug << "subgroupPartitionedOrNV"; break; + case EOpSubgroupPartitionedXor: out.debug << "subgroupPartitionedXorNV"; break; + case EOpSubgroupPartitionedInclusiveAdd: out.debug << "subgroupPartitionedInclusiveAddNV"; break; + case EOpSubgroupPartitionedInclusiveMul: out.debug << "subgroupPartitionedInclusiveMulNV"; break; + case EOpSubgroupPartitionedInclusiveMin: out.debug << "subgroupPartitionedInclusiveMinNV"; break; + case EOpSubgroupPartitionedInclusiveMax: out.debug << "subgroupPartitionedInclusiveMaxNV"; break; + case EOpSubgroupPartitionedInclusiveAnd: out.debug << "subgroupPartitionedInclusiveAndNV"; break; + case EOpSubgroupPartitionedInclusiveOr: out.debug << "subgroupPartitionedInclusiveOrNV"; break; + case EOpSubgroupPartitionedInclusiveXor: out.debug << "subgroupPartitionedInclusiveXorNV"; break; + case EOpSubgroupPartitionedExclusiveAdd: out.debug << "subgroupPartitionedExclusiveAddNV"; break; + case EOpSubgroupPartitionedExclusiveMul: out.debug << "subgroupPartitionedExclusiveMulNV"; break; + case EOpSubgroupPartitionedExclusiveMin: out.debug << "subgroupPartitionedExclusiveMinNV"; break; + case EOpSubgroupPartitionedExclusiveMax: out.debug << "subgroupPartitionedExclusiveMaxNV"; break; + case EOpSubgroupPartitionedExclusiveAnd: out.debug << "subgroupPartitionedExclusiveAndNV"; break; + case EOpSubgroupPartitionedExclusiveOr: out.debug << "subgroupPartitionedExclusiveOrNV"; break; + case EOpSubgroupPartitionedExclusiveXor: out.debug << "subgroupPartitionedExclusiveXorNV"; break; +#endif + case EOpClip: out.debug << "clip"; break; case EOpIsFinite: out.debug << "isfinite"; break; case EOpLog10: out.debug << "log10"; break; case EOpRcp: out.debug << "rcp"; break; case EOpSaturate: out.debug << "saturate"; break; + case EOpSparseTexelsResident: out.debug << "sparseTexelsResident"; break; + +#ifdef AMD_EXTENSIONS + case EOpMinInvocations: out.debug << "minInvocations"; break; + case EOpMaxInvocations: out.debug << "maxInvocations"; break; + case EOpAddInvocations: out.debug << "addInvocations"; break; + case EOpMinInvocationsNonUniform: out.debug << "minInvocationsNonUniform"; break; + case EOpMaxInvocationsNonUniform: out.debug << "maxInvocationsNonUniform"; break; + case EOpAddInvocationsNonUniform: out.debug << "addInvocationsNonUniform"; break; + + case EOpMinInvocationsInclusiveScan: out.debug << "minInvocationsInclusiveScan"; break; + case EOpMaxInvocationsInclusiveScan: out.debug << "maxInvocationsInclusiveScan"; break; + case EOpAddInvocationsInclusiveScan: out.debug << "addInvocationsInclusiveScan"; break; + case EOpMinInvocationsInclusiveScanNonUniform: out.debug << "minInvocationsInclusiveScanNonUniform"; break; + case EOpMaxInvocationsInclusiveScanNonUniform: out.debug << "maxInvocationsInclusiveScanNonUniform"; break; + case EOpAddInvocationsInclusiveScanNonUniform: out.debug << "addInvocationsInclusiveScanNonUniform"; break; + + case EOpMinInvocationsExclusiveScan: out.debug << "minInvocationsExclusiveScan"; break; + case EOpMaxInvocationsExclusiveScan: out.debug << "maxInvocationsExclusiveScan"; break; + case EOpAddInvocationsExclusiveScan: out.debug << "addInvocationsExclusiveScan"; break; + case EOpMinInvocationsExclusiveScanNonUniform: out.debug << "minInvocationsExclusiveScanNonUniform"; break; + case EOpMaxInvocationsExclusiveScanNonUniform: out.debug << "maxInvocationsExclusiveScanNonUniform"; break; + case EOpAddInvocationsExclusiveScanNonUniform: out.debug << "addInvocationsExclusiveScanNonUniform"; break; + + case EOpMbcnt: out.debug << "mbcnt"; break; + + case EOpFragmentMaskFetch: out.debug << "fragmentMaskFetchAMD"; break; + case EOpFragmentFetch: out.debug << "fragmentFetchAMD"; break; + + case EOpCubeFaceIndex: out.debug << "cubeFaceIndex"; break; + case EOpCubeFaceCoord: out.debug << "cubeFaceCoord"; break; +#endif + + case EOpSubpassLoad: out.debug << "subpassLoad"; break; + case EOpSubpassLoadMS: out.debug << "subpassLoadMS"; break; + default: out.debug.message(EPrefixError, "Bad unary op"); } @@ -396,29 +705,49 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node case EOpConstructFloat: out.debug << "Construct float"; break; case EOpConstructDouble:out.debug << "Construct double"; break; + case EOpConstructVec2: out.debug << "Construct vec2"; break; case EOpConstructVec3: out.debug << "Construct vec3"; break; case EOpConstructVec4: out.debug << "Construct vec4"; break; + case EOpConstructDVec2: out.debug << "Construct dvec2"; break; + case EOpConstructDVec3: out.debug << "Construct dvec3"; break; + case EOpConstructDVec4: out.debug << "Construct dvec4"; break; case EOpConstructBool: out.debug << "Construct bool"; break; case EOpConstructBVec2: out.debug << "Construct bvec2"; break; case EOpConstructBVec3: out.debug << "Construct bvec3"; break; case EOpConstructBVec4: out.debug << "Construct bvec4"; break; + case EOpConstructInt8: out.debug << "Construct int8_t"; break; + case EOpConstructI8Vec2: out.debug << "Construct i8vec2"; break; + case EOpConstructI8Vec3: out.debug << "Construct i8vec3"; break; + case EOpConstructI8Vec4: out.debug << "Construct i8vec4"; break; case EOpConstructInt: out.debug << "Construct int"; break; case EOpConstructIVec2: out.debug << "Construct ivec2"; break; case EOpConstructIVec3: out.debug << "Construct ivec3"; break; case EOpConstructIVec4: out.debug << "Construct ivec4"; break; + case EOpConstructUint8: out.debug << "Construct uint8_t"; break; + case EOpConstructU8Vec2: out.debug << "Construct u8vec2"; break; + case EOpConstructU8Vec3: out.debug << "Construct u8vec3"; break; + case EOpConstructU8Vec4: out.debug << "Construct u8vec4"; break; case EOpConstructUint: out.debug << "Construct uint"; break; case EOpConstructUVec2: out.debug << "Construct uvec2"; break; case EOpConstructUVec3: out.debug << "Construct uvec3"; break; case EOpConstructUVec4: out.debug << "Construct uvec4"; break; - case EOpConstructInt64: out.debug << "Construct int64_t"; break; + case EOpConstructInt64: out.debug << "Construct int64"; break; case EOpConstructI64Vec2: out.debug << "Construct i64vec2"; break; case EOpConstructI64Vec3: out.debug << "Construct i64vec3"; break; case EOpConstructI64Vec4: out.debug << "Construct i64vec4"; break; - case EOpConstructUint64: out.debug << "Construct uint64_t"; break; + case EOpConstructUint64: out.debug << "Construct uint64"; break; case EOpConstructU64Vec2: out.debug << "Construct u64vec2"; break; case EOpConstructU64Vec3: out.debug << "Construct u64vec3"; break; case EOpConstructU64Vec4: out.debug << "Construct u64vec4"; break; + case EOpConstructInt16: out.debug << "Construct int16_t"; break; + case EOpConstructI16Vec2: out.debug << "Construct i16vec2"; break; + case EOpConstructI16Vec3: out.debug << "Construct i16vec3"; break; + case EOpConstructI16Vec4: out.debug << "Construct i16vec4"; break; + case EOpConstructUint16: out.debug << "Construct uint16_t"; break; + case EOpConstructU16Vec2: out.debug << "Construct u16vec2"; break; + case EOpConstructU16Vec3: out.debug << "Construct u16vec3"; break; + case EOpConstructU16Vec4: out.debug << "Construct u16vec4"; break; case EOpConstructMat2x2: out.debug << "Construct mat2"; break; case EOpConstructMat2x3: out.debug << "Construct mat2x3"; break; case EOpConstructMat2x4: out.debug << "Construct mat2x4"; break; @@ -437,6 +766,46 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node case EOpConstructDMat4x2: out.debug << "Construct dmat4x2"; break; case EOpConstructDMat4x3: out.debug << "Construct dmat4x3"; break; case EOpConstructDMat4x4: out.debug << "Construct dmat4"; break; + case EOpConstructIMat2x2: out.debug << "Construct imat2"; break; + case EOpConstructIMat2x3: out.debug << "Construct imat2x3"; break; + case EOpConstructIMat2x4: out.debug << "Construct imat2x4"; break; + case EOpConstructIMat3x2: out.debug << "Construct imat3x2"; break; + case EOpConstructIMat3x3: out.debug << "Construct imat3"; break; + case EOpConstructIMat3x4: out.debug << "Construct imat3x4"; break; + case EOpConstructIMat4x2: out.debug << "Construct imat4x2"; break; + case EOpConstructIMat4x3: out.debug << "Construct imat4x3"; break; + case EOpConstructIMat4x4: out.debug << "Construct imat4"; break; + case EOpConstructUMat2x2: out.debug << "Construct umat2"; break; + case EOpConstructUMat2x3: out.debug << "Construct umat2x3"; break; + case EOpConstructUMat2x4: out.debug << "Construct umat2x4"; break; + case EOpConstructUMat3x2: out.debug << "Construct umat3x2"; break; + case EOpConstructUMat3x3: out.debug << "Construct umat3"; break; + case EOpConstructUMat3x4: out.debug << "Construct umat3x4"; break; + case EOpConstructUMat4x2: out.debug << "Construct umat4x2"; break; + case EOpConstructUMat4x3: out.debug << "Construct umat4x3"; break; + case EOpConstructUMat4x4: out.debug << "Construct umat4"; break; + case EOpConstructBMat2x2: out.debug << "Construct bmat2"; break; + case EOpConstructBMat2x3: out.debug << "Construct bmat2x3"; break; + case EOpConstructBMat2x4: out.debug << "Construct bmat2x4"; break; + case EOpConstructBMat3x2: out.debug << "Construct bmat3x2"; break; + case EOpConstructBMat3x3: out.debug << "Construct bmat3"; break; + case EOpConstructBMat3x4: out.debug << "Construct bmat3x4"; break; + case EOpConstructBMat4x2: out.debug << "Construct bmat4x2"; break; + case EOpConstructBMat4x3: out.debug << "Construct bmat4x3"; break; + case EOpConstructBMat4x4: out.debug << "Construct bmat4"; break; + case EOpConstructFloat16: out.debug << "Construct float16_t"; break; + case EOpConstructF16Vec2: out.debug << "Construct f16vec2"; break; + case EOpConstructF16Vec3: out.debug << "Construct f16vec3"; break; + case EOpConstructF16Vec4: out.debug << "Construct f16vec4"; break; + case EOpConstructF16Mat2x2: out.debug << "Construct f16mat2"; break; + case EOpConstructF16Mat2x3: out.debug << "Construct f16mat2x3"; break; + case EOpConstructF16Mat2x4: out.debug << "Construct f16mat2x4"; break; + case EOpConstructF16Mat3x2: out.debug << "Construct f16mat3x2"; break; + case EOpConstructF16Mat3x3: out.debug << "Construct f16mat3"; break; + case EOpConstructF16Mat3x4: out.debug << "Construct f16mat3x4"; break; + case EOpConstructF16Mat4x2: out.debug << "Construct f16mat4x2"; break; + case EOpConstructF16Mat4x3: out.debug << "Construct f16mat4x3"; break; + case EOpConstructF16Mat4x4: out.debug << "Construct f16mat4"; break; case EOpConstructStruct: out.debug << "Construct structure"; break; case EOpConstructTextureSampler: out.debug << "Construct combined texture-sampler"; break; @@ -482,6 +851,18 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node case EOpReadInvocation: out.debug << "readInvocation"; break; +#ifdef AMD_EXTENSIONS + case EOpSwizzleInvocations: out.debug << "swizzleInvocations"; break; + case EOpSwizzleInvocationsMasked: out.debug << "swizzleInvocationsMasked"; break; + case EOpWriteInvocation: out.debug << "writeInvocation"; break; + + case EOpMin3: out.debug << "min3"; break; + case EOpMax3: out.debug << "max3"; break; + case EOpMid3: out.debug << "mid3"; break; + + case EOpTime: out.debug << "time"; break; +#endif + case EOpAtomicAdd: out.debug << "AtomicAdd"; break; case EOpAtomicMin: out.debug << "AtomicMin"; break; case EOpAtomicMax: out.debug << "AtomicMax"; break; @@ -491,6 +872,16 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node case EOpAtomicExchange: out.debug << "AtomicExchange"; break; case EOpAtomicCompSwap: out.debug << "AtomicCompSwap"; break; + case EOpAtomicCounterAdd: out.debug << "AtomicCounterAdd"; break; + case EOpAtomicCounterSubtract: out.debug << "AtomicCounterSubtract"; break; + case EOpAtomicCounterMin: out.debug << "AtomicCounterMin"; break; + case EOpAtomicCounterMax: out.debug << "AtomicCounterMax"; break; + case EOpAtomicCounterAnd: out.debug << "AtomicCounterAnd"; break; + case EOpAtomicCounterOr: out.debug << "AtomicCounterOr"; break; + case EOpAtomicCounterXor: out.debug << "AtomicCounterXor"; break; + case EOpAtomicCounterExchange: out.debug << "AtomicCounterExchange"; break; + case EOpAtomicCounterCompSwap: out.debug << "AtomicCounterCompSwap"; break; + case EOpImageQuerySize: out.debug << "imageQuerySize"; break; case EOpImageQuerySamples: out.debug << "imageQuerySamples"; break; case EOpImageLoad: out.debug << "imageLoad"; break; @@ -503,6 +894,10 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node case EOpImageAtomicXor: out.debug << "imageAtomicXor"; break; case EOpImageAtomicExchange: out.debug << "imageAtomicExchange"; break; case EOpImageAtomicCompSwap: out.debug << "imageAtomicCompSwap"; break; +#ifdef AMD_EXTENSIONS + case EOpImageLoadLod: out.debug << "imageLoadLod"; break; + case EOpImageStoreLod: out.debug << "imageStoreLod"; break; +#endif case EOpTextureQuerySize: out.debug << "textureSize"; break; case EOpTextureQueryLod: out.debug << "textureQueryLod"; break; @@ -525,6 +920,38 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node case EOpTextureGather: out.debug << "textureGather"; break; case EOpTextureGatherOffset: out.debug << "textureGatherOffset"; break; case EOpTextureGatherOffsets: out.debug << "textureGatherOffsets"; break; + case EOpTextureClamp: out.debug << "textureClamp"; break; + case EOpTextureOffsetClamp: out.debug << "textureOffsetClamp"; break; + case EOpTextureGradClamp: out.debug << "textureGradClamp"; break; + case EOpTextureGradOffsetClamp: out.debug << "textureGradOffsetClamp"; break; +#ifdef AMD_EXTENSIONS + case EOpTextureGatherLod: out.debug << "textureGatherLod"; break; + case EOpTextureGatherLodOffset: out.debug << "textureGatherLodOffset"; break; + case EOpTextureGatherLodOffsets: out.debug << "textureGatherLodOffsets"; break; +#endif + + case EOpSparseTexture: out.debug << "sparseTexture"; break; + case EOpSparseTextureOffset: out.debug << "sparseTextureOffset"; break; + case EOpSparseTextureLod: out.debug << "sparseTextureLod"; break; + case EOpSparseTextureLodOffset: out.debug << "sparseTextureLodOffset"; break; + case EOpSparseTextureFetch: out.debug << "sparseTexelFetch"; break; + case EOpSparseTextureFetchOffset: out.debug << "sparseTexelFetchOffset"; break; + case EOpSparseTextureGrad: out.debug << "sparseTextureGrad"; break; + case EOpSparseTextureGradOffset: out.debug << "sparseTextureGradOffset"; break; + case EOpSparseTextureGather: out.debug << "sparseTextureGather"; break; + case EOpSparseTextureGatherOffset: out.debug << "sparseTextureGatherOffset"; break; + case EOpSparseTextureGatherOffsets: out.debug << "sparseTextureGatherOffsets"; break; + case EOpSparseImageLoad: out.debug << "sparseImageLoad"; break; + case EOpSparseTextureClamp: out.debug << "sparseTextureClamp"; break; + case EOpSparseTextureOffsetClamp: out.debug << "sparseTextureOffsetClamp"; break; + case EOpSparseTextureGradClamp: out.debug << "sparseTextureGradClamp"; break; + case EOpSparseTextureGradOffsetClamp: out.debug << "sparseTextureGradOffsetClam"; break; +#ifdef AMD_EXTENSIONS + case EOpSparseTextureGatherLod: out.debug << "sparseTextureGatherLod"; break; + case EOpSparseTextureGatherLodOffset: out.debug << "sparseTextureGatherLodOffset"; break; + case EOpSparseTextureGatherLodOffsets: out.debug << "sparseTextureGatherLodOffsets"; break; + case EOpSparseImageLoadLod: out.debug << "sparseImageLoadLod"; break; +#endif case EOpAddCarry: out.debug << "addCarry"; break; case EOpSubBorrow: out.debug << "subBorrow"; break; @@ -539,15 +966,78 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node case EOpInterpolateAtSample: out.debug << "interpolateAtSample"; break; case EOpInterpolateAtOffset: out.debug << "interpolateAtOffset"; break; +#ifdef AMD_EXTENSIONS + case EOpInterpolateAtVertex: out.debug << "interpolateAtVertex"; break; +#endif case EOpSinCos: out.debug << "sincos"; break; case EOpGenMul: out.debug << "mul"; break; case EOpAllMemoryBarrierWithGroupSync: out.debug << "AllMemoryBarrierWithGroupSync"; break; - case EOpGroupMemoryBarrierWithGroupSync: out.debug << "GroupMemoryBarrierWithGroupSync"; break; + case EOpDeviceMemoryBarrier: out.debug << "DeviceMemoryBarrier"; break; + case EOpDeviceMemoryBarrierWithGroupSync: out.debug << "DeviceMemoryBarrierWithGroupSync"; break; case EOpWorkgroupMemoryBarrier: out.debug << "WorkgroupMemoryBarrier"; break; case EOpWorkgroupMemoryBarrierWithGroupSync: out.debug << "WorkgroupMemoryBarrierWithGroupSync"; break; + case EOpSubgroupBarrier: out.debug << "subgroupBarrier"; break; + case EOpSubgroupMemoryBarrier: out.debug << "subgroupMemoryBarrier"; break; + case EOpSubgroupMemoryBarrierBuffer: out.debug << "subgroupMemoryBarrierBuffer"; break; + case EOpSubgroupMemoryBarrierImage: out.debug << "subgroupMemoryBarrierImage"; break; + case EOpSubgroupMemoryBarrierShared: out.debug << "subgroupMemoryBarrierShared"; break; + case EOpSubgroupElect: out.debug << "subgroupElect"; break; + case EOpSubgroupAll: out.debug << "subgroupAll"; break; + case EOpSubgroupAny: out.debug << "subgroupAny"; break; + case EOpSubgroupAllEqual: out.debug << "subgroupAllEqual"; break; + case EOpSubgroupBroadcast: out.debug << "subgroupBroadcast"; break; + case EOpSubgroupBroadcastFirst: out.debug << "subgroupBroadcastFirst"; break; + case EOpSubgroupBallot: out.debug << "subgroupBallot"; break; + case EOpSubgroupInverseBallot: out.debug << "subgroupInverseBallot"; break; + case EOpSubgroupBallotBitExtract: out.debug << "subgroupBallotBitExtract"; break; + case EOpSubgroupBallotBitCount: out.debug << "subgroupBallotBitCount"; break; + case EOpSubgroupBallotInclusiveBitCount: out.debug << "subgroupBallotInclusiveBitCount"; break; + case EOpSubgroupBallotExclusiveBitCount: out.debug << "subgroupBallotExclusiveBitCount"; break; + case EOpSubgroupBallotFindLSB: out.debug << "subgroupBallotFindLSB"; break; + case EOpSubgroupBallotFindMSB: out.debug << "subgroupBallotFindMSB"; break; + case EOpSubgroupShuffle: out.debug << "subgroupShuffle"; break; + case EOpSubgroupShuffleXor: out.debug << "subgroupShuffleXor"; break; + case EOpSubgroupShuffleUp: out.debug << "subgroupShuffleUp"; break; + case EOpSubgroupShuffleDown: out.debug << "subgroupShuffleDown"; break; + case EOpSubgroupAdd: out.debug << "subgroupAdd"; break; + case EOpSubgroupMul: out.debug << "subgroupMul"; break; + case EOpSubgroupMin: out.debug << "subgroupMin"; break; + case EOpSubgroupMax: out.debug << "subgroupMax"; break; + case EOpSubgroupAnd: out.debug << "subgroupAnd"; break; + case EOpSubgroupOr: out.debug << "subgroupOr"; break; + case EOpSubgroupXor: out.debug << "subgroupXor"; break; + case EOpSubgroupInclusiveAdd: out.debug << "subgroupInclusiveAdd"; break; + case EOpSubgroupInclusiveMul: out.debug << "subgroupInclusiveMul"; break; + case EOpSubgroupInclusiveMin: out.debug << "subgroupInclusiveMin"; break; + case EOpSubgroupInclusiveMax: out.debug << "subgroupInclusiveMax"; break; + case EOpSubgroupInclusiveAnd: out.debug << "subgroupInclusiveAnd"; break; + case EOpSubgroupInclusiveOr: out.debug << "subgroupInclusiveOr"; break; + case EOpSubgroupInclusiveXor: out.debug << "subgroupInclusiveXor"; break; + case EOpSubgroupExclusiveAdd: out.debug << "subgroupExclusiveAdd"; break; + case EOpSubgroupExclusiveMul: out.debug << "subgroupExclusiveMul"; break; + case EOpSubgroupExclusiveMin: out.debug << "subgroupExclusiveMin"; break; + case EOpSubgroupExclusiveMax: out.debug << "subgroupExclusiveMax"; break; + case EOpSubgroupExclusiveAnd: out.debug << "subgroupExclusiveAnd"; break; + case EOpSubgroupExclusiveOr: out.debug << "subgroupExclusiveOr"; break; + case EOpSubgroupExclusiveXor: out.debug << "subgroupExclusiveXor"; break; + case EOpSubgroupClusteredAdd: out.debug << "subgroupClusteredAdd"; break; + case EOpSubgroupClusteredMul: out.debug << "subgroupClusteredMul"; break; + case EOpSubgroupClusteredMin: out.debug << "subgroupClusteredMin"; break; + case EOpSubgroupClusteredMax: out.debug << "subgroupClusteredMax"; break; + case EOpSubgroupClusteredAnd: out.debug << "subgroupClusteredAnd"; break; + case EOpSubgroupClusteredOr: out.debug << "subgroupClusteredOr"; break; + case EOpSubgroupClusteredXor: out.debug << "subgroupClusteredXor"; break; + case EOpSubgroupQuadBroadcast: out.debug << "subgroupQuadBroadcast"; break; + case EOpSubgroupQuadSwapHorizontal: out.debug << "subgroupQuadSwapHorizontal"; break; + case EOpSubgroupQuadSwapVertical: out.debug << "subgroupQuadSwapVertical"; break; + case EOpSubgroupQuadSwapDiagonal: out.debug << "subgroupQuadSwapDiagonal"; break; + + case EOpSubpassLoad: out.debug << "subpassLoad"; break; + case EOpSubpassLoadMS: out.debug << "subpassLoadMS"; break; + default: out.debug.message(EPrefixError, "Bad aggregation op"); } @@ -566,7 +1056,15 @@ bool TOutputTraverser::visitSelection(TVisit /* visit */, TIntermSelection* node OutputTreeText(out, node, depth); out.debug << "Test condition and select"; - out.debug << " (" << node->getCompleteString() << ")\n"; + out.debug << " (" << node->getCompleteString() << ")"; + + if (node->getShortCircuit() == false) + out.debug << ": no shortcircuit"; + if (node->getFlatten()) + out.debug << ": Flatten"; + if (node->getDontFlatten()) + out.debug << ": DontFlatten"; + out.debug << "\n"; ++depth; @@ -592,7 +1090,61 @@ bool TOutputTraverser::visitSelection(TVisit /* visit */, TIntermSelection* node return false; } -static void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const TConstUnionArray& constUnion, int depth) +// Print infinities and NaNs, and numbers in a portable way. +// Goals: +// - portable (across IEEE 754 platforms) +// - shows all possible IEEE values +// - shows simple numbers in a simple way, e.g., no leading/trailing 0s +// - shows all digits, no premature rounding +static void OutputDouble(TInfoSink& out, double value, TOutputTraverser::EExtraOutput extra) +{ + if (IsInfinity(value)) { + if (value < 0) + out.debug << "-1.#INF"; + else + out.debug << "+1.#INF"; + } else if (IsNan(value)) + out.debug << "1.#IND"; + else { + const int maxSize = 340; + char buf[maxSize]; + const char* format = "%f"; + if (fabs(value) > 0.0 && (fabs(value) < 1e-5 || fabs(value) > 1e12)) + format = "%-.13e"; + int len = snprintf(buf, maxSize, format, value); + assert(len < maxSize); + + // remove a leading zero in the 100s slot in exponent; it is not portable + // pattern: XX...XXXe+0XX or XX...XXXe-0XX + if (len > 5) { + if (buf[len-5] == 'e' && (buf[len-4] == '+' || buf[len-4] == '-') && buf[len-3] == '0') { + buf[len-3] = buf[len-2]; + buf[len-2] = buf[len-1]; + buf[len-1] = '\0'; + } + } + + out.debug << buf; + + switch (extra) { + case TOutputTraverser::BinaryDoubleOutput: + { + out.debug << " : "; + long long b = *reinterpret_cast(&value); + for (int i = 0; i < 8 * sizeof(value); ++i, ++b) { + out.debug << ((b & 0x8000000000000000) != 0 ? "1" : "0"); + b <<= 1; + } + break; + } + default: + break; + } + } +} + +static void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const TConstUnionArray& constUnion, + TOutputTraverser::EExtraOutput extra, int depth) { int size = node->getType().computeNumComponents(); @@ -611,20 +1163,44 @@ static void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const break; case EbtFloat: case EbtDouble: + case EbtFloat16: + OutputDouble(out, constUnion[i].getDConst(), extra); + out.debug << "\n"; + break; + case EbtInt8: { - const double value = constUnion[i].getDConst(); - // Print infinity in a portable way, for test stability. - // Other cases may be needed in the future: negative infinity, - // and NaNs. - if (is_positive_infinity(value)) - out.debug << "inf\n"; - else { - const int maxSize = 300; - char buf[maxSize]; - snprintf(buf, maxSize, "%f", value); + const int maxSize = 300; + char buf[maxSize]; + snprintf(buf, maxSize, "%d (%s)", constUnion[i].getI8Const(), "const int8_t"); - out.debug << buf << "\n"; - } + out.debug << buf << "\n"; + } + break; + case EbtUint8: + { + const int maxSize = 300; + char buf[maxSize]; + snprintf(buf, maxSize, "%u (%s)", constUnion[i].getU8Const(), "const uint8_t"); + + out.debug << buf << "\n"; + } + break; + case EbtInt16: + { + const int maxSize = 300; + char buf[maxSize]; + snprintf(buf, maxSize, "%d (%s)", constUnion[i].getI16Const(), "const int16_t"); + + out.debug << buf << "\n"; + } + break; + case EbtUint16: + { + const int maxSize = 300; + char buf[maxSize]; + snprintf(buf, maxSize, "%u (%s)", constUnion[i].getU16Const(), "const uint16_t"); + + out.debug << buf << "\n"; } break; case EbtInt: @@ -675,7 +1251,7 @@ void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node) OutputTreeText(infoSink, node, depth); infoSink.debug << "Constant:\n"; - OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1); + OutputConstantUnion(infoSink, node, node->getConstArray(), extraOutput, depth + 1); } void TOutputTraverser::visitSymbol(TIntermSymbol* node) @@ -685,7 +1261,7 @@ void TOutputTraverser::visitSymbol(TIntermSymbol* node) infoSink.debug << "'" << node->getName() << "' (" << node->getCompleteString() << ")\n"; if (! node->getConstArray().empty()) - OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1); + OutputConstantUnion(infoSink, node, node->getConstArray(), extraOutput, depth + 1); else if (node->getConstSubtree()) { incrementDepth(node); node->getConstSubtree()->traverse(this); @@ -702,7 +1278,17 @@ bool TOutputTraverser::visitLoop(TVisit /* visit */, TIntermLoop* node) out.debug << "Loop with condition "; if (! node->testFirst()) out.debug << "not "; - out.debug << "tested first\n"; + out.debug << "tested first"; + + if (node->getUnroll()) + out.debug << ": Unroll"; + if (node->getDontUnroll()) + out.debug << ": DontUnroll"; + if (node->getLoopDependency()) { + out.debug << ": Dependency "; + out.debug << node->getLoopDependency(); + } + out.debug << "\n"; ++depth; @@ -763,7 +1349,13 @@ bool TOutputTraverser::visitSwitch(TVisit /* visit */, TIntermSwitch* node) TInfoSink& out = infoSink; OutputTreeText(out, node, depth); - out.debug << "switch\n"; + out.debug << "switch"; + + if (node->getFlatten()) + out.debug << ": Flatten"; + if (node->getDontFlatten()) + out.debug << ": DontFlatten"; + out.debug << "\n"; OutputTreeText(out, node, depth); out.debug << "condition\n"; @@ -803,6 +1395,13 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree) case EShLangTessControl: infoSink.debug << "vertices = " << vertices << "\n"; + + if (inputPrimitive != ElgNone) + infoSink.debug << "input primitive = " << TQualifier::getGeometryString(inputPrimitive) << "\n"; + if (vertexSpacing != EvsNone) + infoSink.debug << "vertex spacing = " << TQualifier::getVertexSpacingString(vertexSpacing) << "\n"; + if (vertexOrder != EvoNone) + infoSink.debug << "triangle order = " << TQualifier::getVertexOrderString(vertexOrder) << "\n"; break; case EShLangTessEvaluation: @@ -827,6 +1426,8 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree) infoSink.debug << "gl_FragCoord origin is upper left\n"; if (earlyFragmentTests) infoSink.debug << "using early_fragment_tests\n"; + if (postDepthCoverage) + infoSink.debug << "using post_depth_coverage\n"; if (depthLayout != EldNone) infoSink.debug << "using " << TQualifier::getLayoutDepthString(depthLayout) << "\n"; if (blendEquations != 0) { @@ -862,7 +1463,8 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree) return; TOutputTraverser it(infoSink); - + if (getBinaryDoubleOutput()) + it.setDoubleOutput(TOutputTraverser::BinaryDoubleOutput); treeRoot->traverse(&it); } diff --git a/Externals/glslang/glslang/MachineIndependent/iomapper.cpp b/Externals/glslang/glslang/MachineIndependent/iomapper.cpp new file mode 100644 index 0000000000..297c123712 --- /dev/null +++ b/Externals/glslang/glslang/MachineIndependent/iomapper.cpp @@ -0,0 +1,798 @@ +// +// Copyright (C) 2016-2017 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. +// + +#include "../Include/Common.h" +#include "../Include/InfoSink.h" +#include "iomapper.h" +#include "LiveTraverser.h" +#include "localintermediate.h" + +#include "gl_types.h" + +#include +#include + +// +// Map IO bindings. +// +// High-level algorithm for one stage: +// +// 1. Traverse all code (live+dead) to find the explicitly provided bindings. +// +// 2. Traverse (just) the live code to determine which non-provided bindings +// require auto-numbering. We do not auto-number dead ones. +// +// 3. Traverse all the code to apply the bindings: +// a. explicitly given bindings are offset according to their type +// b. implicit live bindings are auto-numbered into the holes, using +// any open binding slot. +// c. implicit dead bindings are left un-bound. +// + + +namespace glslang { + +struct TVarEntryInfo +{ + int id; + TIntermSymbol* symbol; + bool live; + int newBinding; + int newSet; + int newLocation; + int newComponent; + int newIndex; + + 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; + } + }; +}; + + + +typedef std::vector TVarLiveMap; + +class TVarGatherTraverser : public TLiveTraverser +{ +public: + TVarGatherTraverser(const TIntermediate& i, bool traverseDeadCode, TVarLiveMap& inList, TVarLiveMap& outList, TVarLiveMap& uniformList) + : TLiveTraverser(i, traverseDeadCode, true, true, false) + , inputList(inList) + , outputList(outList) + , uniformList(uniformList) + { + } + + + virtual void visitSymbol(TIntermSymbol* base) + { + TVarLiveMap* target = nullptr; + if (base->getQualifier().storage == EvqVaryingIn) + target = &inputList; + else if (base->getQualifier().storage == EvqVaryingOut) + target = &outputList; + else if (base->getQualifier().isUniformOrBuffer() && !base->getQualifier().layoutPushConstant) + target = &uniformList; + + if (target) { + TVarEntryInfo ent = { base->getId(), base, !traverseAll }; + TVarLiveMap::iterator at = std::lower_bound(target->begin(), target->end(), ent, TVarEntryInfo::TOrderById()); + if (at != target->end() && at->id == ent.id) + at->live = at->live || !traverseAll; // update live state + else + target->insert(at, ent); + } + } + +private: + TVarLiveMap& inputList; + TVarLiveMap& outputList; + TVarLiveMap& uniformList; +}; + +class TVarSetTraverser : public TLiveTraverser +{ +public: + TVarSetTraverser(const TIntermediate& i, const TVarLiveMap& inList, const TVarLiveMap& outList, const TVarLiveMap& uniformList) + : TLiveTraverser(i, true, true, true, false) + , inputList(inList) + , outputList(outList) + , uniformList(uniformList) + { + } + + + virtual void visitSymbol(TIntermSymbol* base) + { + const TVarLiveMap* source; + if (base->getQualifier().storage == EvqVaryingIn) + source = &inputList; + else if (base->getQualifier().storage == EvqVaryingOut) + source = &outputList; + else if (base->getQualifier().isUniformOrBuffer()) + source = &uniformList; + else + return; + + TVarEntryInfo ent = { base->getId() }; + TVarLiveMap::const_iterator at = std::lower_bound(source->begin(), source->end(), ent, TVarEntryInfo::TOrderById()); + if (at == source->end()) + return; + + if (at->id != ent.id) + return; + + if (at->newBinding != -1) + base->getWritableType().getQualifier().layoutBinding = at->newBinding; + if (at->newSet != -1) + base->getWritableType().getQualifier().layoutSet = at->newSet; + if (at->newLocation != -1) + base->getWritableType().getQualifier().layoutLocation = at->newLocation; + if (at->newComponent != -1) + base->getWritableType().getQualifier().layoutComponent = at->newComponent; + if (at->newIndex != -1) + base->getWritableType().getQualifier().layoutIndex = at->newIndex; + } + + private: + const TVarLiveMap& inputList; + const TVarLiveMap& outputList; + const TVarLiveMap& uniformList; +}; + +struct TNotifyUniformAdaptor +{ + EShLanguage stage; + TIoMapResolver& resolver; + inline TNotifyUniformAdaptor(EShLanguage s, TIoMapResolver& r) + : stage(s) + , resolver(r) + { + } + inline void operator()(TVarEntryInfo& ent) + { + resolver.notifyBinding(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), ent.live); + } +private: + TNotifyUniformAdaptor& operator=(TNotifyUniformAdaptor&); +}; + +struct TNotifyInOutAdaptor +{ + EShLanguage stage; + TIoMapResolver& resolver; + inline TNotifyInOutAdaptor(EShLanguage s, TIoMapResolver& r) + : stage(s) + , resolver(r) + { + } + inline void operator()(TVarEntryInfo& ent) + { + resolver.notifyInOut(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), ent.live); + } +private: + TNotifyInOutAdaptor& operator=(TNotifyInOutAdaptor&); +}; + +struct TResolverUniformAdaptor +{ + TResolverUniformAdaptor(EShLanguage s, TIoMapResolver& r, TInfoSink& i, bool& e, TIntermediate& interm) + : stage(s) + , resolver(r) + , infoSink(i) + , error(e) + , intermediate(interm) + { + } + + inline void operator()(TVarEntryInfo& ent) + { + ent.newLocation = -1; + ent.newComponent = -1; + ent.newBinding = -1; + ent.newSet = -1; + ent.newIndex = -1; + const bool isValid = resolver.validateBinding(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), + ent.live); + if (isValid) { + ent.newBinding = resolver.resolveBinding(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), + ent.live); + ent.newSet = resolver.resolveSet(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), ent.live); + ent.newLocation = resolver.resolveUniformLocation(stage, ent.symbol->getName().c_str(), + ent.symbol->getType(), ent.live); + + if (ent.newBinding != -1) { + if (ent.newBinding >= int(TQualifier::layoutBindingEnd)) { + TString err = "mapped binding out of range: " + ent.symbol->getName(); + + infoSink.info.message(EPrefixInternalError, err.c_str()); + error = true; + } + } + if (ent.newSet != -1) { + if (ent.newSet >= int(TQualifier::layoutSetEnd)) { + TString err = "mapped set out of range: " + ent.symbol->getName(); + + infoSink.info.message(EPrefixInternalError, err.c_str()); + error = true; + } + } + } else { + TString errorMsg = "Invalid binding: " + ent.symbol->getName(); + infoSink.info.message(EPrefixInternalError, errorMsg.c_str()); + error = true; + } + } + + EShLanguage stage; + TIoMapResolver& resolver; + TInfoSink& infoSink; + bool& error; + TIntermediate& intermediate; + +private: + TResolverUniformAdaptor& operator=(TResolverUniformAdaptor&); +}; + +struct TResolverInOutAdaptor +{ + TResolverInOutAdaptor(EShLanguage s, TIoMapResolver& r, TInfoSink& i, bool& e, TIntermediate& interm) + : stage(s) + , resolver(r) + , infoSink(i) + , error(e) + , intermediate(interm) + { + } + + inline void operator()(TVarEntryInfo& ent) + { + ent.newLocation = -1; + ent.newComponent = -1; + ent.newBinding = -1; + ent.newSet = -1; + ent.newIndex = -1; + const bool isValid = resolver.validateInOut(stage, + ent.symbol->getName().c_str(), + ent.symbol->getType(), + ent.live); + if (isValid) { + ent.newLocation = resolver.resolveInOutLocation(stage, + ent.symbol->getName().c_str(), + ent.symbol->getType(), + ent.live); + ent.newComponent = resolver.resolveInOutComponent(stage, + ent.symbol->getName().c_str(), + ent.symbol->getType(), + ent.live); + ent.newIndex = resolver.resolveInOutIndex(stage, + ent.symbol->getName().c_str(), + ent.symbol->getType(), + ent.live); + } else { + TString errorMsg = "Invalid shader In/Out variable semantic: "; + errorMsg += ent.symbol->getType().getQualifier().semanticName; + infoSink.info.message(EPrefixInternalError, errorMsg.c_str()); + error = true; + } + } + + EShLanguage stage; + TIoMapResolver& resolver; + TInfoSink& infoSink; + bool& error; + TIntermediate& intermediate; + +private: + TResolverInOutAdaptor& operator=(TResolverInOutAdaptor&); +}; + +// Base class for shared TIoMapResolver services, used by several derivations. +struct TDefaultIoResolverBase : public glslang::TIoMapResolver +{ + TDefaultIoResolverBase(const TIntermediate &intermediate) : + intermediate(intermediate), + nextUniformLocation(0), + nextInputLocation(0), + nextOutputLocation(0) + { } + + int getBaseBinding(TResourceType res, unsigned int set) const { + return selectBaseBinding(intermediate.getShiftBinding(res), + intermediate.getShiftBindingForSet(res, set)); + } + + const std::vector& getResourceSetBinding() const { return intermediate.getResourceSetBinding(); } + + bool doAutoBindingMapping() const { return intermediate.getAutoMapBindings(); } + bool doAutoLocationMapping() const { return intermediate.getAutoMapLocations(); } + + typedef std::vector TSlotSet; + typedef std::unordered_map TSlotSetMap; + TSlotSetMap slots; + + TSlotSet::iterator findSlot(int set, int slot) + { + return std::lower_bound(slots[set].begin(), slots[set].end(), slot); + } + + bool checkEmpty(int set, int slot) + { + TSlotSet::iterator at = findSlot(set, slot); + return !(at != slots[set].end() && *at == slot); + } + + int reserveSlot(int set, int slot) + { + TSlotSet::iterator at = findSlot(set, slot); + + // tolerate aliasing, by not double-recording aliases + // (policy about appropriateness of the alias is higher up) + if (at == slots[set].end() || *at != slot) + slots[set].insert(at, slot); + + return slot; + } + + int getFreeSlot(int set, int base) + { + TSlotSet::iterator at = findSlot(set, base); + if (at == slots[set].end()) + return reserveSlot(set, base); + + // look in locksteps, if they not match, then there is a free slot + for (; at != slots[set].end(); ++at, ++base) + if (*at != base) + break; + return reserveSlot(set, base); + } + + virtual bool validateBinding(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& type, bool /*is_live*/) override = 0; + + virtual int resolveBinding(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& type, bool is_live) override = 0; + + int resolveSet(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& type, bool /*is_live*/) override + { + if (type.getQualifier().hasSet()) + return type.getQualifier().layoutSet; + + // If a command line or API option requested a single descriptor set, use that (if not overrided by spaceN) + if (getResourceSetBinding().size() == 1) + return atoi(getResourceSetBinding()[0].c_str()); + + return 0; + } + int resolveUniformLocation(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& type, bool /*is_live*/) override + { + // kick out of not doing this + if (!doAutoLocationMapping()) + return -1; + + // no locations added if already present, a built-in variable, a block, or an opaque + if (type.getQualifier().hasLocation() || type.isBuiltIn() || + type.getBasicType() == EbtBlock || + type.getBasicType() == EbtAtomicUint || + (type.containsOpaque() && intermediate.getSpv().openGl == 0)) + return -1; + + // no locations on blocks of built-in variables + if (type.isStruct()) { + if (type.getStruct()->size() < 1) + return -1; + if ((*type.getStruct())[0].type->isBuiltIn()) + return -1; + } + + int location = nextUniformLocation; + + nextUniformLocation += TIntermediate::computeTypeUniformLocationSize(type); + + return location; + } + bool validateInOut(EShLanguage /*stage*/, const char* /*name*/, const TType& /*type*/, bool /*is_live*/) override + { + return true; + } + int resolveInOutLocation(EShLanguage stage, const char* /*name*/, const TType& type, bool /*is_live*/) override + { + // kick out of not doing this + if (!doAutoLocationMapping()) + return -1; + + // no locations added if already present, or a built-in variable + if (type.getQualifier().hasLocation() || type.isBuiltIn()) + return -1; + + // no locations on blocks of built-in variables + if (type.isStruct()) { + if (type.getStruct()->size() < 1) + return -1; + if ((*type.getStruct())[0].type->isBuiltIn()) + return -1; + } + + // point to the right input or output location counter + int& nextLocation = type.getQualifier().isPipeInput() ? nextInputLocation : nextOutputLocation; + + // Placeholder. This does not do proper cross-stage lining up, nor + // work with mixed location/no-location declarations. + int location = nextLocation; + int typeLocationSize; + // Don’t take into account the outer-most array if the stage’s + // interface is automatically an array. + if (type.getQualifier().isArrayedIo(stage)) { + TType elementType(type, 0); + typeLocationSize = TIntermediate::computeTypeLocationSize(elementType, stage); + } else { + typeLocationSize = TIntermediate::computeTypeLocationSize(type, stage); + } + nextLocation += typeLocationSize; + + return location; + } + int resolveInOutComponent(EShLanguage /*stage*/, const char* /*name*/, const TType& /*type*/, bool /*is_live*/) override + { + return -1; + } + int resolveInOutIndex(EShLanguage /*stage*/, const char* /*name*/, const TType& /*type*/, bool /*is_live*/) override + { + return -1; + } + + void notifyBinding(EShLanguage, const char* /*name*/, const TType&, bool /*is_live*/) override {} + void notifyInOut(EShLanguage, const char* /*name*/, const TType&, bool /*is_live*/) override {} + void endNotifications(EShLanguage) override {} + void beginNotifications(EShLanguage) override {} + void beginResolve(EShLanguage) override {} + void endResolve(EShLanguage) override {} + +protected: + const TIntermediate &intermediate; + int nextUniformLocation; + int nextInputLocation; + int nextOutputLocation; + + // Return descriptor set specific base if there is one, and the generic base otherwise. + int selectBaseBinding(int base, int descriptorSetBase) const { + return descriptorSetBase != -1 ? descriptorSetBase : base; + } + + static int getLayoutSet(const glslang::TType& type) { + if (type.getQualifier().hasSet()) + return type.getQualifier().layoutSet; + else + return 0; + } + + static bool isSamplerType(const glslang::TType& type) { + return type.getBasicType() == glslang::EbtSampler && type.getSampler().isPureSampler(); + } + + static bool isTextureType(const glslang::TType& type) { + return (type.getBasicType() == glslang::EbtSampler && + (type.getSampler().isTexture() || type.getSampler().isSubpass())); + } + + static bool isUboType(const glslang::TType& type) { + return type.getQualifier().storage == EvqUniform; + } +}; + +/* + * Basic implementation of glslang::TIoMapResolver that replaces the + * previous offset behavior. + * It does the same, uses the offsets for the corresponding uniform + * types. Also respects the EOptionAutoMapBindings flag and binds + * them if needed. + */ +/* + * Default resolver + */ +struct TDefaultIoResolver : public TDefaultIoResolverBase +{ + TDefaultIoResolver(const TIntermediate &intermediate) : TDefaultIoResolverBase(intermediate) { } + + bool validateBinding(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& /*type*/, bool /*is_live*/) override + { + return true; + } + + int resolveBinding(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& type, bool is_live) override + { + const int set = getLayoutSet(type); + + if (type.getQualifier().hasBinding()) { + if (isImageType(type)) + return reserveSlot(set, getBaseBinding(EResImage, set) + type.getQualifier().layoutBinding); + + if (isTextureType(type)) + return reserveSlot(set, getBaseBinding(EResTexture, set) + type.getQualifier().layoutBinding); + + if (isSsboType(type)) + return reserveSlot(set, getBaseBinding(EResSsbo, set) + type.getQualifier().layoutBinding); + + if (isSamplerType(type)) + return reserveSlot(set, getBaseBinding(EResSampler, set) + type.getQualifier().layoutBinding); + + if (isUboType(type)) + return reserveSlot(set, getBaseBinding(EResUbo, set) + type.getQualifier().layoutBinding); + } else if (is_live && doAutoBindingMapping()) { + // find free slot, the caller did make sure it passes all vars with binding + // first and now all are passed that do not have a binding and needs one + + if (isImageType(type)) + return getFreeSlot(set, getBaseBinding(EResImage, set)); + + if (isTextureType(type)) + return getFreeSlot(set, getBaseBinding(EResTexture, set)); + + if (isSsboType(type)) + return getFreeSlot(set, getBaseBinding(EResSsbo, set)); + + if (isSamplerType(type)) + return getFreeSlot(set, getBaseBinding(EResSampler, set)); + + if (isUboType(type)) + return getFreeSlot(set, getBaseBinding(EResUbo, set)); + } + + return -1; + } + +protected: + static bool isImageType(const glslang::TType& type) { + return type.getBasicType() == glslang::EbtSampler && type.getSampler().isImage(); + } + + static bool isSsboType(const glslang::TType& type) { + return type.getQualifier().storage == EvqBuffer; + } +}; + +/******************************************************************************** +The following IO resolver maps types in HLSL register space, as follows: + +t - for shader resource views (SRV) + TEXTURE1D + TEXTURE1DARRAY + TEXTURE2D + TEXTURE2DARRAY + TEXTURE3D + TEXTURECUBE + TEXTURECUBEARRAY + TEXTURE2DMS + TEXTURE2DMSARRAY + STRUCTUREDBUFFER + BYTEADDRESSBUFFER + BUFFER + TBUFFER + +s - for samplers + SAMPLER + SAMPLER1D + SAMPLER2D + SAMPLER3D + SAMPLERCUBE + SAMPLERSTATE + SAMPLERCOMPARISONSTATE + +u - for unordered access views (UAV) + RWBYTEADDRESSBUFFER + RWSTRUCTUREDBUFFER + APPENDSTRUCTUREDBUFFER + CONSUMESTRUCTUREDBUFFER + RWBUFFER + RWTEXTURE1D + RWTEXTURE1DARRAY + RWTEXTURE2D + RWTEXTURE2DARRAY + RWTEXTURE3D + +b - for constant buffer views (CBV) + CBUFFER + CONSTANTBUFFER + ********************************************************************************/ +struct TDefaultHlslIoResolver : public TDefaultIoResolverBase +{ + TDefaultHlslIoResolver(const TIntermediate &intermediate) : TDefaultIoResolverBase(intermediate) { } + + bool validateBinding(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& /*type*/, bool /*is_live*/) override + { + return true; + } + + int resolveBinding(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& type, bool is_live) override + { + const int set = getLayoutSet(type); + + if (type.getQualifier().hasBinding()) { + if (isUavType(type)) + return reserveSlot(set, getBaseBinding(EResUav, set) + type.getQualifier().layoutBinding); + + if (isSrvType(type)) + return reserveSlot(set, getBaseBinding(EResTexture, set) + type.getQualifier().layoutBinding); + + if (isSamplerType(type)) + return reserveSlot(set, getBaseBinding(EResSampler, set) + type.getQualifier().layoutBinding); + + if (isUboType(type)) + return reserveSlot(set, getBaseBinding(EResUbo, set) + type.getQualifier().layoutBinding); + } else if (is_live && doAutoBindingMapping()) { + // find free slot, the caller did make sure it passes all vars with binding + // first and now all are passed that do not have a binding and needs one + + if (isUavType(type)) + return getFreeSlot(set, getBaseBinding(EResUav, set)); + + if (isSrvType(type)) + return getFreeSlot(set, getBaseBinding(EResTexture, set)); + + if (isSamplerType(type)) + return getFreeSlot(set, getBaseBinding(EResSampler, set)); + + if (isUboType(type)) + return getFreeSlot(set, getBaseBinding(EResUbo, set)); + } + + return -1; + } + +protected: + // 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; + } + + // Return true if this is a UAV (unordered access view) type: + static bool isUavType(const glslang::TType& type) { + if (type.getQualifier().readonly) + return false; + + return (type.getBasicType() == glslang::EbtSampler && type.getSampler().isImage()) || + (type.getQualifier().storage == EvqBuffer); + } +}; + + +// Map I/O variables to provided offsets, and make bindings for +// unbound but live variables. +// +// Returns false if the input is too malformed to do this. +bool TIoMapper::addStage(EShLanguage stage, TIntermediate &intermediate, TInfoSink &infoSink, TIoMapResolver *resolver) +{ + bool somethingToDo = !intermediate.getResourceSetBinding().empty() || + intermediate.getAutoMapBindings() || + intermediate.getAutoMapLocations(); + + for (int res = 0; res < EResCount; ++res) { + somethingToDo = somethingToDo || + (intermediate.getShiftBinding(TResourceType(res)) != 0) || + intermediate.hasShiftBindingForSet(TResourceType(res)); + } + + if (!somethingToDo && resolver == nullptr) + return true; + + if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive()) + return false; + + TIntermNode* root = intermediate.getTreeRoot(); + if (root == nullptr) + return false; + + // if no resolver is provided, use the default resolver with the given shifts and auto map settings + TDefaultIoResolver defaultResolver(intermediate); + TDefaultHlslIoResolver defaultHlslResolver(intermediate); + + if (resolver == nullptr) { + // TODO: use a passed in IO mapper for this + if (intermediate.usingHlslIoMapping()) + resolver = &defaultHlslResolver; + else + resolver = &defaultResolver; + } + + TVarLiveMap inVarMap, outVarMap, uniformVarMap; + TVarGatherTraverser iter_binding_all(intermediate, true, inVarMap, outVarMap, uniformVarMap); + TVarGatherTraverser iter_binding_live(intermediate, false, inVarMap, outVarMap, uniformVarMap); + + root->traverse(&iter_binding_all); + iter_binding_live.pushFunction(intermediate.getEntryPointMangledName().c_str()); + + while (!iter_binding_live.functions.empty()) { + TIntermNode* function = iter_binding_live.functions.back(); + iter_binding_live.functions.pop_back(); + function->traverse(&iter_binding_live); + } + + // sort entries by priority. see TVarEntryInfo::TOrderByPriority for info. + std::sort(uniformVarMap.begin(), uniformVarMap.end(), TVarEntryInfo::TOrderByPriority()); + + bool hadError = false; + TNotifyInOutAdaptor inOutNotify(stage, *resolver); + TNotifyUniformAdaptor uniformNotify(stage, *resolver); + TResolverUniformAdaptor uniformResolve(stage, *resolver, infoSink, hadError, intermediate); + TResolverInOutAdaptor inOutResolve(stage, *resolver, infoSink, hadError, intermediate); + resolver->beginNotifications(stage); + std::for_each(inVarMap.begin(), inVarMap.end(), inOutNotify); + std::for_each(outVarMap.begin(), outVarMap.end(), inOutNotify); + std::for_each(uniformVarMap.begin(), uniformVarMap.end(), uniformNotify); + resolver->endNotifications(stage); + resolver->beginResolve(stage); + std::for_each(inVarMap.begin(), inVarMap.end(), inOutResolve); + std::for_each(outVarMap.begin(), outVarMap.end(), inOutResolve); + std::for_each(uniformVarMap.begin(), uniformVarMap.end(), uniformResolve); + resolver->endResolve(stage); + + if (!hadError) { + // sort by id again, so we can use lower bound to find entries + std::sort(uniformVarMap.begin(), uniformVarMap.end(), TVarEntryInfo::TOrderById()); + TVarSetTraverser iter_iomap(intermediate, inVarMap, outVarMap, uniformVarMap); + root->traverse(&iter_iomap); + } + + return !hadError; +} + +} // end namespace glslang diff --git a/Externals/glslang/glslang/MachineIndependent/iomapper.h b/Externals/glslang/glslang/MachineIndependent/iomapper.h new file mode 100644 index 0000000000..5e0d4391cc --- /dev/null +++ b/Externals/glslang/glslang/MachineIndependent/iomapper.h @@ -0,0 +1,63 @@ +// +// Copyright (C) 2016 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 _IOMAPPER_INCLUDED +#define _IOMAPPER_INCLUDED + +#include "../Public/ShaderLang.h" + +// +// A reflection database and its interface, consistent with the OpenGL API reflection queries. +// + +class TInfoSink; + +namespace glslang { + +class TIntermediate; + +// I/O mapper +class TIoMapper { +public: + TIoMapper() {} + virtual ~TIoMapper() {} + + // grow the reflection stage by stage + bool addStage(EShLanguage, TIntermediate&, TInfoSink&, TIoMapResolver*); +}; + +} // end namespace glslang + +#endif // _IOMAPPER_INCLUDED diff --git a/Externals/glslang/glslang/MachineIndependent/limits.cpp b/Externals/glslang/glslang/MachineIndependent/limits.cpp index 49da930110..64d191b472 100644 --- a/Externals/glslang/glslang/MachineIndependent/limits.cpp +++ b/Externals/glslang/glslang/MachineIndependent/limits.cpp @@ -1,11 +1,11 @@ // -//Copyright (C) 2013 LunarG, Inc. +// Copyright (C) 2013 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,18 +19,18 @@ // 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. +// 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. // // @@ -83,7 +83,7 @@ protected: // check binary operations for those modifying the loop index bool TInductiveTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node) { - if (node->modifiesState() && node->getLeft()->getAsSymbolNode() && + if (node->modifiesState() && node->getLeft()->getAsSymbolNode() && node->getLeft()->getAsSymbolNode()->getId() == loopId) { bad = true; badLoc = node->getLoc(); @@ -95,7 +95,7 @@ bool TInductiveTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node) // check unary operations for those modifying the loop index bool TInductiveTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node) { - if (node->modifiesState() && node->getOperand()->getAsSymbolNode() && + if (node->modifiesState() && node->getOperand()->getAsSymbolNode() && node->getOperand()->getAsSymbolNode()->getId() == loopId) { bad = true; badLoc = node->getLoc(); @@ -145,7 +145,7 @@ void TParseContext::inductiveLoopBodyCheck(TIntermNode* body, int loopId, TSymbo // // The "constant-index-expression" tranverser. // -// Just look at things that can form an index. +// Just look at things that can form an index. // class TIndexTraverser : public TIntermTraverser { diff --git a/Externals/glslang/glslang/MachineIndependent/linkValidate.cpp b/Externals/glslang/glslang/MachineIndependent/linkValidate.cpp index 1cda57d36e..c540ae6477 100644 --- a/Externals/glslang/glslang/MachineIndependent/linkValidate.cpp +++ b/Externals/glslang/glslang/MachineIndependent/linkValidate.cpp @@ -1,11 +1,12 @@ // -//Copyright (C) 2013 LunarG, Inc. +// Copyright (C) 2013 LunarG, Inc. +// Copyright (C) 2017 ARM Limited. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,18 +20,18 @@ // 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. +// 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. // // @@ -48,7 +49,7 @@ #include "../Include/InfoSink.h" namespace glslang { - + // // Link-time error emitter. // @@ -60,8 +61,15 @@ void TIntermediate::error(TInfoSink& infoSink, const char* message) ++numErrors; } -// TODO: 4.4 offset/align: "Two blocks linked together in the same program with the same block -// name must have the exact same set of members qualified with offset and their integral-constant +// Link-time warning. +void TIntermediate::warn(TInfoSink& infoSink, const char* message) +{ + infoSink.info.prefix(EPrefixWarning); + infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n"; +} + +// TODO: 4.4 offset/align: "Two blocks linked together in the same program with the same block +// name must have the exact same set of members qualified with offset and their integral-constant // expression values must be the same, or a link-time error results." // @@ -75,23 +83,28 @@ void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit) if (source != unit.source) error(infoSink, "can't link compilation units from different source languages"); - if (source == EShSourceHlsl && unit.entryPoint.size() > 0) { - if (entryPoint.size() > 0) + if (unit.getNumEntryPoints() > 0) { + if (getNumEntryPoints() > 0) error(infoSink, "can't handle multiple entry points per stage"); - else - entryPoint = unit.entryPoint; + else { + entryPointName = unit.getEntryPointName(); + entryPointMangledName = unit.getEntryPointMangledName(); + } } - numMains += unit.numMains; - numErrors += unit.numErrors; + numEntryPoints += unit.getNumEntryPoints(); + numErrors += unit.getNumErrors(); numPushConstants += unit.numPushConstants; callGraph.insert(callGraph.end(), unit.callGraph.begin(), unit.callGraph.end()); if (originUpperLeft != unit.originUpperLeft || pixelCenterInteger != unit.pixelCenterInteger) - error(infoSink, "gl_FragCoord redeclarations must match across shaders\n"); + error(infoSink, "gl_FragCoord redeclarations must match across shaders"); if (! earlyFragmentTests) earlyFragmentTests = unit.earlyFragmentTests; + if (!postDepthCoverage) + postDepthCoverage = unit.postDepthCoverage; + if (depthLayout == EldNone) depthLayout = unit.depthLayout; else if (depthLayout != unit.depthLayout) @@ -103,12 +116,12 @@ void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit) inputPrimitive = unit.inputPrimitive; else if (inputPrimitive != unit.inputPrimitive) error(infoSink, "Contradictory input layout primitives"); - + if (outputPrimitive == ElgNone) outputPrimitive = unit.outputPrimitive; else if (outputPrimitive != unit.outputPrimitive) error(infoSink, "Contradictory output layout primitives"); - + if (vertices == TQualifier::layoutNotSet) vertices = unit.vertices; else if (vertices != unit.vertices) { @@ -169,7 +182,7 @@ void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit) } // Getting this far means we have two existing trees to merge... - + version = std::max(version, unit.version); requestedExtensions.insert(unit.requestedExtensions.begin(), unit.requestedExtensions.end()); @@ -255,10 +268,13 @@ void TIntermediate::mergeLinkerObjects(TInfoSink& infoSink, TIntermSequence& lin // Recursively merge the implicit array sizes through the objects' respective type trees. void TIntermediate::mergeImplicitArraySizes(TType& type, const TType& unitType) { - if (type.isImplicitlySizedArray() && unitType.isArray()) { - int newImplicitArraySize = unitType.isImplicitlySizedArray() ? unitType.getImplicitArraySize() : unitType.getOuterArraySize(); - if (newImplicitArraySize > type.getImplicitArraySize ()) - type.setImplicitArraySize(newImplicitArraySize); + if (type.isUnsizedArray()) { + if (unitType.isUnsizedArray()) { + type.updateImplicitArraySize(unitType.getImplicitArraySize()); + if (unitType.isArrayVariablyIndexed()) + type.setArrayVariablyIndexed(); + } else if (unitType.isSizedArray()) + type.changeOuterArraySize(unitType.getOuterArraySize()); } // Type mismatches are caught and reported after this, just be careful for now. @@ -281,8 +297,13 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy // Types have to match if (symbol.getType() != unitSymbol.getType()) { - error(infoSink, "Types must match:"); - writeTypeComparison = true; + // but, we make an exception if one is an implicit array and the other is sized + if (! (symbol.getType().isArray() && unitSymbol.getType().isArray() && + symbol.getType().sameElementType(unitSymbol.getType()) && + (symbol.getType().isUnsizedArray() || unitSymbol.getType().isUnsizedArray()))) { + error(infoSink, "Types must match:"); + writeTypeComparison = true; + } } // Qualifiers have to (almost) match @@ -332,9 +353,9 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy writeTypeComparison = true; } - // Layouts... - // TODO: 4.4 enhanced layouts: Generalize to include offset/align: current spec - // requires separate user-supplied offset from actual computed offset, but + // Layouts... + // TODO: 4.4 enhanced layouts: Generalize to include offset/align: current spec + // requires separate user-supplied offset from actual computed offset, but // current implementation only has one offset. if (symbol.getQualifier().layoutMatrix != unitSymbol.getQualifier().layoutMatrix || symbol.getQualifier().layoutPacking != unitSymbol.getQualifier().layoutPacking || @@ -368,16 +389,24 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy // // Also, lock in defaults of things not set, including array sizes. // -void TIntermediate::finalCheck(TInfoSink& infoSink) +void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled) { - if (source == EShSourceGlsl && numMains < 1) - error(infoSink, "Missing entry point: Each stage requires one \"void main()\" entry point"); + if (getTreeRoot() == nullptr) + return; + + if (numEntryPoints < 1) { + if (source == EShSourceGlsl) + error(infoSink, "Missing entry point: Each stage requires one entry point"); + else + warn(infoSink, "Entry point not found"); + } if (numPushConstants > 1) error(infoSink, "Only one push_constant block is allowed per stage"); - // recursion checking + // recursion and missing body checking checkCallGraphCycles(infoSink); + checkCallGraphBodies(infoSink, keepUncalled); // overlap/alias/missing I/O, etc. inOutLocationCheck(infoSink); @@ -400,7 +429,7 @@ void TIntermediate::finalCheck(TInfoSink& infoSink) if (xfbBuffers[b].containsDouble) RoundToPow2(xfbBuffers[b].implicitStride, 8); - // "It is a compile-time or link-time error to have + // "It is a compile-time or link-time error to have // any xfb_offset that overflows xfb_stride, whether stated on declarations before or after the xfb_stride, or // in different compilation units. While xfb_stride can be declared multiple times for the same buffer, it is a // compile-time or link-time error to have different values specified for the stride for the same buffer." @@ -412,8 +441,8 @@ void TIntermediate::finalCheck(TInfoSink& infoSink) if (xfbBuffers[b].stride == TQualifier::layoutXfbStrideEnd) xfbBuffers[b].stride = xfbBuffers[b].implicitStride; - // "If the buffer is capturing any - // outputs with double-precision components, the stride must be a multiple of 8, otherwise it must be a + // "If the buffer is capturing any + // outputs with double-precision components, the stride must be a multiple of 8, otherwise it must be a // multiple of 4, or a compile-time or link-time error results." if (xfbBuffers[b].containsDouble && ! IsMultipleOfPow2(xfbBuffers[b].stride, 8)) { error(infoSink, "xfb_stride must be multiple of 8 for buffer holding a double:"); @@ -425,7 +454,7 @@ void TIntermediate::finalCheck(TInfoSink& infoSink) infoSink.info << " xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n"; } - // "The resulting stride (implicit or explicit), when divided by 4, must be less than or equal to the + // "The resulting stride (implicit or explicit), when divided by 4, must be less than or equal to the // implementation-dependent constant gl_MaxTransformFeedbackInterleavedComponents." if (xfbBuffers[b].stride > (unsigned int)(4 * resources.maxTransformFeedbackInterleavedComponents)) { error(infoSink, "xfb_stride is too large:"); @@ -442,22 +471,37 @@ void TIntermediate::finalCheck(TInfoSink& infoSink) error(infoSink, "At least one shader must specify an output layout(vertices=...)"); break; case EShLangTessEvaluation: - if (inputPrimitive == ElgNone) - error(infoSink, "At least one shader must specify an input layout primitive"); - if (vertexSpacing == EvsNone) - vertexSpacing = EvsEqual; - if (vertexOrder == EvoNone) - vertexOrder = EvoCcw; + if (source == EShSourceGlsl) { + if (inputPrimitive == ElgNone) + error(infoSink, "At least one shader must specify an input layout primitive"); + if (vertexSpacing == EvsNone) + vertexSpacing = EvsEqual; + if (vertexOrder == EvoNone) + vertexOrder = EvoCcw; + } break; case EShLangGeometry: if (inputPrimitive == ElgNone) error(infoSink, "At least one shader must specify an input layout primitive"); - if (outputPrimitive == ElgNone) + if (outputPrimitive == ElgNone +#ifdef NV_EXTENSIONS + && !getGeoPassthroughEXT() +#endif + ) error(infoSink, "At least one shader must specify an output layout primitive"); - if (vertices == TQualifier::layoutNotSet) + if (vertices == TQualifier::layoutNotSet +#ifdef NV_EXTENSIONS + && !getGeoPassthroughEXT() +#endif + ) error(infoSink, "At least one shader must specify a layout(max_vertices = value)"); break; case EShLangFragment: + // for GL_ARB_post_depth_coverage, EarlyFragmentTest is set automatically in + // ParseHelper.cpp. So if we reach here, this must be GL_EXT_post_depth_coverage + // requiring explicit early_fragment_tests + if (getPostDepthCoverage() && !getEarlyFragmentTests()) + error(infoSink, "post_depth_coverage requires early_fragment_tests"); break; case EShLangCompute: break; @@ -475,7 +519,9 @@ void TIntermediate::finalCheck(TInfoSink& infoSink) virtual void visitSymbol(TIntermSymbol* symbol) { // Implicitly size arrays. - symbol->getWritableType().adoptImplicitArraySizes(); + // If an unsized array is left as unsized, it effectively + // becomes run-time sized. + symbol->getWritableType().adoptImplicitArraySizes(false); } } finalLinkTraverser; @@ -488,7 +534,7 @@ void TIntermediate::finalCheck(TInfoSink& infoSink) // void TIntermediate::checkCallGraphCycles(TInfoSink& infoSink) { - // Reset everything, once. + // Clear fields we'll use for this. for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) { call->visited = false; call->currentPath = false; @@ -515,7 +561,7 @@ void TIntermediate::checkCallGraphCycles(TInfoSink& infoSink) break; // Otherwise, we found a new subgraph, process it: - // See what all can be reached by this new root, and if any of + // See what all can be reached by this new root, and if any of // that is recursive. This is done by depth-first traversals, seeing // if a new call is found that was already in the currentPath (a back edge), // thereby detecting recursion. @@ -563,6 +609,85 @@ void TIntermediate::checkCallGraphCycles(TInfoSink& infoSink) } while (newRoot); // redundant loop check; should always exit via the 'break' above } +// +// See which functions are reachable from the entry point and which have bodies. +// Reachable ones with missing bodies are errors. +// Unreachable bodies are dead code. +// +void TIntermediate::checkCallGraphBodies(TInfoSink& infoSink, bool keepUncalled) +{ + // Clear fields we'll use for this. + for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) { + call->visited = false; + call->calleeBodyPosition = -1; + } + + // The top level of the AST includes function definitions (bodies). + // Compare these to function calls in the call graph. + // We'll end up knowing which have bodies, and if so, + // how to map the call-graph node to the location in the AST. + TIntermSequence &functionSequence = getTreeRoot()->getAsAggregate()->getSequence(); + std::vector reachable(functionSequence.size(), true); // so that non-functions are reachable + for (int f = 0; f < (int)functionSequence.size(); ++f) { + glslang::TIntermAggregate* node = functionSequence[f]->getAsAggregate(); + if (node && (node->getOp() == glslang::EOpFunction)) { + if (node->getName().compare(getEntryPointMangledName().c_str()) != 0) + reachable[f] = false; // so that function bodies are unreachable, until proven otherwise + for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) { + if (call->callee == node->getName()) + call->calleeBodyPosition = f; + } + } + } + + // Start call-graph traversal by visiting the entry point nodes. + for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) { + if (call->caller.compare(getEntryPointMangledName().c_str()) == 0) + call->visited = true; + } + + // Propagate 'visited' through the call-graph to every part of the graph it + // can reach (seeded with the entry-point setting above). + bool changed; + do { + changed = false; + for (auto call1 = callGraph.begin(); call1 != callGraph.end(); ++call1) { + if (call1->visited) { + for (TGraph::iterator call2 = callGraph.begin(); call2 != callGraph.end(); ++call2) { + if (! call2->visited) { + if (call1->callee == call2->caller) { + changed = true; + call2->visited = true; + } + } + } + } + } + } while (changed); + + // Any call-graph node set to visited but without a callee body is an error. + for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) { + if (call->visited) { + if (call->calleeBodyPosition == -1) { + error(infoSink, "No function definition (body) found: "); + infoSink.info << " " << call->callee << "\n"; + } else + reachable[call->calleeBodyPosition] = true; + } + } + + // Bodies in the AST not reached by the call graph are dead; + // clear them out, since they can't be reached and also can't + // be translated further due to possibility of being ill defined. + if (! keepUncalled) { + for (int f = 0; f < (int)functionSequence.size(); ++f) { + if (! reachable[f]) + functionSequence[f] = nullptr; + } + functionSequence.erase(std::remove(functionSequence.begin(), functionSequence.end(), nullptr), functionSequence.end()); + } +} + // // Satisfy rules for location qualifiers on inputs and outputs // @@ -605,7 +730,7 @@ TIntermSequence& TIntermediate::findLinkerObjects() const } // See if a variable was both a user-declared output and used. -// Note: the spec discusses writing to one, but this looks at read or write, which +// Note: the spec discusses writing to one, but this looks at read or write, which // is more useful, and perhaps the spec should be changed to reflect that. bool TIntermediate::userOutputUsed() const { @@ -616,7 +741,7 @@ bool TIntermediate::userOutputUsed() const const TIntermSymbol& symbolNode = *linkerObjects[i]->getAsSymbolNode(); if (symbolNode.getQualifier().storage == EvqVaryingOut && symbolNode.getName().compare(0, 3, "gl_") != 0 && - inIoAccessed(symbolNode.getName())) { + inIoAccessed(symbolNode.getName())) { found = true; break; } @@ -651,7 +776,7 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ int size; if (qualifier.isUniformOrBuffer()) { - if (type.isArray()) + if (type.isSizedArray()) size = type.getCumulativeArraySize(); else size = 1; @@ -659,39 +784,102 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ // Strip off the outer array dimension for those having an extra one. if (type.isArray() && qualifier.isArrayedIo(language)) { TType elementType(type, 0); - size = computeTypeLocationSize(elementType); + size = computeTypeLocationSize(elementType, language); } else - size = computeTypeLocationSize(type); + size = computeTypeLocationSize(type, language); } - TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation + size - 1); - TRange componentRange(0, 3); - if (qualifier.hasComponent()) { - componentRange.start = qualifier.layoutComponent; - componentRange.last = componentRange.start + type.getVectorSize() - 1; - } - TIoRange range(locationRange, componentRange, type.getBasicType(), qualifier.hasIndex() ? qualifier.layoutIndex : 0); + // Locations, and components within locations. + // + // Almost always, dealing with components means a single location is involved. + // The exception is a dvec3. From the spec: + // + // "A dvec3 will consume all four components of the first location and components 0 and 1 of + // the second location. This leaves components 2 and 3 available for other component-qualified + // declarations." + // + // That means, without ever mentioning a component, a component range + // for a different location gets specified, if it's not a vertex shader input. (!) + // (A vertex shader input will show using only one location, even for a dvec3/4.) + // + // So, for the case of dvec3, we need two independent ioRanges. - // check for collisions, except for vertex inputs on desktop - if (! (profile != EEsProfile && language == EShLangVertex && qualifier.isPipeInput())) { - for (size_t r = 0; r < usedIo[set].size(); ++r) { - if (range.overlap(usedIo[set][r])) { - // there is a collision; pick one - return std::max(locationRange.start, usedIo[set][r].location.start); - } else if (locationRange.overlap(usedIo[set][r].location) && type.getBasicType() != usedIo[set][r].basicType) { - // aliased-type mismatch - typeCollision = true; - return std::max(locationRange.start, usedIo[set][r].location.start); - } + int collision = -1; // no collision + if (size == 2 && type.getBasicType() == EbtDouble && type.getVectorSize() == 3 && + (qualifier.isPipeInput() || qualifier.isPipeOutput())) { + // Dealing with dvec3 in/out split across two locations. + // Need two io-ranges. + // The case where the dvec3 doesn't start at component 0 was previously caught as overflow. + + // First range: + TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation); + TRange componentRange(0, 3); + TIoRange range(locationRange, componentRange, type.getBasicType(), 0); + + // check for collisions + collision = checkLocationRange(set, range, type, typeCollision); + if (collision < 0) { + usedIo[set].push_back(range); + + // Second range: + TRange locationRange2(qualifier.layoutLocation + 1, qualifier.layoutLocation + 1); + TRange componentRange2(0, 1); + TIoRange range2(locationRange2, componentRange2, type.getBasicType(), 0); + + // check for collisions + collision = checkLocationRange(set, range2, type, typeCollision); + if (collision < 0) + usedIo[set].push_back(range2); + } + } else { + // Not a dvec3 in/out split across two locations, generic path. + // Need a single IO-range block. + + TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation + size - 1); + TRange componentRange(0, 3); + if (qualifier.hasComponent() || type.getVectorSize() > 0) { + int consumedComponents = type.getVectorSize() * (type.getBasicType() == EbtDouble ? 2 : 1); + if (qualifier.hasComponent()) + componentRange.start = qualifier.layoutComponent; + componentRange.last = componentRange.start + consumedComponents - 1; + } + + // combine location and component ranges + TIoRange range(locationRange, componentRange, type.getBasicType(), qualifier.hasIndex() ? qualifier.layoutIndex : 0); + + // check for collisions, except for vertex inputs on desktop targeting OpenGL + if (! (profile != EEsProfile && language == EShLangVertex && qualifier.isPipeInput()) || spvVersion.vulkan > 0) + collision = checkLocationRange(set, range, type, typeCollision); + + if (collision < 0) + usedIo[set].push_back(range); + } + + return collision; +} + +// Compare a new (the passed in) 'range' against the existing set, and see +// if there are any collisions. +// +// Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value. +// +int TIntermediate::checkLocationRange(int set, const TIoRange& range, const TType& type, bool& typeCollision) +{ + for (size_t r = 0; r < usedIo[set].size(); ++r) { + if (range.overlap(usedIo[set][r])) { + // 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) { + // aliased-type mismatch + typeCollision = true; + return std::max(range.location.start, usedIo[set][r].location.start); } } - usedIo[set].push_back(range); - return -1; // no collision } -// Accumulate locations used for inputs, outputs, and uniforms, and check for collisions +// Accumulate bindings and offsets, and check for collisions // as the accumulation is done. // // Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value. @@ -730,41 +918,41 @@ bool TIntermediate::addUsedConstantId(int id) // Recursively figure out how many locations are used up by an input or output type. // Return the size of type, as measured by "locations". -int TIntermediate::computeTypeLocationSize(const TType& type) const +int TIntermediate::computeTypeLocationSize(const TType& type, EShLanguage stage) { - // "If the declared input is an array of size n and each element takes m locations, it will be assigned m * n + // "If the declared input is an array of size n and each element takes m locations, it will be assigned m * n // consecutive locations..." if (type.isArray()) { // TODO: perf: this can be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness + // TODO: are there valid cases of having an unsized array with a location? If so, running this code too early. TType elementType(type, 0); - if (type.isImplicitlySizedArray()) { - // TODO: are there valid cases of having an implicitly-sized array with a location? If so, running this code too early. - return computeTypeLocationSize(elementType); - } else - return type.getOuterArraySize() * computeTypeLocationSize(elementType); + if (type.isSizedArray()) + return type.getOuterArraySize() * computeTypeLocationSize(elementType, stage); + else + return computeTypeLocationSize(elementType, stage); } - // "The locations consumed by block and structure members are determined by applying the rules above - // recursively..." + // "The locations consumed by block and structure members are determined by applying the rules above + // recursively..." if (type.isStruct()) { int size = 0; for (int member = 0; member < (int)type.getStruct()->size(); ++member) { TType memberType(type, member); - size += computeTypeLocationSize(memberType); + size += computeTypeLocationSize(memberType, stage); } return size; } // ES: "If a shader input is any scalar or vector type, it will consume a single location." - // Desktop: "If a vertex shader input is any scalar or vector type, it will consume a single location. If a non-vertex - // shader input is a scalar or vector type other than dvec3 or dvec4, it will consume a single location, while - // types dvec3 or dvec4 will consume two consecutive locations. Inputs of type double and dvec2 will + // Desktop: "If a vertex shader input is any scalar or vector type, it will consume a single location. If a non-vertex + // shader input is a scalar or vector type other than dvec3 or dvec4, it will consume a single location, while + // types dvec3 or dvec4 will consume two consecutive locations. Inputs of type double and dvec2 will // consume only a single location, in all stages." if (type.isScalar()) return 1; if (type.isVector()) { - if (language == EShLangVertex && type.getQualifier().isPipeInput()) + if (stage == EShLangVertex && type.getQualifier().isPipeInput()) return 1; if (type.getBasicType() == EbtDouble && type.getVectorSize() > 2) return 2; @@ -773,17 +961,48 @@ int TIntermediate::computeTypeLocationSize(const TType& type) const } // "If the declared input is an n x m single- or double-precision matrix, ... - // The number of locations assigned for each matrix will be the same as + // The number of locations assigned for each matrix will be the same as // for an n-element array of m-component vectors..." if (type.isMatrix()) { TType columnType(type, 0); - return type.getMatrixCols() * computeTypeLocationSize(columnType); + return type.getMatrixCols() * computeTypeLocationSize(columnType, stage); } assert(0); return 1; } +// Same as computeTypeLocationSize but for uniforms +int TIntermediate::computeTypeUniformLocationSize(const TType& type) +{ + // "Individual elements of a uniform array are assigned + // consecutive locations with the first element taking location + // location." + if (type.isArray()) { + // TODO: perf: this can be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness + TType elementType(type, 0); + if (type.isSizedArray()) { + return type.getOuterArraySize() * computeTypeUniformLocationSize(elementType); + } else { + // TODO: are there valid cases of having an implicitly-sized array with a location? If so, running this code too early. + return computeTypeUniformLocationSize(elementType); + } + } + + // "Each subsequent inner-most member or element gets incremental + // locations for the entire structure or array." + if (type.isStruct()) { + int size = 0; + for (int member = 0; member < (int)type.getStruct()->size(); ++member) { + TType memberType(type, member); + size += computeTypeUniformLocationSize(memberType); + } + return size; + } + + return 1; +} + // Accumulate xfb buffer ranges and check for collisions as the accumulation is done. // // Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value. @@ -819,16 +1038,16 @@ int TIntermediate::addXfbBufferOffset(const TType& type) // N.B. Caller must set containsDouble to false before calling. unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& containsDouble) const { - // "...if applied to an aggregate containing a double, the offset must also be a multiple of 8, + // "...if applied to an aggregate containing a double, the offset must also be a multiple of 8, // and the space taken in the buffer will be a multiple of 8. - // ...within the qualified entity, subsequent components are each + // ...within the qualified entity, subsequent components are each // assigned, in order, to the next available offset aligned to a multiple of // that component's size. Aggregate types are flattened down to the component // level to get this sequence of components." - if (type.isArray()) { + if (type.isArray()) { // TODO: perf: this can be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness - assert(type.isExplicitlySizedArray()); + assert(type.isSizedArray()); TType elementType(type, 0); return type.getOuterArraySize() * computeTypeXfbSize(elementType, containsDouble); } @@ -838,8 +1057,8 @@ unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains bool structContainsDouble = false; for (int member = 0; member < (int)type.getStruct()->size(); ++member) { TType memberType(type, member); - // "... if applied to - // an aggregate containing a double, the offset must also be a multiple of 8, + // "... if applied to + // an aggregate containing a double, the offset must also be a multiple of 8, // and the space taken in the buffer will be a multiple of 8." bool memberContainsDouble = false; int memberSize = computeTypeXfbSize(memberType, memberContainsDouble); @@ -878,15 +1097,20 @@ unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains const int baseAlignmentVec4Std140 = 16; -// Return the size and alignment of a scalar. +// Return the size and alignment of a component of the given type. // The size is returned in the 'size' parameter -// Return value is the alignment of the type. +// Return value is the alignment.. int TIntermediate::getBaseAlignmentScalar(const TType& type, int& size) { switch (type.getBasicType()) { case EbtInt64: case EbtUint64: case EbtDouble: size = 8; return 8; + case EbtFloat16: size = 2; return 2; + case EbtInt8: + case EbtUint8: size = 1; return 1; + case EbtInt16: + case EbtUint16: size = 2; return 2; default: size = 4; return 4; } } @@ -894,7 +1118,7 @@ int TIntermediate::getBaseAlignmentScalar(const TType& type, int& size) // Implement base-alignment and size rules from section 7.6.2.2 Standard Uniform Block Layout // Operates recursively. // -// If std140 is true, it does the rounding up to vec4 size required by std140, +// If std140 is true, it does the rounding up to vec4 size required by std140, // otherwise it does not, yielding std430 rules. // // The size is returned in the 'size' parameter @@ -923,7 +1147,7 @@ int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, b // // 1. If the member is a scalar consuming N basic machine units, the base alignment is N. // - // 2. If the member is a two- or four-component vector with components consuming N basic + // 2. If the member is a two- or four-component vector with components consuming N basic // machine units, the base alignment is 2N or 4N, respectively. // // 3. If the member is a three-component vector with components consuming N @@ -936,11 +1160,11 @@ int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, b // the array is rounded up to the next multiple of the base alignment. // // 5. If the member is a column-major matrix with C columns and R rows, the - // matrix is stored identically to an array of C column vectors with R + // matrix is stored identically to an array of C column vectors with R // components each, according to rule (4). // // 6. If the member is an array of S column-major matrices with C columns and - // R rows, the matrix is stored identically to a row of S  C column vectors + // R rows, the matrix is stored identically to a row of S X C column vectors // with R components each, according to rule (4). // // 7. If the member is a row-major matrix with C columns and R rows, the matrix @@ -948,12 +1172,12 @@ int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, b // according to rule (4). // // 8. If the member is an array of S row-major matrices with C columns and R - // rows, the matrix is stored identically to a row of S  R row vectors with C + // rows, the matrix is stored identically to a row of S X R row vectors with C // components each, according to rule (4). // // 9. If the member is a structure, the base alignment of the structure is N , where // N is the largest base alignment value of any of its members, and rounded - // up to the base alignment of a vec4. The individual members of this substructure + // up to the base alignment of a vec4. The individual members of this substructure // are then assigned offsets by applying this set of rules recursively, // where the base offset of the first member of the sub-structure is equal to the // aligned offset of the structure. The structure may have padding at the end; @@ -995,7 +1219,7 @@ int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, b int memberAlignment = getBaseAlignment(*memberList[m].type, memberSize, dummyStride, std140, (subMatrixLayout != ElmNone) ? (subMatrixLayout == ElmRowMajor) : rowMajor); maxAlignment = std::max(maxAlignment, memberAlignment); - RoundToPow2(size, memberAlignment); + RoundToPow2(size, memberAlignment); size += memberSize; } @@ -1015,10 +1239,12 @@ int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, b if (type.isVector()) { int scalarAlign = getBaseAlignmentScalar(type, size); switch (type.getVectorSize()) { + case 1: // HLSL has this, GLSL does not + return scalarAlign; case 2: size *= 2; return 2 * scalarAlign; - default: + default: size *= type.getVectorSize(); return 4 * scalarAlign; } @@ -1028,7 +1254,7 @@ int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, b if (type.isMatrix()) { // rule 5: deref to row, not to column, meaning the size of vector is num columns instead of num rows TType derefType(type, 0, rowMajor); - + alignment = getBaseAlignment(derefType, size, dummyStride, std140, rowMajor); if (std140) alignment = std::max(baseAlignmentVec4Std140, alignment); @@ -1047,4 +1273,14 @@ int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, b return baseAlignmentVec4Std140; } +// To aid the basic HLSL rule about crossing vec4 boundaries. +bool TIntermediate::improperStraddle(const TType& type, int size, int offset) +{ + if (! type.isVector() || type.isArray()) + return false; + + return size <= 16 ? offset / 16 != (offset + size - 1) / 16 + : offset % 16 != 0; +} + } // end namespace glslang diff --git a/Externals/glslang/glslang/MachineIndependent/localintermediate.h b/Externals/glslang/glslang/MachineIndependent/localintermediate.h old mode 100644 new mode 100755 index d855e7236b..f3a0e413e2 --- a/Externals/glslang/glslang/MachineIndependent/localintermediate.h +++ b/Externals/glslang/glslang/MachineIndependent/localintermediate.h @@ -1,10 +1,12 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2016 LunarG, Inc. +// Copyright (C) 2017 ARM Limited. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -18,18 +20,18 @@ // 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. +// 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 _LOCAL_INTERMEDIATE_INCLUDED_ @@ -41,14 +43,46 @@ #include #include +#include class TInfoSink; namespace glslang { -struct TVectorFields { - int offsets[4]; - int num; +struct TMatrixSelector { + int coord1; // stay agnostic about column/row; this is parse order + int coord2; +}; + +typedef int TVectorSelector; + +const int MaxSwizzleSelectors = 4; + +template +class TSwizzleSelectors { +public: + TSwizzleSelectors() : size_(0) { } + + void push_back(selectorType comp) + { + if (size_ < MaxSwizzleSelectors) + components[size_++] = comp; + } + void resize(int s) + { + assert(s <= size_); + size_ = s; + } + int size() const { return size_; } + selectorType operator[](int i) const + { + assert(i < MaxSwizzleSelectors); + return components[i]; + } + +private: + int size_; + selectorType components[MaxSwizzleSelectors]; }; // @@ -56,7 +90,9 @@ struct TVectorFields { // by TIntermediate. // -// Used for detecting recursion: A "call" is a pair: . +// Used for call-graph algorithms for detecting recursion, missing bodies, and dead bodies. +// A "call" is a pair: . +// There can be duplicates. General assumption is the list is small. struct TCall { TCall(const TString& pCaller, const TString& pCallee) : caller(pCaller), callee(pCallee) { } TString caller; @@ -64,12 +100,13 @@ struct TCall { bool visited; bool currentPath; bool errorGiven; + int calleeBodyPosition; }; // A generic 1-D range. struct TRange { TRange(int start, int last) : start(start), last(last) { } - bool overlap(const TRange& rhs) const + bool overlap(const TRange& rhs) const { return last >= rhs.start && start <= rhs.last; } @@ -115,6 +152,54 @@ struct TXfbBuffer { bool containsDouble; }; +// Track a set of strings describing how the module was processed. +// Using the form: +// process arg0 arg1 arg2 ... +// process arg0 arg1 arg2 ... +// where everything is textual, and there can be zero or more arguments +class TProcesses { +public: + TProcesses() {} + ~TProcesses() {} + + void addProcess(const char* process) + { + processes.push_back(process); + } + void addProcess(const std::string& process) + { + processes.push_back(process); + } + void addArgument(int arg) + { + processes.back().append(" "); + std::string argString = std::to_string(arg); + processes.back().append(argString); + } + void addArgument(const char* arg) + { + processes.back().append(" "); + processes.back().append(arg); + } + void addArgument(const std::string& arg) + { + processes.back().append(" "); + processes.back().append(arg); + } + void addIfNonZero(const char* process, int value) + { + if (value != 0) { + addProcess(process); + addArgument(value); + } + } + + const std::vector& getProcesses() const { return processes; } + +private: + std::vector processes; +}; + class TSymbolTable; class TSymbol; class TVariable; @@ -125,12 +210,31 @@ class TVariable; class TIntermediate { public: explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) : - source(EShSourceNone), language(l), profile(p), version(v), treeRoot(0), - numMains(0), numErrors(0), numPushConstants(0), recursive(false), - invocations(TQualifier::layoutNotSet), vertices(TQualifier::layoutNotSet), inputPrimitive(ElgNone), outputPrimitive(ElgNone), + implicitThisName("@this"), implicitCounterName("@count"), + language(l), source(EShSourceNone), profile(p), version(v), treeRoot(0), + numEntryPoints(0), numErrors(0), numPushConstants(0), recursive(false), + invocations(TQualifier::layoutNotSet), vertices(TQualifier::layoutNotSet), + inputPrimitive(ElgNone), outputPrimitive(ElgNone), pixelCenterInteger(false), originUpperLeft(false), - vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false), depthLayout(EldNone), depthReplacing(false), blendEquations(0), - multiStream(false), xfbMode(false) + vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false), + postDepthCoverage(false), depthLayout(EldNone), depthReplacing(false), + hlslFunctionality1(false), + blendEquations(0), xfbMode(false), multiStream(false), +#ifdef NV_EXTENSIONS + layoutOverrideCoverage(false), + geoPassthroughEXT(false), +#endif + autoMapBindings(false), + autoMapLocations(false), + invertY(false), + flattenUniformArrays(false), + useUnknownFormat(false), + hlslOffsets(false), + useStorageBuffer(false), + hlslIoMapping(false), + textureSamplerTransformMode(EShTexSampTransKeep), + needToLegalize(false), + binaryDoubleOutput(false) { localSize[0] = 1; localSize[1] = 1; @@ -139,6 +243,8 @@ public: localSizeSpecId[1] = TQualifier::layoutNotSet; localSizeSpecId[2] = TQualifier::layoutNotSet; xfbBuffers.resize(TQualifier::layoutXfbBufferEnd); + + shiftBinding.fill(0); } void setLimits(const TBuiltInResource& r) { resources = r; } @@ -148,13 +254,147 @@ public: void setSource(EShSource s) { source = s; } EShSource getSource() const { return source; } - void setEntryPoint(const char* ep) { entryPoint = ep; } - const std::string& getEntryPoint() const { return entryPoint; } + void setEntryPointName(const char* ep) + { + entryPointName = ep; + processes.addProcess("entry-point"); + processes.addArgument(entryPointName); + } + void setEntryPointMangledName(const char* ep) { entryPointMangledName = ep; } + const std::string& getEntryPointName() const { return entryPointName; } + const std::string& getEntryPointMangledName() const { return entryPointMangledName; } + + void setShiftBinding(TResourceType res, unsigned int shift) + { + shiftBinding[res] = shift; + + const char* name = getResourceName(res); + if (name != nullptr) + processes.addIfNonZero(name, shift); + } + + unsigned int getShiftBinding(TResourceType res) const { return shiftBinding[res]; } + + void setShiftBindingForSet(TResourceType res, unsigned int shift, unsigned int set) + { + if (shift == 0) // ignore if there's no shift: it's a no-op. + return; + + shiftBindingForSet[res][set] = shift; + + const char* name = getResourceName(res); + if (name != nullptr) { + processes.addProcess(name); + processes.addArgument(shift); + processes.addArgument(set); + } + } + + int getShiftBindingForSet(TResourceType res, unsigned int set) const + { + const auto shift = shiftBindingForSet[res].find(set); + return shift == shiftBindingForSet[res].end() ? -1 : shift->second; + } + bool hasShiftBindingForSet(TResourceType res) const { return !shiftBindingForSet[res].empty(); } + + void setResourceSetBinding(const std::vector& shift) + { + resourceSetBinding = shift; + if (shift.size() > 0) { + processes.addProcess("resource-set-binding"); + for (int s = 0; s < (int)shift.size(); ++s) + processes.addArgument(shift[s]); + } + } + const std::vector& getResourceSetBinding() const { return resourceSetBinding; } + void setAutoMapBindings(bool map) + { + autoMapBindings = map; + if (autoMapBindings) + processes.addProcess("auto-map-bindings"); + } + bool getAutoMapBindings() const { return autoMapBindings; } + void setAutoMapLocations(bool map) + { + autoMapLocations = map; + if (autoMapLocations) + processes.addProcess("auto-map-locations"); + } + bool getAutoMapLocations() const { return autoMapLocations; } + void setInvertY(bool invert) + { + invertY = invert; + if (invertY) + processes.addProcess("invert-y"); + } + bool getInvertY() const { return invertY; } + + void setFlattenUniformArrays(bool flatten) + { + flattenUniformArrays = flatten; + if (flattenUniformArrays) + processes.addProcess("flatten-uniform-arrays"); + } + bool getFlattenUniformArrays() const { return flattenUniformArrays; } + void setNoStorageFormat(bool b) + { + useUnknownFormat = b; + if (useUnknownFormat) + processes.addProcess("no-storage-format"); + } + bool getNoStorageFormat() const { return useUnknownFormat; } + void setHlslOffsets() + { + hlslOffsets = true; + if (hlslOffsets) + processes.addProcess("hlsl-offsets"); + } + bool usingHlslOFfsets() const { return hlslOffsets; } + void setUseStorageBuffer() + { + useStorageBuffer = true; + processes.addProcess("use-storage-buffer"); + } + bool usingStorageBuffer() const { return useStorageBuffer; } + void setHlslIoMapping(bool b) + { + hlslIoMapping = b; + if (hlslIoMapping) + processes.addProcess("hlsl-iomap"); + } + bool usingHlslIoMapping() { return hlslIoMapping; } + + template T addCounterBufferName(const T& name) const { return name + implicitCounterName; } + bool hasCounterBufferName(const TString& name) const { + size_t len = strlen(implicitCounterName); + return name.size() > len && + name.compare(name.size() - len, len, implicitCounterName) == 0; + } + + void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { textureSamplerTransformMode = mode; } + void setVersion(int v) { version = v; } int getVersion() const { return version; } void setProfile(EProfile p) { profile = p; } EProfile getProfile() const { return profile; } - void setSpv(const SpvVersion& s) { spvVersion = s; } + void setSpv(const SpvVersion& s) + { + spvVersion = s; + + // client processes + if (spvVersion.vulkan > 0) + processes.addProcess("client vulkan100"); + if (spvVersion.openGl > 0) + processes.addProcess("client opengl100"); + + // target-environment processes + if (spvVersion.vulkan > 0) + processes.addProcess("target-env vulkan1.0"); + else if (spvVersion.vulkan > 0) + processes.addProcess("target-env vulkanUnknown"); + if (spvVersion.openGl > 0) + processes.addProcess("target-env opengl"); + } const SpvVersion& getSpv() const { return spvVersion; } EShLanguage getStage() const { return language; } void addRequestedExtension(const char* extension) { requestedExtensions.insert(extension); } @@ -162,8 +402,8 @@ public: void setTreeRoot(TIntermNode* r) { treeRoot = r; } TIntermNode* getTreeRoot() const { return treeRoot; } - void addMainCount() { ++numMains; } - int getNumMains() const { return numMains; } + void incrementEntryPointCount() { ++numEntryPoints; } + int getNumEntryPoints() const { return numEntryPoints; } int getNumErrors() const { return numErrors; } void addPushConstantCount() { ++numPushConstants; } bool isRecursive() const { return recursive; } @@ -171,53 +411,77 @@ public: TIntermSymbol* addSymbol(const TVariable&); TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&); TIntermSymbol* addSymbol(const TType&, const TSourceLoc&); + TIntermSymbol* addSymbol(const TIntermSymbol&); TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*) const; + std::tuple addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1) const; + TIntermTyped* addUniShapeConversion(TOperator, const TType&, TIntermTyped*); + void addBiShapeConversion(TOperator, TIntermTyped*& lhsNode, TIntermTyped*& rhsNode); + TIntermTyped* addShapeConversion(const TType&, TIntermTyped*); TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, TSourceLoc); TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc); TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc); TIntermTyped* addUnaryMath(TOperator, TIntermTyped* child, TSourceLoc); TIntermTyped* addBuiltInFunctionCall(const TSourceLoc& line, TOperator, bool unary, TIntermNode*, const TType& returnType); - bool canImplicitlyPromote(TBasicType from, TBasicType to) const; + bool canImplicitlyPromote(TBasicType from, TBasicType to, TOperator op = EOpNull) const; + bool isIntegralPromotion(TBasicType from, TBasicType to) const; + bool isFPPromotion(TBasicType from, TBasicType to) const; + bool isIntegralConversion(TBasicType from, TBasicType to) const; + bool isFPConversion(TBasicType from, TBasicType to) const; + bool isFPIntegralConversion(TBasicType from, TBasicType to) const; + TOperator mapTypeToConstructorOp(const TType&) const; TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right); TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&); TIntermAggregate* makeAggregate(TIntermNode* node); TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&); + TIntermAggregate* makeAggregate(const TSourceLoc&); TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, TSourceLoc); bool areAllChildConst(TIntermAggregate* aggrNode); - TIntermNode* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&); + TIntermSelection* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&); TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&); TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&); TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&); TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const; + TIntermConstantUnion* addConstantUnion(signed char, const TSourceLoc&, bool literal = false) const; + TIntermConstantUnion* addConstantUnion(unsigned char, const TSourceLoc&, bool literal = false) const; + TIntermConstantUnion* addConstantUnion(signed short, const TSourceLoc&, bool literal = false) const; + TIntermConstantUnion* addConstantUnion(unsigned short, const TSourceLoc&, bool literal = false) const; TIntermConstantUnion* addConstantUnion(int, const TSourceLoc&, bool literal = false) const; TIntermConstantUnion* addConstantUnion(unsigned int, const TSourceLoc&, bool literal = false) const; TIntermConstantUnion* addConstantUnion(long long, const TSourceLoc&, bool literal = false) const; TIntermConstantUnion* addConstantUnion(unsigned long long, const TSourceLoc&, bool literal = false) const; TIntermConstantUnion* addConstantUnion(bool, const TSourceLoc&, bool literal = false) const; TIntermConstantUnion* addConstantUnion(double, TBasicType, const TSourceLoc&, bool literal = false) const; + 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, const TSourceLoc&); + TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, + const TSourceLoc&, TIntermLoop*&); TIntermBranch* addBranch(TOperator, const TSourceLoc&); TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&); - TIntermTyped* addSwizzle(TVectorFields&, const TSourceLoc&); + template TIntermTyped* addSwizzle(TSwizzleSelectors&, const TSourceLoc&); + + // Low level functions to add nodes (no conversions or other higher level transformations) + // If a type is provided, the node's type will be set to it. + TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc) const; + TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc, const TType&) const; + TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc) const; + TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc, const TType&) const; // Constant folding (in Constant.cpp) TIntermTyped* fold(TIntermAggregate* aggrNode); TIntermTyped* foldConstructor(TIntermAggregate* aggrNode); TIntermTyped* foldDereference(TIntermTyped* node, int index, const TSourceLoc&); - TIntermTyped* foldSwizzle(TIntermTyped* node, TVectorFields& fields, const TSourceLoc&); + TIntermTyped* foldSwizzle(TIntermTyped* node, TSwizzleSelectors& fields, const TSourceLoc&); // Tree ops static const TIntermTyped* findLValueBase(const TIntermTyped*, bool swizzleOkay); // Linkage related void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&); - void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&); void addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol&); - bool setInvocations(int i) + bool setInvocations(int i) { if (invocations != TQualifier::layoutNotSet) return invocations == i; @@ -259,7 +523,7 @@ public: TVertexOrder getVertexOrder() const { return vertexOrder; } void setPointMode() { pointMode = true; } bool getPointMode() const { return pointMode; } - + bool setLocalSize(int dim, int size) { if (localSize[dim] > 1) @@ -296,6 +560,8 @@ public: bool getPixelCenterInteger() const { return pixelCenterInteger; } void setEarlyFragmentTests() { earlyFragmentTests = true; } bool getEarlyFragmentTests() const { return earlyFragmentTests; } + void setPostDepthCoverage() { postDepthCoverage = true; } + bool getPostDepthCoverage() const { return postDepthCoverage; } bool setDepth(TLayoutDepth d) { if (depthLayout != EldNone) @@ -307,20 +573,25 @@ public: void setDepthReplacing() { depthReplacing = true; } bool isDepthReplacing() const { return depthReplacing; } + void setHlslFunctionality1() { hlslFunctionality1 = true; } + bool getHlslFunctionality1() const { return hlslFunctionality1; } + void addBlendEquation(TBlendEquationShift b) { blendEquations |= (1 << b); } unsigned int getBlendEquations() const { return blendEquations; } void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee); void merge(TInfoSink&, TIntermediate&); - void finalCheck(TInfoSink&); + void finalCheck(TInfoSink&, bool keepUncalled); void addIoAccessed(const TString& name) { ioAccessed.insert(name); } bool inIoAccessed(const TString& name) const { return ioAccessed.find(name) != ioAccessed.end(); } int addUsedLocation(const TQualifier&, const TType&, bool& typeCollision); + int checkLocationRange(int set, const TIoRange& range, const TType&, bool& typeCollision); int addUsedOffsets(int binding, int offset, int numOffsets); bool addUsedConstantId(int id); - int computeTypeLocationSize(const TType&) const; + static int computeTypeLocationSize(const TType&, EShLanguage); + static int computeTypeUniformLocationSize(const TType&); bool setXfbBufferStride(int buffer, unsigned stride) { @@ -329,34 +600,88 @@ public: xfbBuffers[buffer].stride = stride; return true; } + unsigned getXfbStride(int buffer) const { return xfbBuffers[buffer].stride; } int addXfbBufferOffset(const TType&); unsigned int computeTypeXfbSize(const TType&, bool& containsDouble) const; + static int getBaseAlignmentScalar(const TType&, int& size); static int getBaseAlignment(const TType&, int& size, int& stride, bool std140, bool rowMajor); + static bool improperStraddle(const TType& type, int size, int offset); + bool promote(TIntermOperator*); + +#ifdef NV_EXTENSIONS + void setLayoutOverrideCoverage() { layoutOverrideCoverage = true; } + bool getLayoutOverrideCoverage() const { return layoutOverrideCoverage; } + void setGeoPassthroughEXT() { geoPassthroughEXT = true; } + bool getGeoPassthroughEXT() const { return geoPassthroughEXT; } +#endif + + const char* addSemanticName(const TString& name) + { + return semanticNameSet.insert(name).first->c_str(); + } + + void setSourceFile(const char* file) { if (file != nullptr) sourceFile = file; } + const std::string& getSourceFile() const { return sourceFile; } + void addSourceText(const char* text) { sourceText = sourceText + text; } + const std::string& getSourceText() const { return sourceText; } + void addProcesses(const std::vector& p) { + for (int i = 0; i < (int)p.size(); ++i) + processes.addProcess(p[i]); + } + void addProcess(const std::string& process) { processes.addProcess(process); } + void addProcessArgument(const std::string& arg) { processes.addArgument(arg); } + const std::vector& getProcesses() const { return processes.getProcesses(); } + + void setNeedsLegalization() { needToLegalize = true; } + bool needsLegalization() const { return needToLegalize; } + + void setBinaryDoubleOutput() { binaryDoubleOutput = true; } + bool getBinaryDoubleOutput() { return binaryDoubleOutput; } + + const char* const implicitThisName; + const char* const implicitCounterName; protected: TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&); void error(TInfoSink& infoSink, const char*); + void warn(TInfoSink& infoSink, const char*); void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals); void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects); void mergeImplicitArraySizes(TType&, const TType&); void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, bool crossStage); void checkCallGraphCycles(TInfoSink&); + void checkCallGraphBodies(TInfoSink&, bool keepUncalled); void inOutLocationCheck(TInfoSink&); TIntermSequence& findLinkerObjects() const; bool userOutputUsed() const; - static int getBaseAlignmentScalar(const TType&, int& size); bool isSpecializationOperation(const TIntermOperator&) const; + bool isNonuniformPropagating(TOperator) const; + bool promoteUnary(TIntermUnary&); + bool promoteBinary(TIntermBinary&); + void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&); + bool promoteAggregate(TIntermAggregate&); + void pushSelector(TIntermSequence&, const TVectorSelector&, const TSourceLoc&); + void pushSelector(TIntermSequence&, const TMatrixSelector&, const TSourceLoc&); + bool specConstantPropagates(const TIntermTyped&, const TIntermTyped&); + void performTextureUpgradeAndSamplerRemovalTransformation(TIntermNode* root); + bool isConversionAllowed(TOperator op, TIntermTyped* node) const; + TIntermUnary* createConversion(TBasicType convertTo, TIntermTyped* node) const; + std::tuple getConversionDestinatonType(TBasicType type0, TBasicType type1, TOperator op) const; + bool extensionRequested(const char *extension) const {return requestedExtensions.find(extension) != requestedExtensions.end();} + static const char* getResourceName(TResourceType); const EShLanguage language; // stage, known at construction time EShSource source; // source language, known a bit later - std::string entryPoint; - EProfile profile; - int version; + std::string entryPointName; + std::string entryPointMangledName; + + EProfile profile; // source profile + int version; // source version SpvVersion spvVersion; TIntermNode* treeRoot; std::set requestedExtensions; // cumulation of all enabled or required extensions; not connected to what subset of the shader used them TBuiltInResource resources; - int numMains; + int numEntryPoints; int numErrors; int numPushConstants; bool recursive; @@ -372,12 +697,35 @@ protected: int localSize[3]; int localSizeSpecId[3]; bool earlyFragmentTests; + bool postDepthCoverage; TLayoutDepth depthLayout; bool depthReplacing; + bool hlslFunctionality1; int blendEquations; // an 'or'ing of masks of shifts of TBlendEquationShift bool xfbMode; bool multiStream; +#ifdef NV_EXTENSIONS + bool layoutOverrideCoverage; + bool geoPassthroughEXT; +#endif + + // Base shift values + std::array shiftBinding; + + // Per-descriptor-set shift values + std::array, EResCount> shiftBindingForSet; + + std::vector resourceSetBinding; + bool autoMapBindings; + bool autoMapLocations; + bool invertY; + bool flattenUniformArrays; + bool useUnknownFormat; + bool hlslOffsets; + bool useStorageBuffer; + bool hlslIoMapping; + typedef std::list TGraph; TGraph callGraph; @@ -386,6 +734,19 @@ protected: std::vector usedAtomics; // sets of bindings used by atomic counters std::vector xfbBuffers; // all the data we need to track per xfb buffer std::unordered_set usedConstantId; // specialization constant ids used + std::set semanticNameSet; + + EShTextureSamplerTransformMode textureSamplerTransformMode; + + // source code of shader, useful as part of debug information + std::string sourceFile; + std::string sourceText; + + // for OpModuleProcessed, or equivalent + TProcesses processes; + + bool needToLegalize; + bool binaryDoubleOutput; private: void operator=(TIntermediate&); // prevent assignments diff --git a/Externals/glslang/glslang/MachineIndependent/parseConst.cpp b/Externals/glslang/glslang/MachineIndependent/parseConst.cpp index 90621d39f4..1a8e6d9987 100644 --- a/Externals/glslang/glslang/MachineIndependent/parseConst.cpp +++ b/Externals/glslang/glslang/MachineIndependent/parseConst.cpp @@ -1,10 +1,10 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -18,22 +18,22 @@ // 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. +// 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. // // -// Travarse a tree of constants to create a single folded constant. +// Traverse a tree of constants to create a single folded constant. // It should only be used when the whole tree is known to be constant. // @@ -45,7 +45,7 @@ class TConstTraverser : public TIntermTraverser { public: TConstTraverser(const TConstUnionArray& cUnion, bool singleConstParam, TOperator constructType, const TType& t) : unionArray(cUnion), type(t), - constructorType(constructType), singleConstantParam(singleConstParam), error(false), isMatrix(false), + constructorType(constructType), singleConstantParam(singleConstParam), error(false), isMatrix(false), matrixCols(0), matrixRows(0) { index = 0; tOp = EOpNull; } virtual void visitConstantUnion(TIntermConstantUnion* node); @@ -73,18 +73,12 @@ bool TConstTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node) if (! node->isConstructor() && node->getOp() != EOpComma) { error = true; - return false; - } - - if (node->getSequence().size() == 0) { - error = true; - return false; } bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion(); if (flag) { - singleConstantParam = true; + singleConstantParam = true; constructorType = node->getOp(); size = node->getType().computeNumComponents(); @@ -93,19 +87,19 @@ bool TConstTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node) matrixCols = node->getType().getMatrixCols(); matrixRows = node->getType().getMatrixRows(); } - } + } - for (TIntermSequence::iterator p = node->getSequence().begin(); + for (TIntermSequence::iterator p = node->getSequence().begin(); p != node->getSequence().end(); p++) { if (node->getOp() == EOpComma) - index = 0; + index = 0; (*p)->traverse(this); - } - if (flag) + } + if (flag) { - singleConstantParam = false; + singleConstantParam = false; constructorType = EOpNull; size = 0; isMatrix = false; @@ -126,7 +120,7 @@ void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node) if (! singleConstantParam) { int rightUnionSize = node->getType().computeNumComponents(); - + const TConstUnionArray& rightUnionArray = node->getConstArray(); for (int i = 0; i < rightUnionSize; i++) { if (index >= instanceSize) @@ -148,7 +142,7 @@ void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node) leftUnionArray[i] = rightUnionArray[count]; (index)++; - + if (nodeComps > 1) count++; } @@ -180,13 +174,13 @@ void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node) return; if (i == startIndex || (i - startIndex) % (matrixRows + 1) == 0 ) leftUnionArray[i] = rightUnionArray[count]; - else + else leftUnionArray[i].setDConst(0.0); index++; if (nodeComps > 1) - count++; + count++; } } } @@ -199,7 +193,7 @@ bool TIntermediate::parseConstTree(TIntermNode* root, TConstUnionArray unionArra return false; TConstTraverser it(unionArray, singleConstantParam, constructorType, t); - + root->traverse(&it); if (it.error) return true; diff --git a/Externals/glslang/glslang/MachineIndependent/parseVersions.h b/Externals/glslang/glslang/MachineIndependent/parseVersions.h index c0c8945742..b2aaa39955 100755 --- a/Externals/glslang/glslang/MachineIndependent/parseVersions.h +++ b/Externals/glslang/glslang/MachineIndependent/parseVersions.h @@ -1,11 +1,12 @@ // -//Copyright (C) 2016 Google, Inc. +// Copyright (C) 2016 Google, Inc. +// Copyright (C) 2017 ARM Limited. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,18 +20,18 @@ // 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. +// 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. // // This is implemented in Versions.cpp @@ -68,6 +69,7 @@ public: virtual void requireStage(const TSourceLoc&, EShLanguage, const char* featureDesc); virtual void checkDeprecated(const TSourceLoc&, int queryProfiles, int depVersion, const char* featureDesc); virtual void requireNotRemoved(const TSourceLoc&, int queryProfiles, int removedVersion, const char* featureDesc); + virtual void unimplemented(const TSourceLoc&, const char* featureDesc); virtual void requireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc); virtual void ppRequireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc); virtual TExtensionBehavior getExtensionBehavior(const char*); @@ -76,7 +78,16 @@ public: virtual void updateExtensionBehavior(int line, const char* const extension, const char* behavior); virtual void fullIntegerCheck(const TSourceLoc&, const char* op); virtual void doubleCheck(const TSourceLoc&, const char* op); + virtual void float16Check(const TSourceLoc&, const char* op, bool builtIn = false); +#ifdef AMD_EXTENSIONS + virtual void float16OpaqueCheck(const TSourceLoc&, const char* op, bool builtIn = false); +#endif virtual void int64Check(const TSourceLoc&, const char* op, bool builtIn = false); + virtual void explicitInt8Check(const TSourceLoc&, const char* op, bool builtIn = false); + virtual void explicitInt16Check(const TSourceLoc&, const char* op, bool builtIn = false); + virtual void explicitInt32Check(const TSourceLoc&, const char* op, bool builtIn = false); + virtual void explicitFloat32Check(const TSourceLoc&, const char* op, bool builtIn = false); + virtual void explicitFloat64Check(const TSourceLoc&, const char* op, bool builtIn = false); virtual void spvRemoved(const TSourceLoc&, const char* op); virtual void vulkanRemoved(const TSourceLoc&, const char* op); virtual void requireVulkan(const TSourceLoc&, const char* op); @@ -107,6 +118,8 @@ public: void getPreamble(std::string&); bool relaxedErrors() const { return (messages & EShMsgRelaxedErrors) != 0; } bool suppressWarnings() const { return (messages & EShMsgSuppressWarnings) != 0; } + bool isReadingHLSL() const { return (messages & EShMsgReadHlsl) == EShMsgReadHlsl; } + bool hlslEnable16BitTypes() const { return (messages & EShMsgHlslEnable16BitTypes) != 0; } TInfoSink& infoSink; @@ -119,12 +132,12 @@ public: TIntermediate& intermediate; // helper for making and hooking up pieces of the parse tree protected: + TMap extensionBehavior; // for each extension string, what its current behavior is set to EShMessages messages; // errors/warnings/rule-sets int numErrors; // number of compile-time errors encountered TInputScanner* currentScanner; private: - TMap extensionBehavior; // for each extension string, what its current behavior is set to explicit TParseVersions(const TParseVersions&); TParseVersions& operator=(const TParseVersions&); }; diff --git a/Externals/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp b/Externals/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp index 35097588c4..8048fa513d 100644 --- a/Externals/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp +++ b/Externals/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp @@ -1,11 +1,11 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2013 LunarG, Inc. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2013 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: +// 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. @@ -19,18 +19,18 @@ // 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. +// 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. // /****************************************************************************\ Copyright (c) 2002, NVIDIA Corporation. @@ -57,7 +57,7 @@ Except as expressly stated in this notice, no other rights or licenses express or implied, are granted by NVIDIA herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the NVIDIA Software may be -incorporated. No hardware is licensed hereunder. +incorporated. No hardware is licensed hereunder. THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, @@ -75,38 +75,28 @@ NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \****************************************************************************/ -// -// cpp.c -// +#ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS +#endif -#include -#include #include -#include -#include -#include +#include +#include +#include +#include #include "PpContext.h" #include "PpTokens.h" namespace glslang { -int TPpContext::InitCPP() -{ - pool = mem_CreatePool(0, 0); - - return 1; -} - // Handle #define int TPpContext::CPPdefine(TPpToken* ppToken) { MacroSymbol mac; - Symbol *symb; - // get macro name + // get the macro name int token = scanToken(ppToken); if (token != PpAtomIdentifier) { parseContext.ppError(ppToken->loc, "must be followed by macro name", "#define", ""); @@ -117,38 +107,36 @@ int TPpContext::CPPdefine(TPpToken* ppToken) parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#define"); } - // save the original atom - const int defAtom = ppToken->atom; + // save the macro name + const int defAtom = atomStrings.getAddAtom(ppToken->name); // gather parameters to the macro, between (...) token = scanToken(ppToken); if (token == '(' && ! ppToken->space) { - int argc = 0; - int args[maxMacroArgs]; + mac.emptyArgs = 1; do { token = scanToken(ppToken); - if (argc == 0 && token == ')') + if (mac.args.size() == 0 && token == ')') break; if (token != PpAtomIdentifier) { parseContext.ppError(ppToken->loc, "bad argument", "#define", ""); return token; } + mac.emptyArgs = 0; + const int argAtom = atomStrings.getAddAtom(ppToken->name); + // check for duplication of parameter name bool duplicate = false; - for (int a = 0; a < argc; ++a) { - if (args[a] == ppToken->atom) { + for (size_t a = 0; a < mac.args.size(); ++a) { + if (mac.args[a] == argAtom) { parseContext.ppError(ppToken->loc, "duplicate macro parameter", "#define", ""); duplicate = true; break; } } - if (! duplicate) { - if (argc < maxMacroArgs) - args[argc++] = ppToken->atom; - else - parseContext.ppError(ppToken->loc, "too many macro parameters", "#define", ""); - } + if (! duplicate) + mac.args.push_back(argAtom); token = scanToken(ppToken); } while (token == ','); if (token != ')') { @@ -156,57 +144,50 @@ int TPpContext::CPPdefine(TPpToken* ppToken) return token; } - mac.argc = argc; - mac.args = (int*)mem_Alloc(pool, argc * sizeof(int)); - memcpy(mac.args, args, argc * sizeof(int)); + token = scanToken(ppToken); } // record the definition of the macro TSourceLoc defineLoc = ppToken->loc; // because ppToken is going to go to the next line before we report errors - mac.body = new TokenStream; while (token != '\n' && token != EndOfInput) { - RecordToken(mac.body, token, ppToken); + mac.body.putToken(token, ppToken); token = scanToken(ppToken); if (token != '\n' && ppToken->space) - RecordToken(mac.body, ' ', ppToken); + mac.body.putToken(' ', ppToken); } // check for duplicate definition - symb = LookUpSymbol(defAtom); - if (symb) { - if (! symb->mac.undef) { + MacroSymbol* existing = lookupMacroDef(defAtom); + if (existing != nullptr) { + if (! existing->undef) { // Already defined -- need to make sure they are identical: // "Two replacement lists are identical if and only if the preprocessing tokens in both have the same number, // ordering, spelling, and white-space separation, where all white-space separations are considered identical." - if (symb->mac.argc != mac.argc) - parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define", GetAtomString(defAtom)); + if (existing->args.size() != mac.args.size() || existing->emptyArgs != mac.emptyArgs) + parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define", atomStrings.getString(defAtom)); else { - for (int argc = 0; argc < mac.argc; argc++) { - if (symb->mac.args[argc] != mac.args[argc]) - parseContext.ppError(defineLoc, "Macro redefined; different argument names:", "#define", GetAtomString(defAtom)); - } - RewindTokenStream(symb->mac.body); - RewindTokenStream(mac.body); + if (existing->args != mac.args) + parseContext.ppError(defineLoc, "Macro redefined; different argument names:", "#define", atomStrings.getString(defAtom)); + existing->body.reset(); + mac.body.reset(); int newToken; do { int oldToken; TPpToken oldPpToken; - TPpToken newPpToken; - oldToken = ReadToken(symb->mac.body, &oldPpToken); - newToken = ReadToken(mac.body, &newPpToken); + TPpToken newPpToken; + oldToken = existing->body.getToken(parseContext, &oldPpToken); + newToken = mac.body.getToken(parseContext, &newPpToken); if (oldToken != newToken || oldPpToken != newPpToken) { - parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define", GetAtomString(defAtom)); - break; + parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define", atomStrings.getString(defAtom)); + break; } } while (newToken > 0); } } + *existing = mac; } else - symb = AddSymbol(defAtom); - - delete symb->mac.body; - symb->mac = mac; + addMacroDef(defAtom, mac); return '\n'; } @@ -215,7 +196,6 @@ int TPpContext::CPPdefine(TPpToken* ppToken) int TPpContext::CPPundef(TPpToken* ppToken) { int token = scanToken(ppToken); - Symbol *symb; if (token != PpAtomIdentifier) { parseContext.ppError(ppToken->loc, "must be followed by macro name", "#undef", ""); @@ -224,10 +204,9 @@ int TPpContext::CPPundef(TPpToken* ppToken) parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#undef"); - symb = LookUpSymbol(ppToken->atom); - if (symb) { - symb->mac.undef = 1; - } + MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name)); + if (macro != nullptr) + macro->undef = 1; token = scanToken(ppToken); if (token != '\n') parseContext.ppError(ppToken->loc, "can only be followed by a single macro name", "#undef", ""); @@ -242,7 +221,6 @@ int TPpContext::CPPundef(TPpToken* ppToken) */ int TPpContext::CPPelse(int matchelse, TPpToken* ppToken) { - int atom; int depth = 0; int token = scanToken(ppToken); @@ -250,7 +228,7 @@ int TPpContext::CPPelse(int matchelse, TPpToken* ppToken) if (token != '#') { while (token != '\n' && token != EndOfInput) token = scanToken(ppToken); - + if (token == EndOfInput) return token; @@ -261,35 +239,40 @@ int TPpContext::CPPelse(int matchelse, TPpToken* ppToken) if ((token = scanToken(ppToken)) != PpAtomIdentifier) continue; - atom = ppToken->atom; - if (atom == PpAtomIf || atom == PpAtomIfdef || atom == PpAtomIfndef) { - depth++; - ifdepth++; - elsetracker++; - } else if (atom == PpAtomEndif) { - token = extraTokenCheck(atom, ppToken, scanToken(ppToken)); + int nextAtom = atomStrings.getAtom(ppToken->name); + if (nextAtom == PpAtomIf || nextAtom == PpAtomIfdef || nextAtom == PpAtomIfndef) { + depth++; + if (ifdepth >= maxIfNesting || elsetracker >= maxIfNesting) { + parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#if/#ifdef/#ifndef", ""); + return EndOfInput; + } else { + ifdepth++; + elsetracker++; + } + } else if (nextAtom == PpAtomEndif) { + token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken)); elseSeen[elsetracker] = false; --elsetracker; if (depth == 0) { // found the #endif we are looking for - if (ifdepth) + if (ifdepth > 0) --ifdepth; break; } --depth; --ifdepth; } else if (matchelse && depth == 0) { - if (atom == PpAtomElse) { + if (nextAtom == PpAtomElse) { elseSeen[elsetracker] = true; - token = extraTokenCheck(atom, ppToken, scanToken(ppToken)); + token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken)); // found the #else we are looking for break; - } else if (atom == PpAtomElif) { + } else if (nextAtom == PpAtomElif) { if (elseSeen[elsetracker]) parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", ""); /* we decrement ifdepth here, because CPPif will increment * it and we really want to leave it alone */ - if (ifdepth) { + if (ifdepth > 0) { --ifdepth; elseSeen[elsetracker] = false; --elsetracker; @@ -297,13 +280,13 @@ int TPpContext::CPPelse(int matchelse, TPpToken* ppToken) return CPPif(ppToken); } - } else if (atom == PpAtomElse) { + } else if (nextAtom == PpAtomElse) { if (elseSeen[elsetracker]) parseContext.ppError(ppToken->loc, "#else after #else", "#else", ""); else elseSeen[elsetracker] = true; - token = extraTokenCheck(atom, ppToken, scanToken(ppToken)); - } else if (atom == PpAtomElif) { + token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken)); + } else if (nextAtom == PpAtomElif) { if (elseSeen[elsetracker]) parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", ""); } @@ -313,21 +296,21 @@ int TPpContext::CPPelse(int matchelse, TPpToken* ppToken) } // Call when there should be no more tokens left on a line. -int TPpContext::extraTokenCheck(int atom, TPpToken* ppToken, int token) +int TPpContext::extraTokenCheck(int contextAtom, TPpToken* ppToken, int token) { if (token != '\n' && token != EndOfInput) { static const char* message = "unexpected tokens following directive"; const char* label; - if (atom == PpAtomElse) + if (contextAtom == PpAtomElse) label = "#else"; - else if (atom == PpAtomElif) + else if (contextAtom == PpAtomElif) label = "#elif"; - else if (atom == PpAtomEndif) + else if (contextAtom == PpAtomEndif) label = "#endif"; - else if (atom == PpAtomIf) + else if (contextAtom == PpAtomIf) label = "#if"; - else if (atom == PpAtomLine) + else if (contextAtom == PpAtomLine) label = "#line"; else label = ""; @@ -368,8 +351,8 @@ namespace { int op_add(int a, int b) { return a + b; } int op_sub(int a, int b) { return a - b; } int op_mul(int a, int b) { return a * b; } - int op_div(int a, int b) { return a / b; } - int op_mod(int a, int b) { return a % b; } + 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_cmpl(int a) { return ~a; } @@ -415,7 +398,15 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo { TSourceLoc loc = ppToken->loc; // because we sometimes read the newline before reporting the error if (token == PpAtomIdentifier) { - if (ppToken->atom == PpAtomDefined) { + if (strcmp("defined", ppToken->name) == 0) { + if (! parseContext.isReadingHLSL() && isMacroInput()) { + if (parseContext.relaxedErrors()) + parseContext.ppWarn(ppToken->loc, "nonportable when expanded from macros for preprocessor expression", + "defined", ""); + else + parseContext.ppError(ppToken->loc, "cannot use in preprocessor expression when expanded from macros", + "defined", ""); + } bool needclose = 0; token = scanToken(ppToken); if (token == '(') { @@ -429,8 +420,9 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo return token; } - Symbol* s = LookUpSymbol(ppToken->atom); - res = s ? ! s->mac.undef : 0; + + MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name)); + res = macro != nullptr ? !macro->undef : 0; token = scanToken(ppToken); if (needclose) { if (token != ')') { @@ -485,7 +477,7 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo // Perform evaluation of binary operation, if there is one, otherwise we are done. while (! err) { - if (token == ')' || token == '\n') + if (token == ')' || token == '\n') break; int op; for (op = NUM_ELEMENTS(binop) - 1; op >= 0; op--) { @@ -495,7 +487,7 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo if (op < 0 || binop[op].precedence <= precedence) break; int leftSide = res; - + // Setup short-circuiting, needed for ES, unless already in a short circuit. // (Once in a short-circuit, can't turn off again, until that whole subexpression is done. if (! shortCircuit) { @@ -522,8 +514,8 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo // Expand macros, skipping empty expansions, to get to the first real token in those expansions. int TPpContext::evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken* ppToken) { - while (token == PpAtomIdentifier && ppToken->atom != PpAtomDefined) { - int macroReturn = MacroExpand(ppToken->atom, ppToken, true, false); + while (token == PpAtomIdentifier && strcmp("defined", ppToken->name) != 0) { + int macroReturn = MacroExpand(ppToken, true, false); if (macroReturn == 0) { parseContext.ppError(ppToken->loc, "can't evaluate expression", "preprocessor evaluation", ""); err = true; @@ -547,14 +539,15 @@ int TPpContext::evalToToken(int token, bool shortCircuit, int& res, bool& err, T } // Handle #if -int TPpContext::CPPif(TPpToken* ppToken) +int TPpContext::CPPif(TPpToken* ppToken) { int token = scanToken(ppToken); - elsetracker++; - ifdepth++; - if (ifdepth > maxIfNesting) { + if (ifdepth >= maxIfNesting || elsetracker >= maxIfNesting) { parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#if", ""); - return 0; + return EndOfInput; + } else { + elsetracker++; + ifdepth++; } int res = 0; bool err = false; @@ -570,77 +563,110 @@ int TPpContext::CPPif(TPpToken* ppToken) int TPpContext::CPPifdef(int defined, TPpToken* ppToken) { int token = scanToken(ppToken); - int name = ppToken->atom; - if (++ifdepth > maxIfNesting) { + if (ifdepth > maxIfNesting || elsetracker > maxIfNesting) { parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#ifdef", ""); - return 0; + return EndOfInput; + } else { + elsetracker++; + ifdepth++; } - elsetracker++; + if (token != PpAtomIdentifier) { if (defined) parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifdef", ""); - else + else parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifndef", ""); } else { - Symbol *s = LookUpSymbol(name); + MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name)); token = scanToken(ppToken); if (token != '\n') { parseContext.ppError(ppToken->loc, "unexpected tokens following #ifdef directive - expected a newline", "#ifdef", ""); while (token != '\n' && token != EndOfInput) token = scanToken(ppToken); } - if (((s && !s->mac.undef) ? 1 : 0) != defined) + if (((macro != nullptr && !macro->undef) ? 1 : 0) != defined) token = CPPelse(1, ppToken); } return token; } -// Handle #include +// Handle #include ... +// TODO: Handle macro expansions for the header name int TPpContext::CPPinclude(TPpToken* ppToken) { const TSourceLoc directiveLoc = ppToken->loc; + bool startWithLocalSearch = true; // to additionally include the extra "" paths int token = scanToken(ppToken); - if (token != PpAtomConstString) { - // TODO: handle angle brackets. - parseContext.ppError(directiveLoc, "must be followed by a file designation", "#include", ""); - } else { - // Make a copy of the name because it will be overwritten by the next token scan. - const std::string filename = ppToken->name; - token = scanToken(ppToken); - if (token != '\n' && token != EndOfInput) { - parseContext.ppError(ppToken->loc, "extra content after file designation", "#include", ""); - } else { - TShader::Includer::IncludeResult* res = includer.include(filename.c_str(), TShader::Includer::EIncludeRelative, currentSourceFile.c_str(), includeStack.size() + 1); - if (res && !res->file_name.empty()) { - if (res->file_data && res->file_length) { - const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine(); - std::ostringstream prologue; - std::ostringstream epilogue; - prologue << "#line " << forNextLine << " " << "\"" << res->file_name << "\"\n"; - epilogue << (res->file_data[res->file_length - 1] == '\n'? "" : "\n") << "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n"; - pushInput(new TokenizableIncludeFile(directiveLoc, prologue.str(), res, epilogue.str(), this)); - } - // At EOF, there's no "current" location anymore. - if (token != EndOfInput) parseContext.setCurrentColumn(0); - // Don't accidentally return EndOfInput, which will end all preprocessing. - return '\n'; - } else { - std::string message = - res ? std::string(res->file_data, res->file_length) - : std::string("Could not process include directive"); - parseContext.ppError(directiveLoc, message.c_str(), "#include", ""); - if (res) { - includer.releaseInclude(res); - } - } - } + + // handle -style #include + if (token == '<') { + startWithLocalSearch = false; + token = scanHeaderName(ppToken, '>'); } + // otherwise ppToken already has the header name and it was "header-name" style + + if (token != PpAtomConstString) { + parseContext.ppError(directiveLoc, "must be followed by a header name", "#include", ""); + return token; + } + + // Make a copy of the name because it will be overwritten by the next token scan. + const std::string filename = ppToken->name; + + // See if the directive was well formed + token = scanToken(ppToken); + if (token != '\n') { + if (token == EndOfInput) + parseContext.ppError(ppToken->loc, "expected newline after header name:", "#include", "%s", filename.c_str()); + else + parseContext.ppError(ppToken->loc, "extra content after header name:", "#include", "%s", filename.c_str()); + return token; + } + + // Process well-formed directive + + // Find the inclusion, first look in "Local" ("") paths, if requested, + // otherwise, only search the "System" (<>) paths. + TShader::Includer::IncludeResult* res = nullptr; + if (startWithLocalSearch) + res = includer.includeLocal(filename.c_str(), currentSourceFile.c_str(), includeStack.size() + 1); + if (res == nullptr || res->headerName.empty()) { + includer.releaseInclude(res); + res = includer.includeSystem(filename.c_str(), currentSourceFile.c_str(), includeStack.size() + 1); + } + + // Process the results + if (res != nullptr && !res->headerName.empty()) { + if (res->headerData != nullptr && res->headerLength > 0) { + // path for processing one or more tokens from an included header, hand off 'res' + const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine(); + std::ostringstream prologue; + std::ostringstream epilogue; + prologue << "#line " << forNextLine << " " << "\"" << res->headerName << "\"\n"; + epilogue << (res->headerData[res->headerLength - 1] == '\n'? "" : "\n") << + "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n"; + pushInput(new TokenizableIncludeFile(directiveLoc, prologue.str(), res, epilogue.str(), this)); + // There's no "current" location anymore. + parseContext.setCurrentColumn(0); + } else { + // things are okay, but there is nothing to process + includer.releaseInclude(res); + } + } else { + // error path, clean up + std::string message = + res != nullptr ? std::string(res->headerData, res->headerLength) + : std::string("Could not process include directive"); + parseContext.ppError(directiveLoc, message.c_str(), "#include", "for header name: %s", filename.c_str()); + includer.releaseInclude(res); + } + return token; } // Handle #line -int TPpContext::CPPline(TPpToken* ppToken) +int TPpContext::CPPline(TPpToken* ppToken) { // "#line must have, after macro substitution, one of the following forms: // "#line line @@ -676,7 +702,7 @@ int TPpContext::CPPline(TPpToken* ppToken) // We need to save a copy of the string instead of pointing // to the name field of the token since the name field // will likely be overwritten by the next token scan. - sourceName = GetAtomString(LookUpAddString(ppToken->name)); + sourceName = atomStrings.getString(atomStrings.getAddAtom(ppToken->name)); parseContext.setCurrentSourceName(sourceName); hasFile = true; token = scanToken(ppToken); @@ -698,27 +724,29 @@ int TPpContext::CPPline(TPpToken* ppToken) } // Handle #error -int TPpContext::CPPerror(TPpToken* ppToken) +int TPpContext::CPPerror(TPpToken* ppToken) { int token = scanToken(ppToken); std::string message; TSourceLoc loc = ppToken->loc; while (token != '\n' && token != EndOfInput) { - if (token == PpAtomConstInt || token == PpAtomConstUint || + if (token == PpAtomConstInt16 || token == PpAtomConstUint16 || + token == PpAtomConstInt || token == PpAtomConstUint || token == PpAtomConstInt64 || token == PpAtomConstUint64 || + token == PpAtomConstFloat16 || token == PpAtomConstFloat || token == PpAtomConstDouble) { message.append(ppToken->name); } else if (token == PpAtomIdentifier || token == PpAtomConstString) { message.append(ppToken->name); } else { - message.append(GetAtomString(token)); + message.append(atomStrings.getString(token)); } message.append(" "); token = scanToken(ppToken); } parseContext.notifyErrorDirective(loc.line, message.c_str()); - //store this msg into the shader's information log..set the Compile Error flag!!!! + // store this msg into the shader's information log..set the Compile Error flag!!!! parseContext.ppError(loc, message.c_str(), "#error", ""); return '\n'; @@ -739,8 +767,13 @@ int TPpContext::CPPpragma(TPpToken* ppToken) case PpAtomConstUint: case PpAtomConstInt64: case PpAtomConstUint64: +#ifdef AMD_EXTENSIONS + case PpAtomConstInt16: + case PpAtomConstUint16: +#endif case PpAtomConstFloat: case PpAtomConstDouble: + case PpAtomConstFloat16: tokens.push_back(ppToken->name); break; default: @@ -756,7 +789,7 @@ int TPpContext::CPPpragma(TPpToken* ppToken) else parseContext.handlePragma(loc, tokens); - return token; + return token; } // #version: This is just for error checking: the version and profile are decided before preprocessing starts @@ -764,8 +797,12 @@ int TPpContext::CPPversion(TPpToken* ppToken) { int token = scanToken(ppToken); - if (errorOnVersion || versionSeen) - parseContext.ppError(ppToken->loc, "must occur first in shader", "#version", ""); + if (errorOnVersion || versionSeen) { + if (parseContext.isReadingHLSL()) + parseContext.ppError(ppToken->loc, "invalid preprocessor command", "#version", ""); + else + parseContext.ppError(ppToken->loc, "must occur first in shader", "#version", ""); + } versionSeen = true; if (token == '\n') { @@ -786,9 +823,10 @@ int TPpContext::CPPversion(TPpToken* ppToken) parseContext.notifyVersion(line, versionNumber, nullptr); return token; } else { - if (ppToken->atom != PpAtomCore && - ppToken->atom != PpAtomCompatibility && - ppToken->atom != PpAtomEs) + int profileAtom = atomStrings.getAtom(ppToken->name); + if (profileAtom != PpAtomCore && + profileAtom != PpAtomCompatibility && + profileAtom != PpAtomEs) parseContext.ppError(ppToken->loc, "bad profile name; use es, core, or compatibility", "#version", ""); parseContext.notifyVersion(line, versionNumber, ppToken->name); token = scanToken(ppToken); @@ -849,32 +887,32 @@ int TPpContext::readCPPline(TPpToken* ppToken) int token = scanToken(ppToken); if (token == PpAtomIdentifier) { - switch (ppToken->atom) { + switch (atomStrings.getAtom(ppToken->name)) { case PpAtomDefine: token = CPPdefine(ppToken); break; case PpAtomElse: - if (elsetracker[elseSeen]) + if (elseSeen[elsetracker]) parseContext.ppError(ppToken->loc, "#else after #else", "#else", ""); - elsetracker[elseSeen] = true; - if (! ifdepth) + elseSeen[elsetracker] = true; + if (ifdepth == 0) parseContext.ppError(ppToken->loc, "mismatched statements", "#else", ""); token = extraTokenCheck(PpAtomElse, ppToken, scanToken(ppToken)); token = CPPelse(0, ppToken); break; case PpAtomElif: - if (! ifdepth) + if (ifdepth == 0) parseContext.ppError(ppToken->loc, "mismatched statements", "#elif", ""); if (elseSeen[elsetracker]) parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", ""); // this token is really a dont care, but we still need to eat the tokens - token = scanToken(ppToken); + token = scanToken(ppToken); while (token != '\n' && token != EndOfInput) token = scanToken(ppToken); token = CPPelse(0, ppToken); break; case PpAtomEndif: - if (! ifdepth) + if (ifdepth == 0) parseContext.ppError(ppToken->loc, "mismatched statements", "#endif", ""); else { elseSeen[elsetracker] = false; @@ -893,7 +931,9 @@ int TPpContext::readCPPline(TPpToken* ppToken) token = CPPifdef(0, ppToken); break; case PpAtomInclude: - parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_include_directive, "#include"); + if(!parseContext.isReadingHLSL()) { + parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_include_directive, "#include"); + } token = CPPinclude(ppToken); break; case PpAtomLine: @@ -927,52 +967,128 @@ int TPpContext::readCPPline(TPpToken* ppToken) return token; } -TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream* a, TPpToken* ppToken, bool newLineOkay) +// Context-dependent parsing of a #include . +// Assumes no macro expansions etc. are being done; the name is just on the current input. +// Always creates a name and returns PpAtomicConstString, unless we run out of input. +int TPpContext::scanHeaderName(TPpToken* ppToken, char delimit) { - int token; - TokenStream *n; - RewindTokenStream(a); + bool tooLong = false; + + if (inputStack.empty()) + return EndOfInput; + + int len = 0; + ppToken->name[0] = '\0'; do { - token = ReadToken(a, ppToken); - if (token == PpAtomIdentifier && LookUpSymbol(ppToken->atom)) - break; - } while (token != EndOfInput); + int ch = inputStack.back()->getch(); - if (token == EndOfInput) - return a; + // done yet? + if (ch == delimit) { + ppToken->name[len] = '\0'; + if (tooLong) + parseContext.ppError(ppToken->loc, "header name too long", "", ""); + return PpAtomConstString; + } else if (ch == EndOfInput) + return EndOfInput; - n = new TokenStream; - pushInput(new tMarkerInput(this)); - pushTokenStreamInput(a); - while ((token = scanToken(ppToken)) != tMarkerInput::marker) { - if (token == PpAtomIdentifier && MacroExpand(ppToken->atom, ppToken, false, newLineOkay) != 0) - continue; - RecordToken(n, token, ppToken); - } - popInput(); - delete a; - - return n; + // found a character to expand the name with + if (len < MaxTokenLength) + ppToken->name[len++] = (char)ch; + else + tooLong = true; + } while (true); } -// -// Return the next token for a macro expansion, handling macro args. +// Macro-expand a macro argument 'arg' to create 'expandedArg'. +// Does not replace 'arg'. +// Returns nullptr if no expanded argument is created. +TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream& arg, TPpToken* ppToken, bool newLineOkay) +{ + // expand the argument + TokenStream* expandedArg = new TokenStream; + pushInput(new tMarkerInput(this)); + pushTokenStreamInput(arg); + int token; + while ((token = scanToken(ppToken)) != tMarkerInput::marker && token != EndOfInput) { + token = tokenPaste(token, *ppToken); + if (token == tMarkerInput::marker || token == EndOfInput) + break; + if (token == PpAtomIdentifier && MacroExpand(ppToken, false, newLineOkay) != 0) + continue; + expandedArg->putToken(token, ppToken); + } + + if (token == EndOfInput) { + // MacroExpand ate the marker, so had bad input, recover + delete expandedArg; + expandedArg = nullptr; + } else { + // remove the marker + popInput(); + } + + return expandedArg; +} + +// +// Return the next token for a macro expansion, handling macro arguments, +// whose semantics are dependent on being adjacent to ##. // int TPpContext::tMacroInput::scan(TPpToken* ppToken) { int token; do { - token = pp->ReadToken(mac->body, ppToken); + token = mac->body.getToken(pp->parseContext, ppToken); } while (token == ' '); // handle white space in macro + // Hash operators basically turn off a round of macro substitution + // (the round done on the argument before the round done on the RHS of the + // macro definition): + // + // "A parameter in the replacement list, unless preceded by a # or ## + // preprocessing token or followed by a ## preprocessing token (see below), + // is replaced by the corresponding argument after all macros contained + // therein have been expanded." + // + // "If, in the replacement list, a parameter is immediately preceded or + // followed by a ## preprocessing token, the parameter is replaced by the + // corresponding argument's preprocessing token sequence." + + bool pasting = false; + if (postpaste) { + // don't expand next token + pasting = true; + postpaste = false; + } + + if (prepaste) { + // already know we should be on a ##, verify + assert(token == PpAtomPaste); + prepaste = false; + postpaste = true; + } + + // see if are preceding a ## + if (mac->body.peekUntokenizedPasting()) { + prepaste = true; + pasting = true; + } + + // HLSL does expand macros before concatenation + if (pasting && pp->parseContext.isReadingHLSL()) + pasting = false; + // TODO: preprocessor: properly handle whitespace (or lack of it) between tokens when expanding if (token == PpAtomIdentifier) { int i; - for (i = mac->argc - 1; i >= 0; i--) - if (mac->args[i] == ppToken->atom) + for (i = (int)mac->args.size() - 1; i >= 0; i--) + if (strcmp(pp->atomStrings.getString(mac->args[i]), ppToken->name) == 0) break; if (i >= 0) { - pp->pushTokenStreamInput(args[i]); + TokenStream* arg = expandedArgs[i]; + if (arg == nullptr || pasting) + arg = args[i]; + pp->pushTokenStreamInput(*arg, prepaste); return pp->scanToken(ppToken); } @@ -980,7 +1096,7 @@ int TPpContext::tMacroInput::scan(TPpToken* ppToken) if (token == EndOfInput) mac->busy = 0; - + return token; } @@ -999,17 +1115,18 @@ int TPpContext::tZeroInput::scan(TPpToken* ppToken) } // -// Check an identifier (atom) to see if it is a macro that should be expanded. +// Check a token to see if it is a macro that should be expanded. // If it is, and defined, push a tInput that will produce the appropriate expansion // and return 1. -// If it is, but undefined, and expandUndef is requested, push a tInput that will +// If it is, but undefined, and expandUndef is requested, push a tInput that will // expand to 0 and return -1. // Otherwise, return 0 to indicate no expansion, which is not necessarily an error. // -int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool newLineOkay) +int TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay) { ppToken->space = false; - switch (atom) { + int macroAtom = atomStrings.getAtom(ppToken->name); + switch (macroAtom) { case PpAtomLineMacro: ppToken->ival = parseContext.getCurrentLoc().line; snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival); @@ -1035,20 +1152,19 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool break; } - Symbol *sym = LookUpSymbol(atom); - int token; + MacroSymbol* macro = macroAtom == 0 ? nullptr : lookupMacroDef(macroAtom); int depth = 0; // no recursive expansions - if (sym && sym->mac.busy) + if (macro != nullptr && macro->busy) return 0; // not expanding undefined macros - if ((! sym || sym->mac.undef) && ! expandUndef) + if ((macro == nullptr || macro->undef) && ! expandUndef) return 0; // 0 is the value of an undefined macro - if ((! sym || sym->mac.undef) && expandUndef) { + if ((macro == nullptr || macro->undef) && expandUndef) { pushInput(new tZeroInput(this)); return -1; } @@ -1056,49 +1172,49 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool tMacroInput *in = new tMacroInput(this); TSourceLoc loc = ppToken->loc; // in case we go to the next line before discovering the error - in->mac = &sym->mac; - if (sym->mac.args) { - token = scanToken(ppToken); + in->mac = macro; + if (macro->args.size() > 0 || macro->emptyArgs) { + int token = scanToken(ppToken); if (newLineOkay) { - while (token == '\n') + while (token == '\n') token = scanToken(ppToken); } if (token != '(') { - parseContext.ppError(loc, "expected '(' following", "macro expansion", GetAtomString(atom)); UngetToken(token, ppToken); - ppToken->atom = atom; - delete in; return 0; } - in->args.resize(in->mac->argc); - for (int i = 0; i < in->mac->argc; i++) + in->args.resize(in->mac->args.size()); + for (size_t i = 0; i < in->mac->args.size(); i++) in->args[i] = new TokenStream; - int arg = 0; + in->expandedArgs.resize(in->mac->args.size()); + for (size_t i = 0; i < in->mac->args.size(); i++) + in->expandedArgs[i] = nullptr; + size_t arg = 0; bool tokenRecorded = false; do { depth = 0; while (1) { token = scanToken(ppToken); - if (token == EndOfInput) { - parseContext.ppError(loc, "End of input in macro", "macro expansion", GetAtomString(atom)); + if (token == EndOfInput || token == tMarkerInput::marker) { + parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom)); delete in; return 0; } if (token == '\n') { if (! newLineOkay) { - parseContext.ppError(loc, "End of line in macro substitution:", "macro expansion", GetAtomString(atom)); + parseContext.ppError(loc, "End of line in macro substitution:", "macro expansion", atomStrings.getString(macroAtom)); delete in; return 0; } continue; } if (token == '#') { - parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", GetAtomString(atom)); + parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", atomStrings.getString(macroAtom)); delete in; return 0; } - if (in->mac->argc == 0 && token != ')') + if (in->mac->args.size() == 0 && token != ')') break; if (depth == 0 && (token == ',' || token == ')')) break; @@ -1106,20 +1222,20 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool depth++; if (token == ')') depth--; - RecordToken(in->args[arg], token, ppToken); + in->args[arg]->putToken(token, ppToken); tokenRecorded = true; } if (token == ')') { - if (in->mac->argc == 1 && tokenRecorded == 0) + if (in->mac->args.size() == 1 && tokenRecorded == 0) break; arg++; break; } arg++; - } while (arg < in->mac->argc); + } while (arg < in->mac->args.size()); - if (arg < in->mac->argc) - parseContext.ppError(loc, "Too few args in Macro", "macro expansion", GetAtomString(atom)); + if (arg < in->mac->args.size()) + parseContext.ppError(loc, "Too few args in Macro", "macro expansion", atomStrings.getString(macroAtom)); else if (token != ')') { depth=0; while (token != EndOfInput && (depth > 0 || token != ')')) { @@ -1131,19 +1247,22 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool } if (token == EndOfInput) { - parseContext.ppError(loc, "End of input in macro", "macro expansion", GetAtomString(atom)); + parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom)); delete in; return 0; } - parseContext.ppError(loc, "Too many args in macro", "macro expansion", GetAtomString(atom)); + parseContext.ppError(loc, "Too many args in macro", "macro expansion", atomStrings.getString(macroAtom)); } - for (int i = 0; i < in->mac->argc; i++) - in->args[i] = PrescanMacroArg(in->args[i], ppToken, newLineOkay); + + // We need both expanded and non-expanded forms of the argument, for whether or + // not token pasting will be applied later when the argument is consumed next to ##. + for (size_t i = 0; i < in->mac->args.size(); i++) + in->expandedArgs[i] = PrescanMacroArg(*in->args[i], ppToken, newLineOkay); } pushInput(in); - sym->mac.busy = 1; - RewindTokenStream(sym->mac.body); + macro->busy = 1; + macro->body.reset(); return 1; } diff --git a/Externals/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp b/Externals/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp index 763b6b4e67..06c2333ef1 100644 --- a/Externals/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp +++ b/Externals/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp @@ -1,11 +1,11 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2013 LunarG, Inc. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2013 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: +// 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. @@ -19,18 +19,18 @@ // 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. +// 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. // /****************************************************************************\ Copyright (c) 2002, NVIDIA Corporation. @@ -57,7 +57,7 @@ Except as expressly stated in this notice, no other rights or licenses express or implied, are granted by NVIDIA herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the NVIDIA Software may be -incorporated. No hardware is licensed hereunder. +incorporated. No hardware is licensed hereunder. THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, @@ -76,16 +76,13 @@ TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \****************************************************************************/ -// -// atom.c -// - +#ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS +#endif -#include -#include -#include -#include +#include +#include +#include #include "PpContext.h" #include "PpTokens.h" @@ -98,8 +95,36 @@ const struct { int val; const char* str; } tokens[] = { + + { PPAtomAddAssign, "+=" }, + { PPAtomSubAssign, "-=" }, + { PPAtomMulAssign, "*=" }, + { PPAtomDivAssign, "/=" }, + { PPAtomModAssign, "%=" }, + + { PpAtomRight, ">>" }, + { PpAtomLeft, "<<" }, + { PpAtomAnd, "&&" }, + { PpAtomOr, "||" }, + { PpAtomXor, "^^" }, + + { PpAtomRightAssign, ">>=" }, + { PpAtomLeftAssign, "<<=" }, + { PpAtomAndAssign, "&=" }, + { PpAtomOrAssign, "|=" }, + { PpAtomXorAssign, "^=" }, + + { PpAtomEQ, "==" }, + { PpAtomNE, "!=" }, + { PpAtomGE, ">=" }, + { PpAtomLE, "<=" }, + + { PpAtomDecrement, "--" }, + { PpAtomIncrement, "++" }, + + { PpAtomColonColon, "::" }, + { PpAtomDefine, "define" }, - { PpAtomDefined, "defined" }, { PpAtomUndef, "undef" }, { PpAtomIf, "if" }, { PpAtomElif, "elif" }, @@ -121,56 +146,20 @@ const struct { { PpAtomFileMacro, "__FILE__" }, { PpAtomVersionMacro, "__VERSION__" }, - { PpAtomInclude, "include" }, - + { PpAtomInclude, "include" }, }; } // end anonymous namespace namespace glslang { -// -// Map a new or existing string to an atom, inventing a new atom if necessary. -// -int TPpContext::LookUpAddString(const char* s) -{ - auto it = atomMap.find(s); - if (it == atomMap.end()) { - AddAtomFixed(s, nextAtom); - return nextAtom++; - } else - return it->second; -} - -// -// Map an already created atom to its string. -// -const char* TPpContext::GetAtomString(int atom) -{ - if ((size_t)atom >= stringMap.size()) - return ""; - - const TString* atomString = stringMap[atom]; - - return atomString ? atomString->c_str() : ""; -} - -// -// Add forced mapping of string to atom. -// -void TPpContext::AddAtomFixed(const char* s, int atom) -{ - auto it = atomMap.insert(std::pair(s, atom)).first; - if (stringMap.size() < (size_t)atom + 1) - stringMap.resize(atom + 100, 0); - stringMap[atom] = &it->first; -} - // // Initialize the atom table. // -void TPpContext::InitAtomTable() +TStringAtomMap::TStringAtomMap() { + badToken.assign(""); + // Add single character tokens to the atom table: const char* s = "~!%^&*()-+=|,.<>/?;:[]{}#\\"; char t[2]; @@ -178,13 +167,13 @@ void TPpContext::InitAtomTable() t[1] = '\0'; while (*s) { t[0] = *s; - AddAtomFixed(t, s[0]); + addAtomFixed(t, s[0]); s++; } // Add multiple character scanner tokens : for (size_t ii = 0; ii < sizeof(tokens)/sizeof(tokens[0]); ii++) - AddAtomFixed(tokens[ii].str, tokens[ii].val); + addAtomFixed(tokens[ii].str, tokens[ii].val); nextAtom = PpAtomLast; } diff --git a/Externals/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp b/Externals/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp old mode 100644 new mode 100755 index 6f0b8a9a11..c89b37688a --- a/Externals/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp +++ b/Externals/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp @@ -1,11 +1,11 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2013 LunarG, Inc. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2013 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: +// 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. @@ -19,18 +19,18 @@ // 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. +// 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. // /****************************************************************************\ Copyright (c) 2002, NVIDIA Corporation. @@ -57,7 +57,7 @@ Except as expressly stated in this notice, no other rights or licenses express or implied, are granted by NVIDIA herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the NVIDIA Software may be -incorporated. No hardware is licensed hereunder. +incorporated. No hardware is licensed hereunder. THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, @@ -76,32 +76,28 @@ TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \****************************************************************************/ -#include -#include +#include +#include #include "PpContext.h" namespace glslang { -TPpContext::TPpContext(TParseContextBase& pc, const std::string& rootFileName, TShader::Includer& inclr) : - preamble(0), strings(0), parseContext(pc), includer(inclr), inComment(false), +TPpContext::TPpContext(TParseContextBase& pc, const std::string& rootFileName, TShader::Includer& inclr) : + preamble(0), strings(0), previous_token('\n'), parseContext(pc), includer(inclr), inComment(false), rootFileName(rootFileName), currentSourceFile(rootFileName) { - InitAtomTable(); - InitScanner(); - ifdepth = 0; for (elsetracker = 0; elsetracker < maxIfNesting; elsetracker++) elseSeen[elsetracker] = false; elsetracker = 0; + + strtodStream.imbue(std::locale::classic()); } TPpContext::~TPpContext() { - for (TSymbolMap::iterator it = symbols.begin(); it != symbols.end(); ++it) - delete it->second->mac.body; - mem_FreePool(pool); delete [] preamble; // free up the inputStack diff --git a/Externals/glslang/glslang/MachineIndependent/preprocessor/PpContext.h b/Externals/glslang/glslang/MachineIndependent/preprocessor/PpContext.h old mode 100644 new mode 100755 index 23021e24e0..b3a39c5cbc --- a/Externals/glslang/glslang/MachineIndependent/preprocessor/PpContext.h +++ b/Externals/glslang/glslang/MachineIndependent/preprocessor/PpContext.h @@ -1,10 +1,10 @@ // -//Copyright (C) 2013 LunarG, Inc. -//All rights reserved. +// Copyright (C) 2013 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: +// 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. @@ -18,18 +18,18 @@ // 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. +// 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. // /****************************************************************************\ Copyright (c) 2002, NVIDIA Corporation. @@ -56,7 +56,7 @@ Except as expressly stated in this notice, no other rights or licenses express or implied, are granted by NVIDIA herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the NVIDIA Software may be -incorporated. No hardware is licensed hereunder. +incorporated. No hardware is licensed hereunder. THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, @@ -80,6 +80,7 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include "../ParseHelper.h" @@ -92,28 +93,92 @@ namespace glslang { class TPpToken { public: - TPpToken() : token(0), space(false), ival(0), dval(0.0), atom(0) + TPpToken() { clear(); } + void clear() { - loc.init(); + space = false; + i64val = 0; + loc.init(); name[0] = 0; } + // Used for comparing macro definitions, so checks what is relevant for that. bool operator==(const TPpToken& right) { - return token == right.token && atom == right.atom && - ival == right.ival && dval == right.dval && - strcmp(name, right.name) == 0; + return space == right.space && + ival == right.ival && dval == right.dval && i64val == right.i64val && + strncmp(name, right.name, MaxTokenLength) == 0; } bool operator!=(const TPpToken& right) { return ! operator==(right); } TSourceLoc loc; - int token; - bool space; // true if a space (for white space or a removed comment) should also be recognized, in front of the token returned - int ival; - double dval; - long long i64val; - int atom; - char name[MaxTokenLength + 1]; + // True if a space (for white space or a removed comment) should also be + // recognized, in front of the token returned: + bool space; + // Numeric value of the token: + union { + int ival; + double dval; + long long i64val; + }; + // Text string of the token: + char name[MaxTokenLength + 1]; +}; + +class TStringAtomMap { +// +// Implementation is in PpAtom.cpp +// +// Maintain a bi-directional mapping between relevant preprocessor strings and +// "atoms" which a unique integers (small, contiguous, not hash-like) per string. +// +public: + TStringAtomMap(); + + // Map string -> atom. + // Return 0 if no existing string. + int getAtom(const char* s) const + { + auto it = atomMap.find(s); + return it == atomMap.end() ? 0 : it->second; + } + + // Map a new or existing string -> atom, inventing a new atom if necessary. + int getAddAtom(const char* s) + { + int atom = getAtom(s); + if (atom == 0) { + atom = nextAtom++; + addAtomFixed(s, atom); + } + return atom; + } + + // Map atom -> string. + const char* getString(int atom) const { return stringMap[atom]->c_str(); } + +protected: + TStringAtomMap(TStringAtomMap&); + TStringAtomMap& operator=(TStringAtomMap&); + + TUnorderedMap atomMap; + TVector stringMap; // these point into the TString in atomMap + int nextAtom; + + // Bad source characters can lead to bad atoms, so gracefully handle those by + // pre-filling the table with them (to avoid if tests later). + TString badToken; + + // Add bi-directional mappings: + // - string -> atom + // - atom -> string + void addAtomFixed(const char* s, int atom) + { + auto it = atomMap.insert(std::pair(s, atom)).first; + if (stringMap.size() < (size_t)atom + 1) + stringMap.resize(atom + 100, &badToken); + stringMap[atom] = &it->first; + } }; class TInputScanner; @@ -128,7 +193,8 @@ public: void setPreamble(const char* preamble, size_t length); - const char* tokenize(TPpToken* ppToken); + int tokenize(TPpToken& ppToken); + int tokenPaste(int token, TPpToken&); class tInput { public: @@ -138,6 +204,9 @@ public: virtual int scan(TPpToken*) = 0; virtual int getch() = 0; virtual void ungetch() = 0; + virtual bool peekPasting() { return false; } // true when about to see ## + virtual bool endOfReplacementList() { return false; } // true when at the end of a macro replacement list (RHS of #define) + virtual bool isMacroInput() { return false; } // Will be called when we start reading tokens from this instance virtual void notifyActivated() {} @@ -162,50 +231,57 @@ public: inputStack.pop_back(); } - struct TokenStream { + // + // From PpTokens.cpp + // + + class TokenStream { + public: TokenStream() : current(0) { } + + void putToken(int token, TPpToken* ppToken); + int getToken(TParseContextBase&, TPpToken*); + bool atEnd() { return current >= data.size(); } + bool peekTokenizedPasting(bool lastTokenPastes); + bool peekUntokenizedPasting(); + void reset() { current = 0; } + + protected: + void putSubtoken(char); + int getSubtoken(); + void ungetSubtoken(); + TVector data; size_t current; }; - struct MemoryPool { - struct chunk *next; - uintptr_t free, end; - size_t chunksize; - uintptr_t alignmask; - }; - // // From Pp.cpp // struct MacroSymbol { - MacroSymbol() : argc(0), args(0), body(0), busy(0), undef(0) { } - int argc; - int *args; - TokenStream *body; - unsigned busy:1; - unsigned undef:1; + MacroSymbol() : emptyArgs(0), busy(0), undef(0) { } + TVector args; + TokenStream body; + unsigned emptyArgs : 1; + unsigned busy : 1; + unsigned undef : 1; }; - struct Symbol { - int atom; - MacroSymbol mac; - }; - - struct SymbolList { - struct SymbolList_Rec *next; - Symbol *symb; - }; - - MemoryPool *pool; - typedef TMap TSymbolMap; - TSymbolMap symbols; // this has light use... just defined macros + typedef TMap TSymbolMap; + TSymbolMap macroDefs; // map atoms to macro definitions + MacroSymbol* lookupMacroDef(int atom) + { + auto existingMacroIt = macroDefs.find(atom); + return (existingMacroIt == macroDefs.end()) ? nullptr : &(existingMacroIt->second); + } + void addMacroDef(int atom, MacroSymbol& macroDef) { macroDefs[atom] = macroDef; } protected: TPpContext(TPpContext&); TPpContext& operator=(TPpContext&); + TStringAtomMap atomStrings; char* preamble; // string to parse, all before line 1 of string 0, it is 0 if no preamble int preambleLength; char** strings; // official strings of shader, starting a string 0 line 1 @@ -218,7 +294,7 @@ protected: TParseContextBase& parseContext; // Get the next token from *stack* of input sources, popping input sources - // that are out of tokens, down until an input sources is found that has a token. + // that are out of tokens, down until an input source is found that has a token. // Return EndOfInput when there are no more tokens to be found by doing this. int scanToken(TPpToken* ppToken) { @@ -226,7 +302,7 @@ protected: while (! inputStack.empty()) { token = inputStack.back()->scan(ppToken); - if (token != EndOfInput) + if (token != EndOfInput || inputStack.empty()) break; popInput(); } @@ -235,34 +311,47 @@ protected: } int getChar() { return inputStack.back()->getch(); } void ungetChar() { inputStack.back()->ungetch(); } + bool peekPasting() { return !inputStack.empty() && inputStack.back()->peekPasting(); } + bool endOfReplacementList() { return inputStack.empty() || inputStack.back()->endOfReplacementList(); } + bool isMacroInput() { return inputStack.size() > 0 && inputStack.back()->isMacroInput(); } - static const int maxMacroArgs = 64; - static const int maxIfNesting = 64; + static const int maxIfNesting = 65; - int ifdepth; // current #if-#else-#endif nesting in the cpp.c file (pre-processor) + int ifdepth; // current #if-#else-#endif nesting in the cpp.c file (pre-processor) bool elseSeen[maxIfNesting]; // Keep a track of whether an else has been seen at a particular depth int elsetracker; // #if-#else and #endif constructs...Counter. class tMacroInput : public tInput { public: - tMacroInput(TPpContext* pp) : tInput(pp) { } + tMacroInput(TPpContext* pp) : tInput(pp), prepaste(false), postpaste(false) { } virtual ~tMacroInput() { for (size_t i = 0; i < args.size(); ++i) delete args[i]; + for (size_t i = 0; i < expandedArgs.size(); ++i) + delete expandedArgs[i]; } - virtual int scan(TPpToken*); - virtual int getch() { assert(0); return EndOfInput; } - virtual void ungetch() { assert(0); } + virtual int scan(TPpToken*) override; + virtual int getch() override { assert(0); return EndOfInput; } + virtual void ungetch() override { assert(0); } + bool peekPasting() override { return prepaste; } + bool endOfReplacementList() override { return mac->body.atEnd(); } + bool isMacroInput() override { return true; } + MacroSymbol *mac; TVector args; + TVector expandedArgs; + + protected: + bool prepaste; // true if we are just before ## + bool postpaste; // true if we are right after ## }; class tMarkerInput : public tInput { public: tMarkerInput(TPpContext* pp) : tInput(pp) { } - virtual int scan(TPpToken*) + virtual int scan(TPpToken*) override { if (done) return EndOfInput; @@ -270,17 +359,17 @@ protected: return marker; } - virtual int getch() { assert(0); return EndOfInput; } - virtual void ungetch() { assert(0); } + virtual int getch() override { assert(0); return EndOfInput; } + virtual void ungetch() override { assert(0); } static const int marker = -3; }; class tZeroInput : public tInput { public: tZeroInput(TPpContext* pp) : tInput(pp) { } - virtual int scan(TPpToken*); - virtual int getch() { assert(0); return EndOfInput; } - virtual void ungetch() { assert(0); } + virtual int scan(TPpToken*) override; + virtual int getch() override { assert(0); return EndOfInput; } + virtual void ungetch() override { assert(0); } }; std::vector inputStack; @@ -294,60 +383,49 @@ protected: // Used to obtain #include content. TShader::Includer& includer; - int InitCPP(); int CPPdefine(TPpToken * ppToken); int CPPundef(TPpToken * ppToken); int CPPelse(int matchelse, TPpToken * ppToken); int extraTokenCheck(int atom, TPpToken* ppToken, int token); int eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken * ppToken); int evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken * ppToken); - int CPPif (TPpToken * ppToken); + int CPPif (TPpToken * ppToken); int CPPifdef(int defined, TPpToken * ppToken); int CPPinclude(TPpToken * ppToken); - int CPPline(TPpToken * ppToken); - int CPPerror(TPpToken * ppToken); + int CPPline(TPpToken * ppToken); + int CPPerror(TPpToken * ppToken); int CPPpragma(TPpToken * ppToken); int CPPversion(TPpToken * ppToken); int CPPextension(TPpToken * ppToken); int readCPPline(TPpToken * ppToken); - TokenStream* PrescanMacroArg(TokenStream *a, TPpToken * ppToken, bool newLineOkay); - int MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool newLineOkay); - - // - // from PpSymbols.cpp - // - Symbol *NewSymbol(int name); - Symbol *AddSymbol(int atom); - Symbol *LookUpSymbol(int atom); + int scanHeaderName(TPpToken* ppToken, char delimit); + TokenStream* PrescanMacroArg(TokenStream&, TPpToken*, bool newLineOkay); + int MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay); // // From PpTokens.cpp // - void lAddByte(TokenStream *fTok, unsigned char fVal); - int lReadByte(TokenStream *pTok); - void lUnreadByte(TokenStream *pTok); - void RecordToken(TokenStream* pTok, int token, TPpToken* ppToken); - void RewindTokenStream(TokenStream *pTok); - int ReadToken(TokenStream* pTok, TPpToken* ppToken); - void pushTokenStreamInput(TokenStream *ts); - void UngetToken(int token, TPpToken* ppToken); - + void pushTokenStreamInput(TokenStream&, bool pasting = false); + void UngetToken(int token, TPpToken*); + class tTokenInput : public tInput { public: - tTokenInput(TPpContext* pp, TokenStream* t) : tInput(pp), tokens(t) { } - virtual int scan(TPpToken *); - virtual int getch() { assert(0); return EndOfInput; } - virtual void ungetch() { assert(0); } + tTokenInput(TPpContext* pp, TokenStream* t, bool prepasting) : tInput(pp), tokens(t), lastTokenPastes(prepasting) { } + virtual int scan(TPpToken *ppToken) override { return tokens->getToken(pp->parseContext, ppToken); } + virtual int getch() override { assert(0); return EndOfInput; } + virtual void ungetch() override { assert(0); } + virtual bool peekPasting() override { return tokens->peekTokenizedPasting(lastTokenPastes); } protected: - TokenStream *tokens; + TokenStream* tokens; + bool lastTokenPastes; // true if the last token in the input is to be pasted, rather than consumed as a token }; class tUngotTokenInput : public tInput { public: tUngotTokenInput(TPpContext* pp, int t, TPpToken* p) : tInput(pp), token(t), lval(*p) { } - virtual int scan(TPpToken *); - virtual int getch() { assert(0); return EndOfInput; } - virtual void ungetch() { assert(0); } + virtual int scan(TPpToken *) override; + virtual int getch() override { assert(0); return EndOfInput; } + virtual void ungetch() override { assert(0); } protected: int token; TPpToken lval; @@ -359,12 +437,12 @@ protected: class tStringInput : public tInput { public: tStringInput(TPpContext* pp, TInputScanner& i) : tInput(pp), input(&i) { } - virtual int scan(TPpToken*); + virtual int scan(TPpToken*) override; // Scanner used to get source stream characters. // - Escaped newlines are handled here, invisibly to the caller. // - All forms of newline are handled, and turned into just a '\n'. - int getch() + int getch() override { int ch = input->get(); @@ -387,7 +465,7 @@ protected: return '\\'; } while (ch == '\\'); } - + // handle any non-escaped newline if (ch == '\r' || ch == '\n') { if (ch == '\r' && input->peek() == '\n') @@ -402,7 +480,7 @@ protected: // handled here, invisibly to the caller, meaning have to undo exactly // what getch() above does (e.g., don't leave things in the middle of a // sequence of escaped newlines). - void ungetch() + void ungetch() override { input->unget(); @@ -432,7 +510,7 @@ protected: TInputScanner* input; }; - // Holds a reference to included file data, as well as a + // Holds a reference to included file data, as well as a // prologue and an epilogue string. This can be scanned using the tInput // interface and acts as a single source string. class TokenizableIncludeFile : public tInput { @@ -446,18 +524,18 @@ protected: TPpContext* pp) : tInput(pp), prologue_(prologue), - includedFile_(includedFile), epilogue_(epilogue), + includedFile_(includedFile), scanner(3, strings, lengths, names, 0, 0, true), prevScanner(nullptr), stringInput(pp, scanner) { strings[0] = prologue_.data(); - strings[1] = includedFile_->file_data; + strings[1] = includedFile_->headerData; strings[2] = epilogue_.data(); lengths[0] = prologue_.size(); - lengths[1] = includedFile_->file_length; + lengths[1] = includedFile_->headerLength; lengths[2] = epilogue_.size(); scanner.setLine(startLoc.line); @@ -498,7 +576,7 @@ protected: // Points to the IncludeResult that this TokenizableIncludeFile represents. TShader::Includer::IncludeResult* includedFile_; - // Will point to prologue_, includedFile_->file_data and epilogue_ + // Will point to prologue_, includedFile_->headerData and epilogue_ // This is passed to scanner constructor. // These do not own the storage and it must remain valid until this // object has been destroyed. @@ -516,14 +594,14 @@ protected: tStringInput stringInput; }; - int InitScanner(); int ScanFromString(char* s); void missingEndifCheck(); int lFloatConst(int len, int ch, TPpToken* ppToken); + int characterLiteral(TPpToken* ppToken); void push_include(TShader::Includer::IncludeResult* result) { - currentSourceFile = result->file_name; + currentSourceFile = result->headerName; includeStack.push(result); } @@ -535,36 +613,16 @@ protected: if (includeStack.empty()) { currentSourceFile = rootFileName; } else { - currentSourceFile = includeStack.top()->file_name; + currentSourceFile = includeStack.top()->headerName; } } bool inComment; - - // - // From PpAtom.cpp - // - typedef TUnorderedMap TAtomMap; - typedef TVector TStringMap; - - TAtomMap atomMap; - TStringMap stringMap; + std::string rootFileName; std::stack includeStack; std::string currentSourceFile; - std::string rootFileName; - int nextAtom; - void InitAtomTable(); - void AddAtomFixed(const char* s, int atom); - int LookUpAddString(const char* s); - const char* GetAtomString(int atom); - // - // From PpMemory.cpp - // - MemoryPool *mem_CreatePool(size_t chunksize, unsigned align); - void mem_FreePool(MemoryPool*); - void *mem_Alloc(MemoryPool* p, size_t size); - int mem_AddCleanup(MemoryPool* p, void (*fn)(void *, void*), void* arg1, void* arg2); + std::istringstream strtodStream; }; } // end namespace glslang diff --git a/Externals/glslang/glslang/MachineIndependent/preprocessor/PpMemory.cpp b/Externals/glslang/glslang/MachineIndependent/preprocessor/PpMemory.cpp deleted file mode 100644 index 57a49fb893..0000000000 --- a/Externals/glslang/glslang/MachineIndependent/preprocessor/PpMemory.cpp +++ /dev/null @@ -1,162 +0,0 @@ -// -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2013 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. -// -/****************************************************************************\ -Copyright (c) 2002, NVIDIA Corporation. - -NVIDIA Corporation("NVIDIA") supplies this software to you in -consideration of your agreement to the following terms, and your use, -installation, modification or redistribution of this NVIDIA software -constitutes acceptance of these terms. If you do not agree with these -terms, please do not use, install, modify or redistribute this NVIDIA -software. - -In consideration of your agreement to abide by the following terms, and -subject to these terms, NVIDIA grants you a personal, non-exclusive -license, under NVIDIA's copyrights in this original NVIDIA software (the -"NVIDIA Software"), to use, reproduce, modify and redistribute the -NVIDIA Software, with or without modifications, in source and/or binary -forms; provided that if you redistribute the NVIDIA Software, you must -retain the copyright notice of NVIDIA, this notice and the following -text and disclaimers in all such redistributions of the NVIDIA Software. -Neither the name, trademarks, service marks nor logos of NVIDIA -Corporation may be used to endorse or promote products derived from the -NVIDIA Software without specific prior written permission from NVIDIA. -Except as expressly stated in this notice, no other rights or licenses -express or implied, are granted by NVIDIA herein, including but not -limited to any patent rights that may be infringed by your derivative -works or by other works in which the NVIDIA Software may be -incorporated. No hardware is licensed hereunder. - -THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT -WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, -INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, -NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR -ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER -PRODUCTS. - -IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, -INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY -OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE -NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, -TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF -NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -\****************************************************************************/ - -#include -#include -#include -#include - -#include "PpContext.h" - -// default alignment and chunksize, if called with 0 arguments -#define CHUNKSIZE (64*1024) -#define ALIGN 8 - -namespace glslang { - -struct chunk { - struct chunk *next; -}; - -TPpContext::MemoryPool* TPpContext::mem_CreatePool(size_t chunksize, unsigned int align) -{ - if (align == 0) - align = ALIGN; - if (chunksize == 0) - chunksize = CHUNKSIZE; - if (align & (align - 1)) - return nullptr; - if (chunksize < sizeof(MemoryPool)) - return nullptr; - if (chunksize & (align - 1)) - return nullptr; - - MemoryPool *pool = (MemoryPool*)malloc(chunksize); - if (! pool) - return nullptr; - - pool->next = 0; - pool->chunksize = chunksize; - pool->alignmask = (uintptr_t)(align) - 1; - pool->free = ((uintptr_t)(pool + 1) + pool->alignmask) & ~pool->alignmask; - pool->end = (uintptr_t)pool + chunksize; - - return pool; -} - -void TPpContext::mem_FreePool(MemoryPool *pool) -{ - struct chunk *p, *next; - - for (p = (struct chunk *)pool; p; p = next) { - next = p->next; - free(p); - } -} - -void* TPpContext::mem_Alloc(MemoryPool *pool, size_t size) -{ - struct chunk *ch; - void *rv = (void *)pool->free; - size = (size + pool->alignmask) & ~pool->alignmask; - if (size <= 0) size = pool->alignmask; - pool->free += size; - if (pool->free > pool->end || pool->free < (uintptr_t)rv) { - size_t minreq = (size + sizeof(struct chunk) + pool->alignmask) & ~pool->alignmask; - pool->free = (uintptr_t)rv; - if (minreq >= pool->chunksize) { - // request size is too big for the chunksize, so allocate it as - // a single chunk of the right size - ch = (struct chunk*)malloc(minreq); - if (! ch) - return nullptr; - } else { - ch = (struct chunk*)malloc(pool->chunksize); - if (! ch) - return nullptr; - pool->free = (uintptr_t)ch + minreq; - pool->end = (uintptr_t)ch + pool->chunksize; - } - ch->next = pool->next; - pool->next = ch; - rv = (void *)(((uintptr_t)(ch+1) + pool->alignmask) & ~pool->alignmask); - } - return rv; -} - -} // end namespace glslang diff --git a/Externals/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp b/Externals/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp old mode 100644 new mode 100755 index b3d1af6dad..0c620a5f5b --- a/Externals/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp +++ b/Externals/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp @@ -1,11 +1,12 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2013 LunarG, Inc. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2013 LunarG, Inc. +// Copyright (C) 2017 ARM Limited. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,18 +20,18 @@ // 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. +// 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. // /****************************************************************************\ Copyright (c) 2002, NVIDIA Corporation. @@ -57,7 +58,7 @@ Except as expressly stated in this notice, no other rights or licenses express or implied, are granted by NVIDIA herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the NVIDIA Software may be -incorporated. No hardware is licensed hereunder. +incorporated. No hardware is licensed hereunder. THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, @@ -75,16 +76,13 @@ NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \****************************************************************************/ -// -// scanner.c -// +#ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS +#endif -#include -#include -#include -#include +#include +#include #include "PpContext.h" #include "PpTokens.h" @@ -92,17 +90,6 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace glslang { -int TPpContext::InitScanner() -{ - // Add various atoms needed by the CPP line scanner: - if (!InitCPP()) - return 0; - - previous_token = '\n'; - - return 1; -} - /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////// Floating point constants: ///////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// @@ -115,131 +102,345 @@ int TPpContext::InitScanner() int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken) { - bool HasDecimalOrExponent = false; - int declen; - int str_len; - int isDouble = 0; + const auto saveName = [&](int ch) { + if (len <= MaxTokenLength) + ppToken->name[len++] = static_cast(ch); + }; - declen = 0; + // find the range of non-zero digits before the decimal point + int startNonZero = 0; + while (startNonZero < len && ppToken->name[startNonZero] == '0') + ++startNonZero; + int endNonZero = len; + while (endNonZero > startNonZero && ppToken->name[endNonZero-1] == '0') + --endNonZero; + int numWholeNumberDigits = endNonZero - startNonZero; - str_len=len; - char* str = ppToken->name; + // accumulate the range's value + bool fastPath = numWholeNumberDigits <= 15; // when the number gets too complex, set to false + unsigned long long wholeNumber = 0; + if (fastPath) { + for (int i = startNonZero; i < endNonZero; ++i) + wholeNumber = wholeNumber * 10 + (ppToken->name[i] - '0'); + } + int decimalShift = len - endNonZero; + + // Decimal point: + bool hasDecimalOrExponent = false; if (ch == '.') { - HasDecimalOrExponent = true; - str[len++] = (char)ch; + hasDecimalOrExponent = true; + saveName(ch); ch = getChar(); - while (ch >= '0' && ch <= '9') { - if (len < MaxTokenLength) { - declen++; - if (len > 0 || ch != '0') { - str[len] = (char)ch; - len++; - str_len++; + int firstDecimal = len; + + // 1.#INF or -1.#INF + if (ch == '#' && (ifdepth > 0 || parseContext.intermediate.getSource() == EShSourceHlsl)) { + if ((len < 2) || + (len == 2 && ppToken->name[0] != '1') || + (len == 3 && ppToken->name[1] != '1' && !(ppToken->name[0] == '-' || ppToken->name[0] == '+')) || + (len > 3)) + parseContext.ppError(ppToken->loc, "unexpected use of", "#", ""); + else { + // we have 1.# or -1.# or +1.#, check for 'INF' + if ((ch = getChar()) != 'I' || + (ch = getChar()) != 'N' || + (ch = getChar()) != 'F') + parseContext.ppError(ppToken->loc, "expected 'INF'", "#", ""); + else { + // we have [+-].#INF, and we are targeting IEEE 754, so wrap it up: + saveName('I'); + saveName('N'); + saveName('F'); + ppToken->name[len] = '\0'; + if (ppToken->name[0] == '-') + ppToken->i64val = 0xfff0000000000000; // -Infinity + else + ppToken->i64val = 0x7ff0000000000000; // +Infinity + return PpAtomConstFloat; } - ch = getChar(); - } else { - parseContext.ppError(ppToken->loc, "float literal too long", "", ""); - len = 1; - str_len = 1; } } + + // Consume leading-zero digits after the decimal point + while (ch == '0') { + saveName(ch); + ch = getChar(); + } + int startNonZeroDecimal = len; + int endNonZeroDecimal = len; + + // Consume remaining digits, up to the exponent + while (ch >= '0' && ch <= '9') { + saveName(ch); + if (ch != '0') + endNonZeroDecimal = len; + ch = getChar(); + } + + // Compute accumulation up to the last non-zero digit + if (endNonZeroDecimal > startNonZeroDecimal) { + numWholeNumberDigits += endNonZeroDecimal - endNonZero - 1; // don't include the "." + if (numWholeNumberDigits > 15) + fastPath = false; + if (fastPath) { + for (int i = endNonZero; i < endNonZeroDecimal; ++i) { + if (ppToken->name[i] != '.') + wholeNumber = wholeNumber * 10 + (ppToken->name[i] - '0'); + } + } + decimalShift = firstDecimal - endNonZeroDecimal; + } } // Exponent: - - if (ch == 'e' || ch == 'E') { - HasDecimalOrExponent = true; - if (len >= MaxTokenLength) { - parseContext.ppError(ppToken->loc, "float literal too long", "", ""); - len = 1; - str_len = 1; - } else { - str[len++] = (char)ch; + bool negativeExponent = false; + double exponentValue = 0.0; + int exponent = 0; + { + if (ch == 'e' || ch == 'E') { + hasDecimalOrExponent = true; + saveName(ch); ch = getChar(); - if (ch == '+') { - str[len++] = (char)ch; - ch = getChar(); - } else if (ch == '-') { - str[len++] = (char)ch; + if (ch == '+' || ch == '-') { + negativeExponent = ch == '-'; + saveName(ch); ch = getChar(); } if (ch >= '0' && ch <= '9') { while (ch >= '0' && ch <= '9') { - if (len < MaxTokenLength) { - str[len++] = (char)ch; - ch = getChar(); - } else { - parseContext.ppError(ppToken->loc, "float literal too long", "", ""); - len = 1; - str_len = 1; - } + exponent = exponent * 10 + (ch - '0'); + saveName(ch); + ch = getChar(); } } else { parseContext.ppError(ppToken->loc, "bad character in float exponent", "", ""); } } + + // Compensate for location of decimal + if (negativeExponent) + exponent -= decimalShift; + else { + exponent += decimalShift; + if (exponent < 0) { + negativeExponent = true; + exponent = -exponent; + } + } + if (exponent > 22) + fastPath = false; + + if (fastPath) { + // Compute the floating-point value of the exponent + exponentValue = 1.0; + if (exponent > 0) { + double expFactor = 10; + while (exponent > 0) { + if (exponent & 0x1) + exponentValue *= expFactor; + expFactor *= expFactor; + exponent >>= 1; + } + } + } } - if (len == 0) { - ppToken->dval = 0.0; - strcpy(str, "0.0"); - } else { - if (ch == 'l' || ch == 'L') { + // Suffix: + bool isDouble = false; + bool isFloat16 = false; + if (ch == 'l' || ch == 'L') { + if (ifdepth == 0 && parseContext.intermediate.getSource() == EShSourceGlsl) parseContext.doubleCheck(ppToken->loc, "double floating-point suffix"); - if (! HasDecimalOrExponent) - parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", ""); + if (ifdepth == 0 && !hasDecimalOrExponent) + parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", ""); + if (parseContext.intermediate.getSource() == EShSourceGlsl) { int ch2 = getChar(); if (ch2 != 'f' && ch2 != 'F') { ungetChar(); ungetChar(); } else { - if (len < MaxTokenLength) { - str[len++] = (char)ch; - str[len++] = (char)ch2; - isDouble = 1; - } else { - parseContext.ppError(ppToken->loc, "float literal too long", "", ""); - len = 1,str_len=1; - } + saveName(ch); + saveName(ch2); + isDouble = true; } - } else if (ch == 'f' || ch == 'F') { + } else if (parseContext.intermediate.getSource() == EShSourceHlsl) { + saveName(ch); + isDouble = true; + } + } else if (ch == 'h' || ch == 'H') { + if (ifdepth == 0 && parseContext.intermediate.getSource() == EShSourceGlsl) + parseContext.float16Check(ppToken->loc, "half floating-point suffix"); + if (ifdepth == 0 && !hasDecimalOrExponent) + parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", ""); + if (parseContext.intermediate.getSource() == EShSourceGlsl) { + int ch2 = getChar(); + if (ch2 != 'f' && ch2 != 'F') { + ungetChar(); + ungetChar(); + } else { + saveName(ch); + saveName(ch2); + isFloat16 = true; + } + } else if (parseContext.intermediate.getSource() == EShSourceHlsl) { + saveName(ch); + isFloat16 = true; + } + } else if (ch == 'f' || ch == 'F') { + if (ifdepth == 0) parseContext.profileRequires(ppToken->loc, EEsProfile, 300, nullptr, "floating-point suffix"); - if (! parseContext.relaxedErrors()) - parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, nullptr, "floating-point suffix"); - if (! HasDecimalOrExponent) - parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", ""); - if (len < MaxTokenLength) - str[len++] = (char)ch; - else { - parseContext.ppError(ppToken->loc, "float literal too long", "", ""); - len = 1,str_len=1; - } - } else - ungetChar(); + if (ifdepth == 0 && !parseContext.relaxedErrors()) + parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, nullptr, "floating-point suffix"); + if (ifdepth == 0 && !hasDecimalOrExponent) + parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", ""); + saveName(ch); + } else + ungetChar(); - str[len]='\0'; + // Patch up the name and length for overflow - ppToken->dval = strtod(str, nullptr); + if (len > MaxTokenLength) { + len = MaxTokenLength; + parseContext.ppError(ppToken->loc, "float literal too long", "", ""); + } + ppToken->name[len] = '\0'; + + // Compute the numerical value + if (fastPath) { + // compute the floating-point value of the exponent + if (exponentValue == 0.0) + ppToken->dval = (double)wholeNumber; + else if (negativeExponent) + ppToken->dval = (double)wholeNumber / exponentValue; + else + ppToken->dval = (double)wholeNumber * exponentValue; + } else { + // slow path + strtodStream.clear(); + strtodStream.str(ppToken->name); + strtodStream >> ppToken->dval; + // Assume failure combined with a large exponent was overflow, in + // an attempt to set INF. Otherwise, assume underflow, and set 0.0. + if (strtodStream.fail()) { + if (!negativeExponent && exponent + numWholeNumberDigits > 300) + ppToken->i64val = 0x7ff0000000000000; // +Infinity + else + ppToken->dval = 0.0; + } } + // Return the right token type if (isDouble) return PpAtomConstDouble; + else if (isFloat16) + return PpAtomConstFloat16; else return PpAtomConstFloat; } +// Recognize a character literal. +// +// The first ' has already been accepted, read the rest, through the closing '. +// +// Always returns PpAtomConstInt. +// +int TPpContext::characterLiteral(TPpToken* ppToken) +{ + ppToken->name[0] = 0; + ppToken->ival = 0; + + if (parseContext.intermediate.getSource() != EShSourceHlsl) { + // illegal, except in macro definition, for which case we report the character + return '\''; + } + + int ch = getChar(); + switch (ch) { + case '\'': + // As empty sequence: '' + parseContext.ppError(ppToken->loc, "unexpected", "\'", ""); + return PpAtomConstInt; + case '\\': + // As escape sequence: '\XXX' + switch (ch = getChar()) { + case 'a': + ppToken->ival = 7; + break; + case 'b': + ppToken->ival = 8; + break; + case 't': + ppToken->ival = 9; + break; + case 'n': + ppToken->ival = 10; + break; + case 'v': + ppToken->ival = 11; + break; + case 'f': + ppToken->ival = 12; + break; + case 'r': + ppToken->ival = 13; + break; + case 'x': + case '0': + parseContext.ppError(ppToken->loc, "octal and hex sequences not supported", "\\", ""); + break; + default: + // This catches '\'', '\"', '\?', etc. + // Also, things like '\C' mean the same thing as 'C' + // (after the above cases are filtered out). + ppToken->ival = ch; + break; + } + break; + default: + ppToken->ival = ch; + break; + } + ppToken->name[0] = (char)ppToken->ival; + ppToken->name[1] = '\0'; + ch = getChar(); + if (ch != '\'') { + parseContext.ppError(ppToken->loc, "expected", "\'", ""); + // Look ahead for a closing ' + do { + ch = getChar(); + } while (ch != '\'' && ch != EndOfInput && ch != '\n'); + } + + return PpAtomConstInt; +} + // // Scanner used to tokenize source stream. // int TPpContext::tStringInput::scan(TPpToken* ppToken) { - char* tokenText = ppToken->name; int AlreadyComplained = 0; int len = 0; int ch = 0; int ii = 0; unsigned long long ival = 0; - bool enableInt64 = pp->parseContext.version >= 450 && pp->parseContext.extensionTurnedOn(E_GL_ARB_gpu_shader_int64); + const auto floatingPointChar = [&](int ch) { return ch == '.' || ch == 'e' || ch == 'E' || + ch == 'f' || ch == 'F' || + ch == 'h' || ch == 'H'; }; + + static const char* const Int64_Extensions[] = { + E_GL_ARB_gpu_shader_int64, + E_GL_KHX_shader_explicit_arithmetic_types, + E_GL_KHX_shader_explicit_arithmetic_types_int64 }; + static const int Num_Int64_Extensions = sizeof(Int64_Extensions) / sizeof(Int64_Extensions[0]); + + static const char* const Int16_Extensions[] = { +#ifdef AMD_EXTENSIONS + E_GL_AMD_gpu_shader_int16, +#endif + E_GL_KHX_shader_explicit_arithmetic_types, + E_GL_KHX_shader_explicit_arithmetic_types_int16 }; + static const int Num_Int16_Extensions = sizeof(Int16_Extensions) / sizeof(Int16_Extensions[0]); ppToken->ival = 0; ppToken->i64val = 0; @@ -256,6 +457,8 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) switch (ch) { default: // Single character token, including EndOfInput, '#' and '\' (escaped newlines are handled at a lower level, so this is just a '\' token) + if (ch > PpAtomMaxSingle) + ch = PpAtomBadToken; return ch; case 'A': case 'B': case 'C': case 'D': case 'E': @@ -272,7 +475,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) case 'z': do { if (len < MaxTokenLength) { - tokenText[len++] = (char)ch; + ppToken->name[len++] = (char)ch; ch = getch(); } else { if (! AlreadyComplained) { @@ -290,18 +493,18 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) if (len == 0) continue; - tokenText[len] = '\0'; + ppToken->name[len] = '\0'; ungetch(); - ppToken->atom = pp->LookUpAddString(tokenText); return PpAtomIdentifier; case '0': ppToken->name[len++] = (char)ch; ch = getch(); if (ch == 'x' || ch == 'X') { - // must be hexidecimal + // must be hexadecimal bool isUnsigned = false; bool isInt64 = false; + bool isInt16 = false; ppToken->name[len++] = (char)ch; ch = getch(); if ((ch >= '0' && ch <= '9') || @@ -310,7 +513,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) ival = 0; do { - if (ival <= 0x0fffffff || (enableInt64 && ival <= 0x0fffffffffffffffull)) { + if (len < MaxTokenLength && ival <= 0x0fffffffffffffffull) { ppToken->name[len++] = (char)ch; if (ch >= '0' && ch <= '9') { ii = ch - '0'; @@ -319,11 +522,14 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) } else if (ch >= 'a' && ch <= 'f') { ii = ch - 'a' + 10; } else - pp->parseContext.ppError(ppToken->loc, "bad digit in hexidecimal literal", "", ""); + pp->parseContext.ppError(ppToken->loc, "bad digit in hexadecimal literal", "", ""); ival = (ival << 4) | ii; } else { if (! AlreadyComplained) { - pp->parseContext.ppError(ppToken->loc, "hexidecimal literal too big", "", ""); + if(len < MaxTokenLength) + pp->parseContext.ppError(ppToken->loc, "hexadecimal literal too big", "", ""); + else + pp->parseContext.ppError(ppToken->loc, "hexadecimal literal too long", "", ""); AlreadyComplained = 1; } ival = 0xffffffffffffffffull; @@ -333,35 +539,69 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')); } else { - pp->parseContext.ppError(ppToken->loc, "bad digit in hexidecimal literal", "", ""); + pp->parseContext.ppError(ppToken->loc, "bad digit in hexadecimal literal", "", ""); } if (ch == 'u' || ch == 'U') { if (len < MaxTokenLength) ppToken->name[len++] = (char)ch; isUnsigned = true; - if (enableInt64) { - int nextCh = getch(); - if ((ch == 'u' && nextCh == 'l') || (ch == 'U' && nextCh == 'L')) { - if (len < MaxTokenLength) - ppToken->name[len++] = (char)nextCh; - isInt64 = true; - } else - ungetch(); - } - } - else if (enableInt64 && (ch == 'l' || ch == 'L')) { + int nextCh = getch(); + if (nextCh == 'l' || nextCh == 'L') { + if (len < MaxTokenLength) + ppToken->name[len++] = (char)nextCh; + isInt64 = true; + } else + ungetch(); + +#ifdef AMD_EXTENSIONS + nextCh = getch(); + if ((nextCh == 's' || nextCh == 'S') && + pp->parseContext.intermediate.getSource() == EShSourceGlsl) { + if (len < MaxTokenLength) + ppToken->name[len++] = (char)nextCh; + isInt16 = true; + } else + ungetch(); +#endif + } else if (ch == 'l' || ch == 'L') { if (len < MaxTokenLength) ppToken->name[len++] = (char)ch; isInt64 = true; +#ifdef AMD_EXTENSIONS + } else if ((ch == 's' || ch == 'S') && + pp->parseContext.intermediate.getSource() == EShSourceGlsl) { + if (len < MaxTokenLength) + ppToken->name[len++] = (char)ch; + isInt16 = true; +#endif } else ungetch(); ppToken->name[len] = '\0'; - if (isInt64) { + if (isInt64 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) { + if (pp->ifdepth == 0) { + pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile, + "64-bit hexadecimal literal"); + pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0, + Num_Int64_Extensions, Int64_Extensions, "64-bit hexadecimal literal"); + } ppToken->i64val = ival; return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64; + } else if (isInt16) { + if (pp->ifdepth == 0) { + if (pp->parseContext.intermediate.getSource() == EShSourceGlsl) { + pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile, + "16-bit hexadecimal literal"); + pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0, + Num_Int16_Extensions, Int16_Extensions, "16-bit hexadecimal literal"); + } + } + ppToken->ival = (int)ival; + return isUnsigned ? PpAtomConstUint16 : PpAtomConstInt16; } else { + if (ival > 0xffffffffu && !AlreadyComplained) + pp->parseContext.ppError(ppToken->loc, "hexadecimal literal too big", "", ""); ppToken->ival = (int)ival; return isUnsigned ? PpAtomConstUint : PpAtomConstInt; } @@ -370,6 +610,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) bool isUnsigned = false; bool isInt64 = false; + bool isInt16 = false; bool octalOverflow = false; bool nonOctal = false; ival = 0; @@ -382,7 +623,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", ""); AlreadyComplained = 1; } - if (ival <= 0x1fffffff || (enableInt64 && ival <= 0x1fffffffffffffffull)) { + if (ival <= 0x1fffffffffffffffull) { ii = ch - '0'; ival = (ival << 3) | ii; } else @@ -403,9 +644,9 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) ch = getch(); } while (ch >= '0' && ch <= '9'); } - if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'E' || ch == 'F') + if (floatingPointChar(ch)) return pp->lFloatConst(len, ch, ppToken); - + // wasn't a float, so must be octal... if (nonOctal) pp->parseContext.ppError(ppToken->loc, "octal literal digit too large", "", ""); @@ -415,30 +656,65 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) ppToken->name[len++] = (char)ch; isUnsigned = true; - if (enableInt64) { - int nextCh = getch(); - if ((ch == 'u' && nextCh == 'l') || (ch == 'U' && nextCh == 'L')) { - if (len < MaxTokenLength) - ppToken->name[len++] = (char)nextCh; - isInt64 = true; - } else - ungetch(); - } - } - else if (enableInt64 && (ch == 'l' || ch == 'L')) { + int nextCh = getch(); + if (nextCh == 'l' || nextCh == 'L') { + if (len < MaxTokenLength) + ppToken->name[len++] = (char)nextCh; + isInt64 = true; + } else + ungetch(); + +#ifdef AMD_EXTENSIONS + nextCh = getch(); + if ((nextCh == 's' || nextCh == 'S') && + pp->parseContext.intermediate.getSource() == EShSourceGlsl) { + if (len < MaxTokenLength) + ppToken->name[len++] = (char)nextCh; + isInt16 = true; + } else + ungetch(); +#endif + } else if (ch == 'l' || ch == 'L') { if (len < MaxTokenLength) ppToken->name[len++] = (char)ch; isInt64 = true; +#ifdef AMD_EXTENSIONS + } else if ((ch == 's' || ch == 'S') && + pp->parseContext.intermediate.getSource() == EShSourceGlsl) { + if (len < MaxTokenLength) + ppToken->name[len++] = (char)ch; + isInt16 = true; +#endif } else ungetch(); ppToken->name[len] = '\0'; + if (!isInt64 && ival > 0xffffffffu) + octalOverflow = true; + if (octalOverflow) pp->parseContext.ppError(ppToken->loc, "octal literal too big", "", ""); - if (isInt64) { + if (isInt64 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) { + if (pp->ifdepth == 0) { + pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile, + "64-bit octal literal"); + pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0, + Num_Int64_Extensions, Int64_Extensions, "64-bit octal literal"); + } ppToken->i64val = ival; return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64; + } else if (isInt16) { + if (pp->ifdepth == 0) { + if (pp->parseContext.intermediate.getSource() == EShSourceGlsl) { + pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile, + "16-bit octal literal"); + pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0, + Num_Int16_Extensions, Int16_Extensions, "16-bit octal literal"); + } + } + ppToken->ival = (int)ival; + return isUnsigned ? PpAtomConstUint16 : PpAtomConstInt16; } else { ppToken->ival = (int)ival; return isUnsigned ? PpAtomConstUint : PpAtomConstInt; @@ -447,7 +723,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - // can't be hexidecimal or octal, is either decimal or floating point + // can't be hexadecimal or octal, is either decimal or floating point do { if (len < MaxTokenLength) @@ -458,31 +734,48 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) } ch = getch(); } while (ch >= '0' && ch <= '9'); - if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'E' || ch == 'F') { + if (floatingPointChar(ch)) return pp->lFloatConst(len, ch, ppToken); - } else { + else { // Finish handling signed and unsigned integers int numericLen = len; bool isUnsigned = false; bool isInt64 = false; + bool isInt16 = false; if (ch == 'u' || ch == 'U') { if (len < MaxTokenLength) ppToken->name[len++] = (char)ch; isUnsigned = true; - if (enableInt64) { - int nextCh = getch(); - if ((ch == 'u' && nextCh == 'l') || (ch == 'U' && nextCh == 'L')) { - if (len < MaxTokenLength) - ppToken->name[len++] = (char)nextCh; - isInt64 = true; - } else - ungetch(); - } - } else if (enableInt64 && (ch == 'l' || ch == 'L')) { + int nextCh = getch(); + if (nextCh == 'l' || nextCh == 'L') { + if (len < MaxTokenLength) + ppToken->name[len++] = (char)nextCh; + isInt64 = true; + } else + ungetch(); + +#ifdef AMD_EXTENSIONS + nextCh = getch(); + if ((nextCh == 's' || nextCh == 'S') && + pp->parseContext.intermediate.getSource() == EShSourceGlsl) { + if (len < MaxTokenLength) + ppToken->name[len++] = (char)nextCh; + isInt16 = true; + } else + ungetch(); +#endif + } else if (ch == 'l' || ch == 'L') { if (len < MaxTokenLength) ppToken->name[len++] = (char)ch; isInt64 = true; +#ifdef AMD_EXTENSIONS + } else if ((ch == 's' || ch == 'S') && + pp->parseContext.intermediate.getSource() == EShSourceGlsl) { + if (len < MaxTokenLength) + ppToken->name[len++] = (char)ch; + isInt16 = true; +#endif } else ungetch(); @@ -492,10 +785,18 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) const unsigned remainderMaxInt = 0xFFFFFFFFu - 10 * oneTenthMaxInt; const unsigned long long oneTenthMaxInt64 = 0xFFFFFFFFFFFFFFFFull / 10; const unsigned long long remainderMaxInt64 = 0xFFFFFFFFFFFFFFFFull - 10 * oneTenthMaxInt64; + const unsigned short oneTenthMaxInt16 = 0xFFFFu / 10; + const unsigned short remainderMaxInt16 = 0xFFFFu - 10 * oneTenthMaxInt16; for (int i = 0; i < numericLen; i++) { ch = ppToken->name[i] - '0'; - if ((enableInt64 == false && ((ival > oneTenthMaxInt) || (ival == oneTenthMaxInt && (unsigned)ch > remainderMaxInt))) || - (enableInt64 && ((ival > oneTenthMaxInt64) || (ival == oneTenthMaxInt64 && (unsigned long long)ch > remainderMaxInt64)))) { + bool overflow = false; + if (isInt64) + overflow = (ival > oneTenthMaxInt64 || (ival == oneTenthMaxInt64 && (unsigned long long)ch > remainderMaxInt64)); + else if (isInt16) + overflow = (ival > oneTenthMaxInt16 || (ival == oneTenthMaxInt16 && (unsigned short)ch > remainderMaxInt16)); + else + overflow = (ival > oneTenthMaxInt || (ival == oneTenthMaxInt && (unsigned)ch > remainderMaxInt)); + if (overflow) { pp->parseContext.ppError(ppToken->loc, "numeric literal too big", "", ""); ival = 0xFFFFFFFFFFFFFFFFull; break; @@ -503,9 +804,24 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) ival = ival * 10 + ch; } - if (isInt64) { + if (isInt64 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) { + if (pp->ifdepth == 0) { + pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile, + "64-bit literal"); + pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0, + Num_Int64_Extensions, Int64_Extensions, "64-bit literal"); + } ppToken->i64val = ival; return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64; + } else if (isInt16) { + if (pp->ifdepth == 0 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) { + pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile, + "16-bit literal"); + pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0, + Num_Int16_Extensions, Int16_Extensions, "16-bit literal"); + } + ppToken->ival = (int)ival; + return isUnsigned ? PpAtomConstUint16 : PpAtomConstInt16; } else { ppToken->ival = (int)ival; return isUnsigned ? PpAtomConstUint : PpAtomConstInt; @@ -517,7 +833,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) if (ch == '-') { return PpAtomDecrement; } else if (ch == '=') { - return PpAtomSub; + return PPAtomSubAssign; } else { ungetch(); return '-'; @@ -527,7 +843,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) if (ch == '+') { return PpAtomIncrement; } else if (ch == '=') { - return PpAtomAdd; + return PPAtomAddAssign; } else { ungetch(); return '+'; @@ -535,7 +851,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) case '*': ch = getch(); if (ch == '=') { - return PpAtomMul; + return PPAtomMulAssign; } else { ungetch(); return '*'; @@ -543,7 +859,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) case '%': ch = getch(); if (ch == '=') { - return PpAtomMod; + return PPAtomModAssign; } else { ungetch(); return '%'; @@ -669,28 +985,39 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) // loop again to get the next token... break; } else if (ch == '=') { - return PpAtomDiv; + return PPAtomDivAssign; } else { ungetch(); return '/'; } break; + case '\'': + return pp->characterLiteral(ppToken); case '"': + // TODO: If this gets enhanced to handle escape sequences, or + // anything that is different than what #include needs, then + // #include needs to use scanHeaderName() for this. ch = getch(); while (ch != '"' && ch != '\n' && ch != EndOfInput) { if (len < MaxTokenLength) { - tokenText[len] = (char)ch; + ppToken->name[len] = (char)ch; len++; ch = getch(); } else break; }; - tokenText[len] = '\0'; + ppToken->name[len] = '\0'; if (ch != '"') { ungetch(); pp->parseContext.ppError(ppToken->loc, "End of line in string", "string", ""); } return PpAtomConstString; + case ':': + ch = getch(); + if (ch == ':') + return PpAtomColonColon; + ungetch(); + return ':'; } ch = getch(); @@ -698,34 +1025,34 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) } // -// The main functional entry-point into the preprocessor, which will +// The main functional entry point into the preprocessor, which will // scan the source strings to figure out and return the next processing token. // -// Return string pointer to next token. -// Return 0 when no more tokens. +// Return the token, or EndOfInput when no more tokens. // -const char* TPpContext::tokenize(TPpToken* ppToken) -{ - int token = '\n'; - +int TPpContext::tokenize(TPpToken& ppToken) +{ for(;;) { - token = scanToken(ppToken); - ppToken->token = token; + int token = scanToken(&ppToken); + + // Handle token-pasting logic + token = tokenPaste(token, ppToken); + if (token == EndOfInput) { missingEndifCheck(); - return nullptr; + return EndOfInput; } if (token == '#') { if (previous_token == '\n') { - token = readCPPline(ppToken); + token = readCPPline(&ppToken); if (token == EndOfInput) { missingEndifCheck(); - return nullptr; + return EndOfInput; } continue; } else { - parseContext.ppError(ppToken->loc, "preprocessor directive cannot be preceded by another token", "#", ""); - return nullptr; + parseContext.ppError(ppToken.loc, "preprocessor directive cannot be preceded by another token", "#", ""); + return EndOfInput; } } previous_token = token; @@ -734,10 +1061,9 @@ const char* TPpContext::tokenize(TPpToken* ppToken) continue; // expand macros - if (token == PpAtomIdentifier && MacroExpand(ppToken->atom, ppToken, false, true) != 0) + if (token == PpAtomIdentifier && MacroExpand(&ppToken, false, true) != 0) continue; - const char* tokenString = nullptr; switch (token) { case PpAtomIdentifier: case PpAtomConstInt: @@ -745,27 +1071,119 @@ const char* TPpContext::tokenize(TPpToken* ppToken) case PpAtomConstFloat: case PpAtomConstInt64: case PpAtomConstUint64: + case PpAtomConstInt16: + case PpAtomConstUint16: case PpAtomConstDouble: - tokenString = ppToken->name; + case PpAtomConstFloat16: + if (ppToken.name[0] == '\0') + continue; break; case PpAtomConstString: - parseContext.ppError(ppToken->loc, "string literals not supported", "\"\"", ""); + if (ifdepth == 0 && parseContext.intermediate.getSource() != EShSourceHlsl) { + // HLSL allows string literals. + parseContext.ppError(ppToken.loc, "string literals not supported", "\"\"", ""); + continue; + } break; case '\'': - parseContext.ppError(ppToken->loc, "character literals not supported", "\'", ""); + parseContext.ppError(ppToken.loc, "character literals not supported", "\'", ""); + continue; + default: + strcpy(ppToken.name, atomStrings.getString(token)); + break; + } + + return token; + } +} + +// +// Do all token-pasting related combining of two pasted tokens when getting a +// stream of tokens from a replacement list. Degenerates to no processing if a +// replacement list is not the source of the token stream. +// +int TPpContext::tokenPaste(int token, TPpToken& ppToken) +{ + // starting with ## is illegal, skip to next token + if (token == PpAtomPaste) { + parseContext.ppError(ppToken.loc, "unexpected location", "##", ""); + return scanToken(&ppToken); + } + + int resultToken = token; // "foo" pasted with "35" is an identifier, not a number + + // ## can be chained, process all in the chain at once + while (peekPasting()) { + TPpToken pastedPpToken; + + // next token has to be ## + token = scanToken(&pastedPpToken); + assert(token == PpAtomPaste); + + // This covers end of macro expansion + if (endOfReplacementList()) { + parseContext.ppError(ppToken.loc, "unexpected location; end of replacement list", "##", ""); + break; + } + + // get the token after the ## + token = scanToken(&pastedPpToken); + + // This covers end of argument expansion + if (token == tMarkerInput::marker) { + parseContext.ppError(ppToken.loc, "unexpected location; end of argument", "##", ""); + break; + } + + // get the token text + switch (resultToken) { + case PpAtomIdentifier: + // already have the correct text in token.names + break; + case '=': + case '!': + case '-': + case '~': + case '+': + case '*': + case '/': + case '%': + case '<': + case '>': + case '|': + case '^': + case '&': + case PpAtomRight: + case PpAtomLeft: + case PpAtomAnd: + case PpAtomOr: + case PpAtomXor: + strcpy(ppToken.name, atomStrings.getString(resultToken)); + strcpy(pastedPpToken.name, atomStrings.getString(token)); break; default: - tokenString = GetAtomString(token); - break; + parseContext.ppError(ppToken.loc, "not supported for these tokens", "##", ""); + return resultToken; } - if (tokenString) { - if (tokenString[0] != 0) - parseContext.tokensBeforeEOF = 1; + // combine the tokens + if (strlen(ppToken.name) + strlen(pastedPpToken.name) > MaxTokenLength) { + parseContext.ppError(ppToken.loc, "combined tokens are too long", "##", ""); + return resultToken; + } + strncat(ppToken.name, pastedPpToken.name, MaxTokenLength - strlen(ppToken.name)); - return tokenString; + // correct the kind of token we are making, if needed (identifiers stay identifiers) + if (resultToken != PpAtomIdentifier) { + int newToken = atomStrings.getAtom(ppToken.name); + if (newToken > 0) + resultToken = newToken; + else + parseContext.ppError(ppToken.loc, "combined token is invalid", "##", ""); } } + + return resultToken; } // Checks if we've seen balanced #if...#endif diff --git a/Externals/glslang/glslang/MachineIndependent/preprocessor/PpSymbols.cpp b/Externals/glslang/glslang/MachineIndependent/preprocessor/PpSymbols.cpp deleted file mode 100644 index c2ab7c0a11..0000000000 --- a/Externals/glslang/glslang/MachineIndependent/preprocessor/PpSymbols.cpp +++ /dev/null @@ -1,135 +0,0 @@ -// -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2013 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. -// -/****************************************************************************\ -Copyright (c) 2002, NVIDIA Corporation. - -NVIDIA Corporation("NVIDIA") supplies this software to you in -consideration of your agreement to the following terms, and your use, -installation, modification or redistribution of this NVIDIA software -constitutes acceptance of these terms. If you do not agree with these -terms, please do not use, install, modify or redistribute this NVIDIA -software. - -In consideration of your agreement to abide by the following terms, and -subject to these terms, NVIDIA grants you a personal, non-exclusive -license, under NVIDIA's copyrights in this original NVIDIA software (the -"NVIDIA Software"), to use, reproduce, modify and redistribute the -NVIDIA Software, with or without modifications, in source and/or binary -forms; provided that if you redistribute the NVIDIA Software, you must -retain the copyright notice of NVIDIA, this notice and the following -text and disclaimers in all such redistributions of the NVIDIA Software. -Neither the name, trademarks, service marks nor logos of NVIDIA -Corporation may be used to endorse or promote products derived from the -NVIDIA Software without specific prior written permission from NVIDIA. -Except as expressly stated in this notice, no other rights or licenses -express or implied, are granted by NVIDIA herein, including but not -limited to any patent rights that may be infringed by your derivative -works or by other works in which the NVIDIA Software may be -incorporated. No hardware is licensed hereunder. - -THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT -WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, -INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, -NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR -ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER -PRODUCTS. - -IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, -INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY -OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE -NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, -TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF -NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -\****************************************************************************/ -// -// symbols.c -// - -#include -#include -#include -#include - -#include "PpContext.h" - -/////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////// Symbol Table Variables: /////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////// - -namespace glslang { - -/* -* Allocate a new symbol node; -* -*/ -TPpContext::Symbol* TPpContext::NewSymbol(int atom) -{ - Symbol* lSymb; - char* pch; - size_t ii; - - lSymb = (Symbol *) mem_Alloc(pool, sizeof(Symbol)); - lSymb->atom = atom; - - // Clear macro - pch = (char*) &lSymb->mac; - for (ii = 0; ii < sizeof(lSymb->mac); ii++) - *pch++ = 0; - - return lSymb; -} - -TPpContext::Symbol* TPpContext::AddSymbol(int atom) -{ - Symbol *lSymb; - - lSymb = NewSymbol(atom); - symbols[lSymb->atom] = lSymb; - - return lSymb; -} - -TPpContext::Symbol* TPpContext::LookUpSymbol(int atom) -{ - TSymbolMap::iterator it = symbols.find(atom); - if (it == symbols.end()) - return nullptr; - else - return it->second; -} - -} // end namespace glslang diff --git a/Externals/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp b/Externals/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp old mode 100644 new mode 100755 index 54d495e11f..d8088e7d4d --- a/Externals/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp +++ b/Externals/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp @@ -1,11 +1,11 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//Copyright (C) 2013 LunarG, Inc. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2013 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: +// 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. @@ -19,18 +19,18 @@ // 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. +// 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. // /****************************************************************************\ Copyright (c) 2002, NVIDIA Corporation. @@ -57,7 +57,7 @@ Except as expressly stated in this notice, no other rights or licenses express or implied, are granted by NVIDIA herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the NVIDIA Software may be -incorporated. No hardware is licensed hereunder. +incorporated. No hardware is licensed hereunder. THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, @@ -80,182 +80,242 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // For recording and playing back the stream of tokens in a macro definition. // -#if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/) +#ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS +#endif +#if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/) #define snprintf sprintf_s #endif -#include -#include -#include -#include -#include +#include +#include +#include +#include #include "PpContext.h" #include "PpTokens.h" namespace glslang { -void TPpContext::lAddByte(TokenStream *fTok, unsigned char fVal) -{ - fTok->data.push_back(fVal); + +namespace { + + // When recording (and playing back) should the backing name string + // be saved (restored)? + bool SaveName(int atom) + { + switch (atom) { + case PpAtomIdentifier: + case PpAtomConstString: + case PpAtomConstInt: + case PpAtomConstUint: + case PpAtomConstInt64: + case PpAtomConstUint64: + #ifdef AMD_EXTENSIONS + case PpAtomConstInt16: + case PpAtomConstUint16: + #endif + case PpAtomConstFloat: + case PpAtomConstDouble: + case PpAtomConstFloat16: + return true; + default: + return false; + } + } + + // When recording (and playing back) should the numeric value + // be saved (restored)? + bool SaveValue(int atom) + { + switch (atom) { + case PpAtomConstInt: + case PpAtomConstUint: + case PpAtomConstInt64: + case PpAtomConstUint64: + #ifdef AMD_EXTENSIONS + case PpAtomConstInt16: + case PpAtomConstUint16: + #endif + case PpAtomConstFloat: + case PpAtomConstDouble: + case PpAtomConstFloat16: + return true; + default: + return false; + } + } } -/* -* Get the next byte from a stream. -*/ -int TPpContext::lReadByte(TokenStream *pTok) +// push onto back of stream +void TPpContext::TokenStream::putSubtoken(char subtoken) { - if (pTok->current < pTok->data.size()) - return pTok->data[pTok->current++]; + data.push_back(static_cast(subtoken)); +} + +// get the next token in stream +int TPpContext::TokenStream::getSubtoken() +{ + if (current < data.size()) + return data[current++]; else return EndOfInput; } -void TPpContext::lUnreadByte(TokenStream *pTok) +// back up one position in the stream +void TPpContext::TokenStream::ungetSubtoken() { - if (pTok->current > 0) - --pTok->current; + if (current > 0) + --current; } -/* -* Add a token to the end of a list for later playback. -*/ -void TPpContext::RecordToken(TokenStream *pTok, int token, TPpToken* ppToken) +// Add a complete token (including backing string) to the end of a list +// for later playback. +void TPpContext::TokenStream::putToken(int atom, TPpToken* ppToken) { - const char* s; - char* str = NULL; + // save the atom + assert((atom & ~0xff) == 0); + putSubtoken(static_cast(atom)); - if (token > PpAtomMaxSingle) - lAddByte(pTok, (unsigned char)((token & 0x7f) + 0x80)); - else - lAddByte(pTok, (unsigned char)(token & 0x7f)); - - switch (token) { - case PpAtomIdentifier: - case PpAtomConstString: - s = ppToken->name; + // save the backing name string + if (SaveName(atom)) { + const char* s = ppToken->name; while (*s) - lAddByte(pTok, (unsigned char) *s++); - lAddByte(pTok, 0); - break; - case PpAtomConstInt: - case PpAtomConstUint: - case PpAtomConstInt64: - case PpAtomConstUint64: - case PpAtomConstFloat: - case PpAtomConstDouble: - str = ppToken->name; - while (*str) { - lAddByte(pTok, (unsigned char) *str); - str++; - } - lAddByte(pTok, 0); - break; - default: - break; + putSubtoken(*s++); + putSubtoken(0); + } + + // save the numeric value + if (SaveValue(atom)) { + const char* n = reinterpret_cast(&ppToken->i64val); + for (int i = 0; i < sizeof(ppToken->i64val); ++i) + putSubtoken(*n++); } } -/* -* Reset a token stream in preperation for reading. -*/ -void TPpContext::RewindTokenStream(TokenStream *pTok) +// Read the next token from a token stream. +// (Not the source stream, but a stream used to hold a tokenized macro). +int TPpContext::TokenStream::getToken(TParseContextBase& parseContext, TPpToken *ppToken) { - pTok->current = 0; -} + // get the atom + int atom = getSubtoken(); + if (atom == EndOfInput) + return atom; -/* -* Read the next token from a token stream (not the source stream, but stream used to hold a tokenized macro). -*/ -int TPpContext::ReadToken(TokenStream *pTok, TPpToken *ppToken) -{ - char* tokenText = ppToken->name; - int ltoken, len; - int ch; - - ltoken = lReadByte(pTok); + // init the token + ppToken->clear(); ppToken->loc = parseContext.getCurrentLoc(); - if (ltoken > 127) - ltoken += 128; - switch (ltoken) { - case '#': - if (lReadByte(pTok) == '#') { - parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)"); - parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, 0, "token pasting (##)"); - parseContext.error(ppToken->loc, "token pasting not implemented (internal error)", "##", ""); - //return PpAtomPaste; - return ReadToken(pTok, ppToken); - } else - lUnreadByte(pTok); - break; - case PpAtomConstString: - case PpAtomIdentifier: - case PpAtomConstFloat: - case PpAtomConstDouble: - case PpAtomConstInt: - case PpAtomConstUint: - case PpAtomConstInt64: - case PpAtomConstUint64: - len = 0; - ch = lReadByte(pTok); + + // get the backing name string + if (SaveName(atom)) { + int ch = getSubtoken(); + int len = 0; while (ch != 0 && ch != EndOfInput) { if (len < MaxTokenLength) { - tokenText[len] = (char)ch; + ppToken->name[len] = (char)ch; len++; - ch = lReadByte(pTok); + ch = getSubtoken(); } else { parseContext.error(ppToken->loc, "token too long", "", ""); break; } } - tokenText[len] = 0; + ppToken->name[len] = 0; + } - switch (ltoken) { - case PpAtomIdentifier: - ppToken->atom = LookUpAddString(tokenText); - break; - case PpAtomConstString: - break; - case PpAtomConstFloat: - case PpAtomConstDouble: - ppToken->dval = atof(ppToken->name); - break; - case PpAtomConstInt: - case PpAtomConstUint: - if (len > 0 && tokenText[0] == '0') { - if (len > 1 && (tokenText[1] == 'x' || tokenText[1] == 'X')) - ppToken->ival = strtol(ppToken->name, 0, 16); - else - ppToken->ival = strtol(ppToken->name, 0, 8); + // Check for ##, unless the current # is the last character + if (atom == '#') { + if (current < data.size()) { + if (getSubtoken() == '#') { + parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)"); + parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, 0, "token pasting (##)"); + atom = PpAtomPaste; } else - ppToken->ival = atoi(ppToken->name); - break; - case PpAtomConstInt64: - case PpAtomConstUint64: - if (len > 0 && tokenText[0] == '0') { - if (len > 1 && (tokenText[1] == 'x' || tokenText[1] == 'X')) - ppToken->i64val = strtoll(ppToken->name, nullptr, 16); - else - ppToken->i64val = strtoll(ppToken->name, nullptr, 8); - } else - ppToken->i64val = atoll(ppToken->name); - break; + ungetSubtoken(); } } - return ltoken; + // get the numeric value + if (SaveValue(atom)) { + char* n = reinterpret_cast(&ppToken->i64val); + for (int i = 0; i < sizeof(ppToken->i64val); ++i) + *n++ = getSubtoken(); + } + + return atom; } -int TPpContext::tTokenInput::scan(TPpToken* ppToken) +// We are pasting if +// 1. we are preceding a pasting operator within this stream +// or +// 2. the entire macro is preceding a pasting operator (lastTokenPastes) +// and we are also on the last token +bool TPpContext::TokenStream::peekTokenizedPasting(bool lastTokenPastes) { - return pp->ReadToken(tokens, ppToken); + // 1. preceding ##? + + size_t savePos = current; + int subtoken; + // skip white space + do { + subtoken = getSubtoken(); + } while (subtoken == ' '); + current = savePos; + if (subtoken == PpAtomPaste) + return true; + + // 2. last token and we've been told after this there will be a ## + + if (! lastTokenPastes) + return false; + // Getting here means the last token will be pasted, after this + + // Are we at the last non-whitespace token? + savePos = current; + bool moreTokens = false; + do { + subtoken = getSubtoken(); + if (subtoken == EndOfInput) + break; + if (subtoken != ' ') { + moreTokens = true; + break; + } + } while (true); + current = savePos; + + return !moreTokens; } -void TPpContext::pushTokenStreamInput(TokenStream* ts) +// See if the next non-white-space tokens are two consecutive # +bool TPpContext::TokenStream::peekUntokenizedPasting() { - pushInput(new tTokenInput(this, ts)); - RewindTokenStream(ts); + // don't return early, have to restore this + size_t savePos = current; + + // skip white-space + int subtoken; + do { + subtoken = getSubtoken(); + } while (subtoken == ' '); + + // check for ## + bool pasting = false; + if (subtoken == '#') { + subtoken = getSubtoken(); + if (subtoken == '#') + pasting = true; + } + + current = savePos; + + return pasting; +} + +void TPpContext::pushTokenStreamInput(TokenStream& ts, bool prepasting) +{ + pushInput(new tTokenInput(this, &ts, prepasting)); + ts.reset(); } int TPpContext::tUngotTokenInput::scan(TPpToken* ppToken) diff --git a/Externals/glslang/glslang/MachineIndependent/preprocessor/PpTokens.h b/Externals/glslang/glslang/MachineIndependent/preprocessor/PpTokens.h index 87f0eb1a60..7b0f815500 100644 --- a/Externals/glslang/glslang/MachineIndependent/preprocessor/PpTokens.h +++ b/Externals/glslang/glslang/MachineIndependent/preprocessor/PpTokens.h @@ -1,10 +1,10 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -18,18 +18,18 @@ // 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. +// 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. // /****************************************************************************\ Copyright (c) 2002, NVIDIA Corporation. @@ -56,7 +56,7 @@ Except as expressly stated in this notice, no other rights or licenses express or implied, are granted by NVIDIA herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the NVIDIA Software may be -incorporated. No hardware is licensed hereunder. +incorporated. No hardware is licensed hereunder. THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, @@ -82,15 +82,19 @@ namespace glslang { // Multi-character tokens enum EFixedAtoms { - PpAtomMaxSingle = 256, // single character tokens get their own char value as their token, skip them + // single character tokens get their own char value as their token; start here for multi-character tokens + PpAtomMaxSingle = 127, + + // replace bad character tokens with this, to avoid accidental aliasing with the below + PpAtomBadToken, // Operators - PpAtomAdd, - PpAtomSub, - PpAtomMul, - PpAtomDiv, - PpAtomMod, + PPAtomAddAssign, + PPAtomSubAssign, + PPAtomMulAssign, + PPAtomDivAssign, + PPAtomModAssign, PpAtomRight, PpAtomLeft, @@ -113,6 +117,8 @@ enum EFixedAtoms { PpAtomDecrement, PpAtomIncrement, + PpAtomColonColon, + PpAtomPaste, // Constants @@ -121,17 +127,19 @@ enum EFixedAtoms { PpAtomConstUint, PpAtomConstInt64, PpAtomConstUint64, + PpAtomConstInt16, + PpAtomConstUint16, PpAtomConstFloat, PpAtomConstDouble, + PpAtomConstFloat16, PpAtomConstString, - // Indentifiers + // Identifiers PpAtomIdentifier, // preprocessor "keywords" PpAtomDefine, - PpAtomDefined, PpAtomUndef, PpAtomIf, diff --git a/Externals/glslang/glslang/MachineIndependent/propagateNoContraction.cpp b/Externals/glslang/glslang/MachineIndependent/propagateNoContraction.cpp index e599f4d9ff..ae95688ae8 100644 --- a/Externals/glslang/glslang/MachineIndependent/propagateNoContraction.cpp +++ b/Externals/glslang/glslang/MachineIndependent/propagateNoContraction.cpp @@ -90,6 +90,7 @@ bool isDereferenceOperation(glslang::TOperator op) case glslang::EOpIndexDirectStruct: case glslang::EOpIndexIndirect: case glslang::EOpVectorSwizzle: + case glslang::EOpMatrixSwizzle: return true; default: return false; @@ -272,9 +273,9 @@ TSymbolDefinitionCollectingTraverser::TSymbolDefinitionCollectingTraverser( ObjectAccesschainSet* precise_objects, std::unordered_set* precise_return_nodes) : TIntermTraverser(true, false, false), symbol_definition_mapping_(*symbol_definition_mapping), - precise_objects_(*precise_objects), current_object_(), - accesschain_mapping_(*accesschain_mapping), current_function_definition_node_(nullptr), - precise_return_nodes_(*precise_return_nodes) {} + precise_objects_(*precise_objects), precise_return_nodes_(*precise_return_nodes), + current_object_(), accesschain_mapping_(*accesschain_mapping), + current_function_definition_node_(nullptr) {} // Visits a symbol node, set the current_object_ to the // current node symbol ID, and record a mapping from this node to the current @@ -616,9 +617,9 @@ class TNoContractionPropagator : public glslang::TIntermTraverser { public: TNoContractionPropagator(ObjectAccesschainSet* precise_objects, const AccessChainMapping& accesschain_mapping) - : TIntermTraverser(true, false, false), remained_accesschain_(), - precise_objects_(*precise_objects), accesschain_mapping_(accesschain_mapping), - added_precise_object_ids_() {} + : TIntermTraverser(true, false, false), + precise_objects_(*precise_objects), added_precise_object_ids_(), + remained_accesschain_(), accesschain_mapping_(accesschain_mapping) {} // Propagates 'precise' in the right nodes of a given assignment node with // access chain record from the assignee node to a 'precise' object it @@ -670,7 +671,7 @@ protected: // Gets the struct dereference index that leads to 'precise' object. ObjectAccessChain precise_accesschain_index_str = getFrontElement(remained_accesschain_); - unsigned precise_accesschain_index = strtoul(precise_accesschain_index_str.c_str(), nullptr, 10); + unsigned precise_accesschain_index = (unsigned)strtoul(precise_accesschain_index_str.c_str(), nullptr, 10); // Gets the node pointed by the access chain index extracted before. glslang::TIntermTyped* potential_precise_node = node->getSequence()[precise_accesschain_index]->getAsTyped(); diff --git a/Externals/glslang/glslang/MachineIndependent/propagateNoContraction.h b/Externals/glslang/glslang/MachineIndependent/propagateNoContraction.h index 3412c85dc6..8521ad7d6a 100644 --- a/Externals/glslang/glslang/MachineIndependent/propagateNoContraction.h +++ b/Externals/glslang/glslang/MachineIndependent/propagateNoContraction.h @@ -37,6 +37,8 @@ // propagate 'noContraction' qualifier. // +#pragma once + #include "../Include/intermediate.h" namespace glslang { diff --git a/Externals/glslang/glslang/MachineIndependent/reflection.cpp b/Externals/glslang/glslang/MachineIndependent/reflection.cpp index d3e04af7f9..4818b10832 100644 --- a/Externals/glslang/glslang/MachineIndependent/reflection.cpp +++ b/Externals/glslang/glslang/MachineIndependent/reflection.cpp @@ -1,11 +1,11 @@ // -//Copyright (C) 2013 LunarG, Inc. +// Copyright (C) 2013-2016 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,22 +19,23 @@ // 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. +// 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. // #include "../Include/Common.h" #include "reflection.h" +#include "LiveTraverser.h" #include "localintermediate.h" #include "gl_types.h" @@ -48,7 +49,7 @@ // // High-level algorithm for one stage: // -// 1. Put main() on list of live functions. +// 1. Put the entry point on the list of live functions. // // 2. Traverse any live function, while skipping if-tests with a compile-time constant // condition of false, and while adding any encountered function calls to the live @@ -59,40 +60,28 @@ // 3. Add any encountered uniform variables and blocks to the reflection database. // // Can be attempted with a failed link, but will return false if recursion had been detected, or -// there wasn't exactly one main. +// there wasn't exactly one entry point. // namespace glslang { // // The traverser: mostly pass through, except -// - processing function-call nodes to push live functions onto the stack of functions to process // - processing binary nodes to see if they are dereferences of an aggregates to track // - processing symbol nodes to see if they are non-aggregate objects to track -// - processing selection nodes to trim semantically dead code +// +// This ignores semantically dead code by using TLiveTraverser. // // This is in the glslang namespace directly so it can be a friend of TReflection. // -class TLiveTraverser : public TIntermTraverser { +class TReflectionTraverser : public TLiveTraverser { public: - TLiveTraverser(const TIntermediate& i, TReflection& r) : intermediate(i), reflection(r) { } + TReflectionTraverser(const TIntermediate& i, TReflection& r) : + TLiveTraverser(i), reflection(r) { } - virtual bool visitAggregate(TVisit, TIntermAggregate* node); virtual bool visitBinary(TVisit, TIntermBinary* node); virtual void visitSymbol(TIntermSymbol* base); - virtual bool visitSelection(TVisit, TIntermSelection* node); - - // Track live funtions as well as uniforms, so that we don't visit dead functions - // and only visit each function once. - void addFunctionCall(TIntermAggregate* call) - { - // just use the map to ensure we process each function at most once - if (reflection.nameToIndex.find(call->getName()) == reflection.nameToIndex.end()) { - reflection.nameToIndex[call->getName()] = -1; - pushFunction(call->getName()); - } - } // Add a simple reference to a uniform variable to the uniform database, no dereference involved. // However, no dereference doesn't mean simple... it could be a complex aggregate. @@ -119,7 +108,7 @@ public: TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name); if (it == reflection.nameToIndex.end()) { reflection.nameToIndex[name] = (int)reflection.indexToAttribute.size(); - reflection.indexToAttribute.push_back(TObjectReflection(name, 0, mapToGlType(type), 0, 0)); + reflection.indexToAttribute.push_back(TObjectReflection(name, type, 0, mapToGlType(type), 0, 0)); } } } @@ -142,8 +131,11 @@ public: for (int m = 0; m <= index; ++m) { // modify just the children's view of matrix layout, if there is one for this member TLayoutMatrix subMatrixLayout = memberList[m].type->getQualifier().layoutMatrix; - int memberAlignment = intermediate.getBaseAlignment(*memberList[m].type, memberSize, dummyStride, type.getQualifier().layoutPacking == ElpStd140, - subMatrixLayout != ElmNone ? subMatrixLayout == ElmRowMajor : type.getQualifier().layoutMatrix == ElmRowMajor); + int memberAlignment = intermediate.getBaseAlignment(*memberList[m].type, memberSize, dummyStride, + type.getQualifier().layoutPacking == ElpStd140, + subMatrixLayout != ElmNone + ? subMatrixLayout == ElmRowMajor + : type.getQualifier().layoutMatrix == ElmRowMajor); RoundToPow2(offset, memberAlignment); if (m < index) offset += memberSize; @@ -162,7 +154,8 @@ public: int lastMemberSize; int dummyStride; - intermediate.getBaseAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride, blockType.getQualifier().layoutPacking == ElpStd140, + intermediate.getBaseAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride, + blockType.getQualifier().layoutPacking == ElpStd140, blockType.getQualifier().layoutMatrix == ElmRowMajor); return lastOffset + lastMemberSize; @@ -178,7 +171,7 @@ public: void blowUpActiveAggregate(const TType& baseType, const TString& baseName, const TList& derefs, TList::const_iterator deref, int offset, int blockIndex, int arraySize) { - // process the part of the derefence chain that was explicit in the shader + // process the part of the dereference chain that was explicit in the shader TString name = baseName; const TType* terminalType = &baseType; for (; deref != derefs.end(); ++deref) { @@ -188,7 +181,7 @@ public: switch (visitNode->getOp()) { case EOpIndexIndirect: // Visit all the indices of this array, and for each one add on the remaining dereferencing - for (int i = 0; i < visitNode->getLeft()->getType().getOuterArraySize(); ++i) { + for (int i = 0; i < std::max(visitNode->getLeft()->getType().getOuterArraySize(), 1); ++i) { TString newBaseName = name; if (baseType.getBasicType() != EbtBlock) newBaseName.append(TString("[") + String(i) + "]"); @@ -223,7 +216,7 @@ public: if (terminalType->isArray()) { // Visit all the indices of this array, and for each one, // fully explode the remaining aggregate to dereference - for (int i = 0; i < terminalType->getOuterArraySize(); ++i) { + for (int i = 0; i < std::max(terminalType->getOuterArraySize(), 1); ++i) { TString newBaseName = name; newBaseName.append(TString("[") + String(i) + "]"); TType derefType(*terminalType, 0); @@ -246,7 +239,7 @@ public: } // Finally, add a full string to the reflection database, and update the array size if necessary. - // If the derefenced entity to record is an array, compute the size and update the maximum size. + // If the dereferenced entity to record is an array, compute the size and update the maximum size. // there might not be a final array dereference, it could have been copied as an array object if (arraySize == 0) @@ -255,7 +248,9 @@ public: TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name); if (it == reflection.nameToIndex.end()) { reflection.nameToIndex[name] = (int)reflection.indexToUniform.size(); - reflection.indexToUniform.push_back(TObjectReflection(name, offset, mapToGlType(*terminalType), arraySize, blockIndex)); + reflection.indexToUniform.push_back(TObjectReflection(name, *terminalType, offset, + mapToGlType(*terminalType), + arraySize, blockIndex)); } else if (arraySize > 1) { int& reflectedArraySize = reflection.indexToUniform[it->second].size; reflectedArraySize = std::max(arraySize, reflectedArraySize); @@ -306,12 +301,18 @@ public: if (block) { offset = 0; anonymous = IsAnonymous(base->getName()); + + const TString& blockName = base->getType().getTypeName(); + if (base->getType().isArray()) { + TType derefType(base->getType(), 0); + assert(! anonymous); for (int e = 0; e < base->getType().getCumulativeArraySize(); ++e) - blockIndex = addBlockName(base->getType().getTypeName() + "[" + String(e) + "]", getBlockSize(base->getType())); + blockIndex = addBlockName(blockName + "[" + String(e) + "]", derefType, + getBlockSize(base->getType())); } else - blockIndex = addBlockName(base->getType().getTypeName(), getBlockSize(base->getType())); + blockIndex = addBlockName(blockName, base->getType(), getBlockSize(base->getType())); } // Process the dereference chain, backward, accumulating the pieces for later forward traversal. @@ -344,36 +345,20 @@ public: blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.begin(), offset, blockIndex, arraySize); } - int addBlockName(const TString& name, int size) + int addBlockName(const TString& name, const TType& type, int size) { int blockIndex; TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name); if (reflection.nameToIndex.find(name) == reflection.nameToIndex.end()) { blockIndex = (int)reflection.indexToUniformBlock.size(); reflection.nameToIndex[name] = blockIndex; - reflection.indexToUniformBlock.push_back(TObjectReflection(name, -1, -1, size, -1)); + reflection.indexToUniformBlock.push_back(TObjectReflection(name, type, -1, -1, size, -1)); } else blockIndex = it->second; return blockIndex; } - // - // Given a function name, find its subroot in the tree, and push it onto the stack of - // functions left to process. - // - void pushFunction(const TString& name) - { - TIntermSequence& globals = intermediate.getTreeRoot()->getAsAggregate()->getSequence(); - for (unsigned int f = 0; f < globals.size(); ++f) { - TIntermAggregate* candidate = globals[f]->getAsAggregate(); - if (candidate && candidate->getOp() == EOpFunction && candidate->getName() == name) { - functions.push_back(candidate); - break; - } - } - } - // Are we at a level in a dereference chain at which individual active uniform queries are made? bool isReflectionGranularity(const TType& type) { @@ -430,6 +415,36 @@ public: case EsdBuffer: return GL_SAMPLER_BUFFER; } +#ifdef AMD_EXTENSIONS + case EbtFloat16: + switch ((int)sampler.dim) { + case Esd1D: + switch ((int)sampler.shadow) { + case false: return sampler.arrayed ? GL_FLOAT16_SAMPLER_1D_ARRAY_AMD : GL_FLOAT16_SAMPLER_1D_AMD; + case true: return sampler.arrayed ? GL_FLOAT16_SAMPLER_1D_ARRAY_SHADOW_AMD : GL_FLOAT16_SAMPLER_1D_SHADOW_AMD; + } + case Esd2D: + switch ((int)sampler.ms) { + case false: + switch ((int)sampler.shadow) { + case false: return sampler.arrayed ? GL_FLOAT16_SAMPLER_2D_ARRAY_AMD : GL_FLOAT16_SAMPLER_2D_AMD; + case true: return sampler.arrayed ? GL_FLOAT16_SAMPLER_2D_ARRAY_SHADOW_AMD : GL_FLOAT16_SAMPLER_2D_SHADOW_AMD; + } + case true: return sampler.arrayed ? GL_FLOAT16_SAMPLER_2D_MULTISAMPLE_ARRAY_AMD : GL_FLOAT16_SAMPLER_2D_MULTISAMPLE_AMD; + } + case Esd3D: + return GL_FLOAT16_SAMPLER_3D_AMD; + case EsdCube: + switch ((int)sampler.shadow) { + case false: return sampler.arrayed ? GL_FLOAT16_SAMPLER_CUBE_MAP_ARRAY_AMD : GL_FLOAT16_SAMPLER_CUBE_AMD; + case true: return sampler.arrayed ? GL_FLOAT16_SAMPLER_CUBE_MAP_ARRAY_SHADOW_AMD : GL_FLOAT16_SAMPLER_CUBE_SHADOW_AMD; + } + case EsdRect: + return sampler.shadow ? GL_FLOAT16_SAMPLER_2D_RECT_SHADOW_AMD : GL_FLOAT16_SAMPLER_2D_RECT_AMD; + case EsdBuffer: + return GL_FLOAT16_SAMPLER_BUFFER_AMD; + } +#endif case EbtInt: switch ((int)sampler.dim) { case Esd1D: @@ -437,7 +452,8 @@ public: case Esd2D: switch ((int)sampler.ms) { case false: return sampler.arrayed ? GL_INT_SAMPLER_2D_ARRAY : GL_INT_SAMPLER_2D; - case true: return sampler.arrayed ? GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY : GL_INT_SAMPLER_2D_MULTISAMPLE; + case true: return sampler.arrayed ? GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY + : GL_INT_SAMPLER_2D_MULTISAMPLE; } case Esd3D: return GL_INT_SAMPLER_3D; @@ -455,7 +471,8 @@ public: case Esd2D: switch ((int)sampler.ms) { case false: return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_ARRAY : GL_UNSIGNED_INT_SAMPLER_2D; - case true: return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY : GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE; + case true: return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY + : GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE; } case Esd3D: return GL_UNSIGNED_INT_SAMPLER_3D; @@ -490,6 +507,26 @@ public: case EsdBuffer: return GL_IMAGE_BUFFER; } +#ifdef AMD_EXTENSIONS + case EbtFloat16: + switch ((int)sampler.dim) { + case Esd1D: + return sampler.arrayed ? GL_FLOAT16_IMAGE_1D_ARRAY_AMD : GL_FLOAT16_IMAGE_1D_AMD; + case Esd2D: + switch ((int)sampler.ms) { + case false: return sampler.arrayed ? GL_FLOAT16_IMAGE_2D_ARRAY_AMD : GL_FLOAT16_IMAGE_2D_AMD; + case true: return sampler.arrayed ? GL_FLOAT16_IMAGE_2D_MULTISAMPLE_ARRAY_AMD : GL_FLOAT16_IMAGE_2D_MULTISAMPLE_AMD; + } + case Esd3D: + return GL_FLOAT16_IMAGE_3D_AMD; + case EsdCube: + return sampler.arrayed ? GL_FLOAT16_IMAGE_CUBE_MAP_ARRAY_AMD : GL_FLOAT16_IMAGE_CUBE_AMD; + case EsdRect: + return GL_FLOAT16_IMAGE_2D_RECT_AMD; + case EsdBuffer: + return GL_FLOAT16_IMAGE_BUFFER_AMD; + } +#endif case EbtInt: switch ((int)sampler.dim) { case Esd1D: @@ -515,7 +552,8 @@ public: case Esd2D: switch ((int)sampler.ms) { case false: return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_ARRAY : GL_UNSIGNED_INT_IMAGE_2D; - case true: return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY : GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE; + case true: return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY + : GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE; } case Esd3D: return GL_UNSIGNED_INT_IMAGE_3D; @@ -554,6 +592,9 @@ public: switch (type.getBasicType()) { case EbtFloat: return GL_FLOAT_VEC2 + offset; case EbtDouble: return GL_DOUBLE_VEC2 + offset; +#ifdef AMD_EXTENSIONS + case EbtFloat16: return GL_FLOAT16_VEC2_NV + offset; +#endif case EbtInt: return GL_INT_VEC2 + offset; case EbtUint: return GL_UNSIGNED_INT_VEC2 + offset; case EbtInt64: return GL_INT64_ARB + offset; @@ -613,6 +654,32 @@ public: default: return 0; } } +#ifdef AMD_EXTENSIONS + case EbtFloat16: + switch (type.getMatrixCols()) { + case 2: + switch (type.getMatrixRows()) { + case 2: return GL_FLOAT16_MAT2_AMD; + case 3: return GL_FLOAT16_MAT2x3_AMD; + case 4: return GL_FLOAT16_MAT2x4_AMD; + default: return 0; + } + case 3: + switch (type.getMatrixRows()) { + case 2: return GL_FLOAT16_MAT3x2_AMD; + case 3: return GL_FLOAT16_MAT3_AMD; + case 4: return GL_FLOAT16_MAT3x4_AMD; + default: return 0; + } + case 4: + switch (type.getMatrixRows()) { + case 2: return GL_FLOAT16_MAT4x2_AMD; + case 3: return GL_FLOAT16_MAT4x3_AMD; + case 4: return GL_FLOAT16_MAT4_AMD; + default: return 0; + } + } +#endif default: return 0; } @@ -621,6 +688,9 @@ public: switch (type.getBasicType()) { case EbtFloat: return GL_FLOAT; case EbtDouble: return GL_DOUBLE; +#ifdef AMD_EXTENSIONS + case EbtFloat16: return GL_FLOAT16_NV; +#endif case EbtInt: return GL_INT; case EbtUint: return GL_UNSIGNED_INT; case EbtInt64: return GL_INT64_ARB; @@ -639,33 +709,21 @@ public: return type.isArray() ? type.getOuterArraySize() : 1; } - typedef std::list TFunctionStack; - TFunctionStack functions; - const TIntermediate& intermediate; TReflection& reflection; std::set processedDerefs; protected: - TLiveTraverser(TLiveTraverser&); - TLiveTraverser& operator=(TLiveTraverser&); + TReflectionTraverser(TReflectionTraverser&); + TReflectionTraverser& operator=(TReflectionTraverser&); }; // // Implement the traversal functions of interest. // -// To catch which function calls are not dead, and hence which functions must be visited. -bool TLiveTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node) -{ - if (node->getOp() == EOpFunctionCall) - addFunctionCall(node); - - return true; // traverse this subtree -} - // To catch dereferenced aggregates that must be reflected. // This catches them at the highest level possible in the tree. -bool TLiveTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node) +bool TReflectionTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node) { switch (node->getOp()) { case EOpIndexDirect: @@ -683,7 +741,7 @@ bool TLiveTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node) } // To reflect non-dereferenced objects. -void TLiveTraverser::visitSymbol(TIntermSymbol* base) +void TReflectionTraverser::visitSymbol(TIntermSymbol* base) { if (base->getQualifier().storage == EvqUniform) addUniform(*base); @@ -692,38 +750,50 @@ void TLiveTraverser::visitSymbol(TIntermSymbol* base) addAttribute(*base); } -// To prune semantically dead paths. -bool TLiveTraverser::visitSelection(TVisit /* visit */, TIntermSelection* node) -{ - TIntermConstantUnion* constant = node->getCondition()->getAsConstantUnion(); - if (constant) { - // cull the path that is dead - if (constant->getConstArray()[0].getBConst() == true && node->getTrueBlock()) - node->getTrueBlock()->traverse(this); - if (constant->getConstArray()[0].getBConst() == false && node->getFalseBlock()) - node->getFalseBlock()->traverse(this); - - return false; // don't traverse any more, we did it all above - } else - return true; // traverse the whole subtree -} - // // Implement TReflection methods. // +// Track any required attribute reflection, such as compute shader numthreads. +// +void TReflection::buildAttributeReflection(EShLanguage stage, const TIntermediate& intermediate) +{ + if (stage == EShLangCompute) { + // Remember thread dimensions + for (int dim=0; dim<3; ++dim) + localSize[dim] = intermediate.getLocalSize(dim); + } +} + +// build counter block index associations for buffers +void TReflection::buildCounterIndices(const TIntermediate& intermediate) +{ + // search for ones that have counters + for (int i = 0; i < int(indexToUniformBlock.size()); ++i) { + const TString counterName(intermediate.addCounterBufferName(indexToUniformBlock[i].name)); + const int index = getIndex(counterName); + + if (index >= 0) + indexToUniformBlock[i].counterIndex = index; + } +} + // Merge live symbols from 'intermediate' into the existing reflection database. // // Returns false if the input is too malformed to do this. -bool TReflection::addStage(EShLanguage, const TIntermediate& intermediate) +bool TReflection::addStage(EShLanguage stage, const TIntermediate& intermediate) { - if (intermediate.getNumMains() != 1 || intermediate.isRecursive()) + if (intermediate.getTreeRoot() == nullptr || + intermediate.getNumEntryPoints() != 1 || + intermediate.isRecursive()) return false; - TLiveTraverser it(intermediate, *this); + buildAttributeReflection(stage, intermediate); - // put main() on functions to process - it.pushFunction("main("); + TReflectionTraverser it(intermediate, *this); + + // put the entry point on the list of functions to process + it.pushFunction(intermediate.getEntryPointMangledName().c_str()); // process all the functions while (! it.functions.empty()) { @@ -732,6 +802,8 @@ bool TReflection::addStage(EShLanguage, const TIntermediate& intermediate) function->traverse(&it); } + buildCounterIndices(intermediate); + return true; } @@ -752,10 +824,20 @@ void TReflection::dump() indexToAttribute[i].dump(); printf("\n"); - //printf("Live names\n"); - //for (TNameToIndex::const_iterator it = nameToIndex.begin(); it != nameToIndex.end(); ++it) + 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: %d\n", axis[dim], getLocalSize(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); - //printf("\n"); + // printf("\n"); } } // end namespace glslang diff --git a/Externals/glslang/glslang/MachineIndependent/reflection.h b/Externals/glslang/glslang/MachineIndependent/reflection.h index 5d930c7a2a..bf233e33eb 100644 --- a/Externals/glslang/glslang/MachineIndependent/reflection.h +++ b/Externals/glslang/glslang/MachineIndependent/reflection.h @@ -1,11 +1,11 @@ // -//Copyright (C) 2013 LunarG, Inc. +// Copyright (C) 2013-2016 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,24 +19,25 @@ // 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. +// 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 _REFLECTION_INCLUDED #define _REFLECTION_INCLUDED #include "../Public/ShaderLang.h" +#include "../Include/Types.h" #include #include @@ -49,25 +50,56 @@ namespace glslang { class TIntermediate; class TIntermAggregate; -class TLiveTraverser; +class TReflectionTraverser; // Data needed for just a single object at the granularity exchanged by the reflection API class TObjectReflection { public: - TObjectReflection(const TString& pName, int pOffset, int pGLDefineType, int pSize, int pIndex) : - name(pName), offset(pOffset), glDefineType(pGLDefineType), size(pSize), index(pIndex) { } - void dump() const { printf("%s: offset %d, type %x, size %d, index %d\n", name.c_str(), offset, glDefineType, size, index); } + TObjectReflection(const TString& pName, const TType& pType, int pOffset, int pGLDefineType, int pSize, int pIndex) : + name(pName), offset(pOffset), + glDefineType(pGLDefineType), size(pSize), index(pIndex), counterIndex(-1), type(pType.clone()) { } + + const TType* const getType() const { return type; } + int getBinding() const + { + if (type == nullptr || !type->getQualifier().hasBinding()) + return -1; + return type->getQualifier().layoutBinding; + } + void dump() const + { + printf("%s: offset %d, type %x, size %d, index %d, binding %d", + name.c_str(), offset, glDefineType, size, index, getBinding() ); + + if (counterIndex != -1) + printf(", counter %d", counterIndex); + + printf("\n"); + } + static TObjectReflection badReflection() { return TObjectReflection(); } + TString name; int offset; int glDefineType; int size; // data size in bytes for a block, array size for a (non-block) object that's an array int index; + int counterIndex; + +protected: + TObjectReflection() : offset(-1), glDefineType(-1), size(-1), index(-1), type(nullptr) { } + + const TType* type; }; // The full reflection database class TReflection { public: - TReflection() : badReflection("__bad__", -1, -1, -1, -1) {} + TReflection() : badReflection(TObjectReflection::badReflection()) + { + for (int dim=0; dim<3; ++dim) + localSize[dim] = 0; + } + virtual ~TReflection() {} // grow the reflection stage by stage @@ -85,7 +117,7 @@ public: // for mapping a block index to the block's description int getNumUniformBlocks() const { return (int)indexToUniformBlock.size(); } - const TObjectReflection& getUniformBlock(int i) const + const TObjectReflection& getUniformBlock(int i) const { if (i >= 0 && i < (int)indexToUniformBlock.size()) return indexToUniformBlock[i]; @@ -104,7 +136,7 @@ public: } // for mapping any name to its index (block names, uniform names and attribute names) - int getIndex(const char* name) const + int getIndex(const char* name) const { TNameToIndex::const_iterator it = nameToIndex.find(name); if (it == nameToIndex.end()) @@ -113,10 +145,19 @@ public: return it->second; } + // see getIndex(const char*) + int getIndex(const TString& name) const { return getIndex(name.c_str()); } + + // Thread local size + unsigned getLocalSize(int dim) const { return dim <= 2 ? localSize[dim] : 0; } + void dump(); protected: - friend class glslang::TLiveTraverser; + friend class glslang::TReflectionTraverser; + + void buildCounterIndices(const TIntermediate&); + void buildAttributeReflection(EShLanguage, const TIntermediate&); // Need a TString hash: typedef std::unordered_map TNameToIndex; typedef std::map TNameToIndex; @@ -127,6 +168,8 @@ protected: TMapIndexToReflection indexToUniform; TMapIndexToReflection indexToUniformBlock; TMapIndexToReflection indexToAttribute; + + unsigned int localSize[3]; }; } // end namespace glslang diff --git a/Externals/glslang/glslang/OSDependent/Unix/CMakeLists.txt b/Externals/glslang/glslang/OSDependent/Unix/CMakeLists.txt index 174cc9167e..1bf49e1256 100644 --- a/Externals/glslang/glslang/OSDependent/Unix/CMakeLists.txt +++ b/Externals/glslang/glslang/OSDependent/Unix/CMakeLists.txt @@ -1,5 +1,8 @@ add_library(OSDependent STATIC ossource.cpp ../osinclude.h) set_property(TARGET OSDependent PROPERTY FOLDER glslang) +set_property(TARGET OSDependent PROPERTY POSITION_INDEPENDENT_CODE ON) -install(TARGETS OSDependent - ARCHIVE DESTINATION lib) +if(ENABLE_GLSLANG_INSTALL) + install(TARGETS OSDependent + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(ENABLE_GLSLANG_INSTALL) diff --git a/Externals/glslang/glslang/OSDependent/Unix/ossource.cpp b/Externals/glslang/glslang/OSDependent/Unix/ossource.cpp index 123e08697e..f59bbceb4a 100644 --- a/Externals/glslang/glslang/OSDependent/Unix/ossource.cpp +++ b/Externals/glslang/glslang/OSDependent/Unix/ossource.cpp @@ -1,10 +1,10 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -18,18 +18,18 @@ // 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. +// 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. // // @@ -43,6 +43,9 @@ #include #include #include +#include +#include +#include namespace glslang { @@ -51,140 +54,151 @@ namespace glslang { // // -// Wrapper for Linux call to DetachThread. This is required as pthread_cleanup_push() expects +// Wrapper for Linux call to DetachThread. This is required as pthread_cleanup_push() expects // the cleanup routine to return void. -// +// static void DetachThreadLinux(void *) { - DetachThread(); + DetachThread(); } - // // Registers cleanup handler, sets cancel type and state, and executes the thread specific -// cleanup handler. This function will be called in the Standalone.cpp for regression -// testing. When OpenGL applications are run with the driver code, Linux OS does the +// cleanup handler. This function will be called in the Standalone.cpp for regression +// testing. When OpenGL applications are run with the driver code, Linux OS does the // thread cleanup. -// +// void OS_CleanupThreadData(void) { #ifdef __ANDROID__ - DetachThreadLinux(NULL); + DetachThreadLinux(NULL); #else - int old_cancel_state, old_cancel_type; - void *cleanupArg = NULL; + int old_cancel_state, old_cancel_type; + void *cleanupArg = NULL; - // - // Set thread cancel state and push cleanup handler. - // - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancel_state); - pthread_cleanup_push(DetachThreadLinux, (void *) cleanupArg); + // + // Set thread cancel state and push cleanup handler. + // + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancel_state); + pthread_cleanup_push(DetachThreadLinux, (void *) cleanupArg); - // - // Put the thread in deferred cancellation mode. - // - pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old_cancel_type); + // + // Put the thread in deferred cancellation mode. + // + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old_cancel_type); - // - // Pop cleanup handler and execute it prior to unregistering the cleanup handler. - // - pthread_cleanup_pop(1); + // + // Pop cleanup handler and execute it prior to unregistering the cleanup handler. + // + pthread_cleanup_pop(1); - // - // Restore the thread's previous cancellation mode. - // - pthread_setcanceltype(old_cancel_state, NULL); + // + // Restore the thread's previous cancellation mode. + // + pthread_setcanceltype(old_cancel_state, NULL); #endif } - // // Thread Local Storage Operations // inline OS_TLSIndex PthreadKeyToTLSIndex(pthread_key_t key) { - return (OS_TLSIndex)((uintptr_t)key + 1); + return (OS_TLSIndex)((uintptr_t)key + 1); } inline pthread_key_t TLSIndexToPthreadKey(OS_TLSIndex nIndex) { - return (pthread_key_t)((uintptr_t)nIndex - 1); + return (pthread_key_t)((uintptr_t)nIndex - 1); } OS_TLSIndex OS_AllocTLSIndex() { - pthread_key_t pPoolIndex; + pthread_key_t pPoolIndex; - // - // Create global pool key. - // - if ((pthread_key_create(&pPoolIndex, NULL)) != 0) { - assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage"); - return OS_INVALID_TLS_INDEX; - } - else - return PthreadKeyToTLSIndex(pPoolIndex); + // + // Create global pool key. + // + if ((pthread_key_create(&pPoolIndex, NULL)) != 0) { + assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage"); + return OS_INVALID_TLS_INDEX; + } + else + return PthreadKeyToTLSIndex(pPoolIndex); } - bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue) { - if (nIndex == OS_INVALID_TLS_INDEX) { - assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); - return false; - } + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } - if (pthread_setspecific(TLSIndexToPthreadKey(nIndex), lpvValue) == 0) - return true; - else - return false; + if (pthread_setspecific(TLSIndexToPthreadKey(nIndex), lpvValue) == 0) + return true; + else + return false; } void* OS_GetTLSValue(OS_TLSIndex nIndex) { - // - // This function should return 0 if nIndex is invalid. - // - assert(nIndex != OS_INVALID_TLS_INDEX); - return pthread_getspecific(TLSIndexToPthreadKey(nIndex)); + // + // This function should return 0 if nIndex is invalid. + // + assert(nIndex != OS_INVALID_TLS_INDEX); + return pthread_getspecific(TLSIndexToPthreadKey(nIndex)); } bool OS_FreeTLSIndex(OS_TLSIndex nIndex) { - if (nIndex == OS_INVALID_TLS_INDEX) { - assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); - return false; - } + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } - // - // Delete the global pool key. - // - if (pthread_key_delete(TLSIndexToPthreadKey(nIndex)) == 0) - return true; - else - return false; + // + // Delete the global pool key. + // + if (pthread_key_delete(TLSIndexToPthreadKey(nIndex)) == 0) + return true; + else + return false; } -// TODO: non-windows: if we need these on linux, flesh them out -void InitGlobalLock() { } -void GetGlobalLock() { } -void ReleaseGlobalLock() { } +namespace { + pthread_mutex_t gMutex; +} -void* OS_CreateThread(TThreadEntrypoint entry) +void InitGlobalLock() { - return 0; + pthread_mutexattr_t mutexattr; + pthread_mutexattr_init(&mutexattr); + pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&gMutex, &mutexattr); } -void OS_WaitForAllThreads(void* threads, int numThreads) +void GetGlobalLock() { + pthread_mutex_lock(&gMutex); } -void OS_Sleep(int milliseconds) +void ReleaseGlobalLock() { + pthread_mutex_unlock(&gMutex); } +// #define DUMP_COUNTERS + void OS_DumpMemoryCounters() { +#ifdef DUMP_COUNTERS + struct rusage usage; + + if (getrusage(RUSAGE_SELF, &usage) == 0) + printf("Working set size: %ld\n", usage.ru_maxrss * 1024); +#else + printf("Recompile with DUMP_COUNTERS defined to see counters.\n"); +#endif } } // end namespace glslang diff --git a/Externals/glslang/glslang/OSDependent/Windows/CMakeLists.txt b/Externals/glslang/glslang/OSDependent/Windows/CMakeLists.txt index 399760c30a..f257418abb 100644 --- a/Externals/glslang/glslang/OSDependent/Windows/CMakeLists.txt +++ b/Externals/glslang/glslang/OSDependent/Windows/CMakeLists.txt @@ -2,16 +2,19 @@ set(SOURCES ossource.cpp ../osinclude.h) add_library(OSDependent STATIC ${SOURCES}) set_property(TARGET OSDependent PROPERTY FOLDER glslang) +set_property(TARGET OSDependent PROPERTY POSITION_INDEPENDENT_CODE ON) # MinGW GCC complains about function pointer casts to void*. # Turn that off with -fpermissive. if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") - target_compile_options(OSDependent PRIVATE -fpermissive) + target_compile_options(OSDependent PRIVATE -fpermissive) endif() if(WIN32) source_group("Source" FILES ${SOURCES}) endif(WIN32) -install(TARGETS OSDependent - ARCHIVE DESTINATION lib) +if(ENABLE_GLSLANG_INSTALL) + install(TARGETS OSDependent + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(ENABLE_GLSLANG_INSTALL) diff --git a/Externals/glslang/glslang/OSDependent/Windows/main.cpp b/Externals/glslang/glslang/OSDependent/Windows/main.cpp index 6d6b0fddcb..0bcde7b660 100644 --- a/Externals/glslang/glslang/OSDependent/Windows/main.cpp +++ b/Externals/glslang/glslang/OSDependent/Windows/main.cpp @@ -1,10 +1,10 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -18,18 +18,18 @@ // 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. +// 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. // #include "InitializeDll.h" diff --git a/Externals/glslang/glslang/OSDependent/Windows/ossource.cpp b/Externals/glslang/glslang/OSDependent/Windows/ossource.cpp index 1d09fd38a3..870840c56e 100644 --- a/Externals/glslang/glslang/OSDependent/Windows/ossource.cpp +++ b/Externals/glslang/glslang/OSDependent/Windows/ossource.cpp @@ -1,10 +1,10 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -18,18 +18,18 @@ // 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. +// 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. // #include "../osinclude.h" @@ -37,14 +37,14 @@ #define STRICT #define VC_EXTRALEAN 1 #include -#include +#include #include #include -#include -#include +#include +#include // -// This file contains contains the Window-OS-specific functions +// This file contains the Window-OS-specific functions // #if !(defined(_WIN32) || defined(_WIN64)) @@ -55,12 +55,12 @@ namespace glslang { inline OS_TLSIndex ToGenericTLSIndex (DWORD handle) { - return (OS_TLSIndex)((uintptr_t)handle + 1); + return (OS_TLSIndex)((uintptr_t)handle + 1); } inline DWORD ToNativeTLSIndex (OS_TLSIndex nIndex) { - return (DWORD)((uintptr_t)nIndex - 1); + return (DWORD)((uintptr_t)nIndex - 1); } // @@ -68,46 +68,45 @@ inline DWORD ToNativeTLSIndex (OS_TLSIndex nIndex) // OS_TLSIndex OS_AllocTLSIndex() { - DWORD dwIndex = TlsAlloc(); - if (dwIndex == TLS_OUT_OF_INDEXES) { - assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage"); - return OS_INVALID_TLS_INDEX; - } + DWORD dwIndex = TlsAlloc(); + if (dwIndex == TLS_OUT_OF_INDEXES) { + assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage"); + return OS_INVALID_TLS_INDEX; + } - return ToGenericTLSIndex(dwIndex); + return ToGenericTLSIndex(dwIndex); } - bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue) { - if (nIndex == OS_INVALID_TLS_INDEX) { - assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); - return false; - } + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } - if (TlsSetValue(ToNativeTLSIndex(nIndex), lpvValue)) - return true; - else - return false; + if (TlsSetValue(ToNativeTLSIndex(nIndex), lpvValue)) + return true; + else + return false; } void* OS_GetTLSValue(OS_TLSIndex nIndex) { - assert(nIndex != OS_INVALID_TLS_INDEX); - return TlsGetValue(ToNativeTLSIndex(nIndex)); + assert(nIndex != OS_INVALID_TLS_INDEX); + return TlsGetValue(ToNativeTLSIndex(nIndex)); } bool OS_FreeTLSIndex(OS_TLSIndex nIndex) { - if (nIndex == OS_INVALID_TLS_INDEX) { - assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); - return false; - } + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } - if (TlsFree(ToNativeTLSIndex(nIndex))) - return true; - else - return false; + if (TlsFree(ToNativeTLSIndex(nIndex))) + return true; + else + return false; } HANDLE GlobalLock; @@ -129,22 +128,7 @@ void ReleaseGlobalLock() unsigned int __stdcall EnterGenericThread (void* entry) { - return ((TThreadEntrypoint)entry)(0); -} - -void* OS_CreateThread(TThreadEntrypoint entry) -{ - return (void*)_beginthreadex(0, 0, EnterGenericThread, (void*)entry, 0, 0); -} - -void OS_WaitForAllThreads(void* threads, int numThreads) -{ - WaitForMultipleObjects(numThreads, (HANDLE*)threads, true, INFINITE); -} - -void OS_Sleep(int milliseconds) -{ - Sleep(milliseconds); + return ((TThreadEntrypoint)entry)(0); } //#define DUMP_COUNTERS diff --git a/Externals/glslang/glslang/OSDependent/osinclude.h b/Externals/glslang/glslang/OSDependent/osinclude.h index 33f880380f..218abe4f23 100644 --- a/Externals/glslang/glslang/OSDependent/osinclude.h +++ b/Externals/glslang/glslang/OSDependent/osinclude.h @@ -1,10 +1,10 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -18,18 +18,18 @@ // 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. +// 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 __OSINCLUDE_H @@ -53,11 +53,8 @@ void GetGlobalLock(); void ReleaseGlobalLock(); typedef unsigned int (*TThreadEntrypoint)(void*); -void* OS_CreateThread(TThreadEntrypoint); -void OS_WaitForAllThreads(void* threads, int numThreads); void OS_CleanupThreadData(void); -void OS_Sleep(int milliseconds); void OS_DumpMemoryCounters(); diff --git a/Externals/glslang/glslang/Public/ShaderLang.h b/Externals/glslang/glslang/Public/ShaderLang.h index 4b4d0fc640..5c629eeb88 100644 --- a/Externals/glslang/glslang/Public/ShaderLang.h +++ b/Externals/glslang/glslang/Public/ShaderLang.h @@ -1,10 +1,12 @@ // -//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -//All rights reserved. +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2013-2016 LunarG, Inc. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -18,18 +20,18 @@ // 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. +// 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 _COMPILER_INTERFACE_INCLUDED_ #define _COMPILER_INTERFACE_INCLUDED_ @@ -37,7 +39,8 @@ #include "../Include/ResourceLimits.h" #include "../MachineIndependent/Versions.h" -#include +#include +#include #ifdef _WIN32 #define C_DECL __cdecl @@ -64,16 +67,20 @@ extern "C" { #endif +// This should always increase, as some paths to do not consume +// a more major number. +// It should increment by one when new functionality is added. +#define GLSLANG_MINOR_VERSION 7 + // -// Driver must call this first, once, before doing any other -// compiler/linker operations. +// Call before doing any other compiler/linker operations. // // (Call once per process, not once per thread.) // SH_IMPORT_EXPORT int ShInitialize(); // -// Driver should call this at process shutdown. +// Call this at process shutdown to clean up memory. // SH_IMPORT_EXPORT int __fastcall ShFinalize(); @@ -101,11 +108,65 @@ typedef enum { namespace glslang { +class TType; + typedef enum { EShSourceNone, EShSourceGlsl, EShSourceHlsl, -} EShSource; // if EShLanguage were EShStage, this could be EShLanguage instead +} EShSource; // if EShLanguage were EShStage, this could be EShLanguage instead + +typedef enum { + EShClientNone, + EShClientVulkan, + EShClientOpenGL, +} EShClient; + +typedef enum { + EShTargetNone, + EShTargetSpv, // preferred spelling + EshTargetSpv = EShTargetSpv, // legacy spelling +} EShTargetLanguage; + +typedef enum { + EShTargetVulkan_1_0 = (1 << 22), + EShTargetVulkan_1_1 = (1 << 22) | (1 << 12), + EShTargetOpenGL_450 = 450, +} EShTargetClientVersion; + +typedef EShTargetClientVersion EshTargetClientVersion; + +typedef enum { + EShTargetSpv_1_0 = (1 << 16), + EShTargetSpv_1_3 = (1 << 16) | (3 << 8), +} EShTargetLanguageVersion; + +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 + EShClient dialect; + int dialectVersion; // version of client's language definition, not the client (when not EShClientNone) +}; + +struct TClient { + EShClient client; + EShTargetClientVersion version; // version of client itself (not the client's input dialect) +}; + +struct TTarget { + EShTargetLanguage language; + EShTargetLanguageVersion version; // version to target, if SPIR-V, defined by "word 1" of the SPIR-V header + bool hlslFunctionality1; // can target hlsl_functionality1 extension(s) +}; + +// All source/client/target versions and settings. +// Can override previous methods of setting, when items are set here. +// Expected to grow, as more are added, rather than growing parameter lists. +struct TEnvironment { + TInputLanguage input; // definition of the input language + TClient client; // what client is the overall compilation being done for? + TTarget target; // what to generate +}; const char* StageName(EShLanguage); @@ -129,6 +190,14 @@ typedef enum { EShOptFull, // Optimizations that will take more time } EShOptimizationLevel; +// +// Texture and Sampler transformation mode. +// +typedef enum { + EShTexSampTransKeep, // keep textures and samplers as is (default) + EShTexSampTransUpgradeTextureRemoveSampler, // change texture w/o embeded sampler into sampled texture and throw away all samplers +} EShTextureSamplerTransformMode; + // // Message choices for what errors and warnings are given. // @@ -142,6 +211,11 @@ enum EShMessages { EShMsgOnlyPreprocessor = (1 << 5), // only print out errors produced by the preprocessor EShMsgReadHlsl = (1 << 6), // use HLSL parsing rules and semantics EShMsgCascadingErrors = (1 << 7), // get cascading errors; risks error-recovery issues, instead of an early exit + EShMsgKeepUncalled = (1 << 8), // for testing, don't eliminate uncalled functions + EShMsgHlslOffsets = (1 << 9), // allow block offsets to follow HLSL rules instead of GLSL rules + EShMsgDebugInfo = (1 << 10), // save debug information + EShMsgHlslEnable16BitTypes = (1 << 11), // enable use of 16-bit types in SPIR-V for HLSL + EShMsgHlslLegalization = (1 << 12), // enable HLSL Legalization messages }; // @@ -160,9 +234,9 @@ typedef struct { // // ShHandle held by but opaque to the driver. It is allocated, -// managed, and de-allocated by the compiler/linker. It's contents +// managed, and de-allocated by the compiler/linker. It's contents // are defined by and used by the compiler and linker. For example, -// symbol table information and object code passed from the compiler +// symbol table information and object code passed from the compiler // to the linker can be stored where ShHandle points. // // If handle creation fails, 0 will be returned. @@ -182,7 +256,7 @@ SH_IMPORT_EXPORT void ShDestruct(ShHandle); // The return value of ShCompile is boolean, non-zero indicating // success. // -// The info-log should be written by ShCompile into +// The info-log should be written by ShCompile into // ShHandle, so it can answer future queries. // SH_IMPORT_EXPORT int ShCompile( @@ -198,14 +272,6 @@ SH_IMPORT_EXPORT int ShCompile( EShMessages messages = EShMsgDefault // warnings and errors ); -SH_IMPORT_EXPORT int ShLink( - const ShHandle, // linker object - const ShHandle h[], // compiler objects to link together - const int numHandles, - ShHandle uniformMap, // updated with new uniforms - short int** uniformsAccessed, // returned with indexes of uniforms accessed - int* numUniformsAccessed); - SH_IMPORT_EXPORT int ShLinkExt( const ShHandle, // linker object const ShHandle h[], // compiler objects to link together @@ -245,9 +311,9 @@ SH_IMPORT_EXPORT int ShGetUniformLocation(const ShHandle uniformMap, const char* // Deferred-Lowering C++ Interface // ----------------------------------- // -// Below is a new alternate C++ interface that might potentially replace the above -// opaque handle-based interface. -// +// Below is a new alternate C++ interface, which deprecates the above +// opaque handle-based interface. +// // The below is further designed to handle multiple compilation units per stage, where // the intermediate results, including the parse tree, are preserved until link time, // rather than the above interface which is designed to have each compilation unit @@ -279,11 +345,26 @@ bool InitializeProcess(); // Call once per process to tear down everything void FinalizeProcess(); -// Make one TShader per shader that you will link into a program. Then provide -// the shader through setStrings() or setStringsWithLengths(), then call parse(), -// then query the info logs. -// Optionally use setPreamble() to set a special shader string that will be -// processed before all others but won't affect the validity of #version. +// Resource type for IO resolver +enum TResourceType { + EResSampler, + EResTexture, + EResImage, + EResUbo, + EResSsbo, + EResUav, + EResCount +}; + +// Make one TShader per shader that you will link into a program. Then +// - provide the shader through setStrings() or setStringsWithLengths() +// - optionally call setEnv*(), see below for more detail +// - optionally use setPreamble() to set a special shader string that will be +// processed before all others but won't affect the validity of #version +// - call parse(): source language and target environment must be selected +// either by correct setting of EShMessages sent to parse(), or by +// explicitly calling setEnv*() +// - query the info logs // // N.B.: Does not yet support having the same TShader instance being linked into // multiple programs. @@ -300,6 +381,51 @@ public: const char* const* s, const int* l, const char* const* names, int n); void setPreamble(const char* s) { preamble = s; } void setEntryPoint(const char* entryPoint); + void setSourceEntryPoint(const char* sourceEntryPointName); + void addProcesses(const std::vector&); + + // IO resolver binding data: see comments in ShaderLang.cpp + 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& base); + void setAutoMapBindings(bool map); + void setAutoMapLocations(bool map); + void setInvertY(bool invert); + void setHlslIoMapping(bool hlslIoMap); + void setFlattenUniformArrays(bool flatten); + void setNoStorageFormat(bool useUnknownFormat); + void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode); + + // 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 + // target environment, either indirectly through TranslateEnvironment() based on + // EShMessages et. al., or directly by the user. + void setEnvInput(EShSource lang, EShLanguage envStage, EShClient client, int version) + { + environment.input.languageFamily = lang; + environment.input.stage = envStage; + environment.input.dialect = client; + environment.input.dialectVersion = version; + } + void setEnvClient(EShClient client, EShTargetClientVersion version) + { + environment.client.client = client; + environment.client.version = version; + } + void setEnvTarget(EShTargetLanguage lang, EShTargetLanguageVersion version) + { + environment.target.language = lang; + environment.target.version = version; + } + void setEnvTargetHlslFunctionality1() { environment.target.hlslFunctionality1 = true; } + bool getEnvTargetHlslFunctionality1() const { return environment.target.hlslFunctionality1; } // Interface to #include handlers. // @@ -318,83 +444,94 @@ public: // release the IncludeResult object. class Includer { public: - typedef enum { - EIncludeRelative, // For #include "something" - EIncludeStandard // Reserved. For #include - } IncludeType; - // An IncludeResult contains the resolved name and content of a source // inclusion. struct IncludeResult { - IncludeResult(const std::string& file_name, const char* const file_data, const size_t file_length, void* user_data) : - file_name(file_name), file_data(file_data), file_length(file_length), user_data(user_data) { } + IncludeResult(const std::string& headerName, const char* const headerData, const size_t headerLength, void* userData) : + headerName(headerName), headerData(headerData), headerLength(headerLength), userData(userData) { } // For a successful inclusion, the fully resolved name of the requested // include. For example, in a file system-based includer, full resolution // should convert a relative path name into an absolute path name. // For a failed inclusion, this is an empty string. - const std::string file_name; + const std::string headerName; // The content and byte length of the requested inclusion. The // Includer producing this IncludeResult retains ownership of the // storage. - // For a failed inclusion, the file_data + // For a failed inclusion, the header // field points to a string containing error details. - const char* const file_data; - const size_t file_length; + const char* const headerData; + const size_t headerLength; // Include resolver's context. - void* user_data; + void* userData; protected: IncludeResult& operator=(const IncludeResult&); IncludeResult(); }; - // Resolves an inclusion request by name, type, current source name, + // For both include methods below: + // + // Resolves an inclusion request by name, current source name, // and include depth. // On success, returns an IncludeResult containing the resolved name - // and content of the include. On failure, returns an IncludeResult - // with an empty string for the file_name and error details in the - // file_data field. The Includer retains ownership of the contents + // and content of the include. + // On failure, returns a nullptr, or an IncludeResult + // with an empty string for the headerName and error details in the + // header field. + // The Includer retains ownership of the contents // of the returned IncludeResult value, and those contents must // remain valid until the releaseInclude method is called on that // IncludeResult object. - virtual IncludeResult* include(const char* requested_source, - IncludeType type, - const char* requesting_source, - size_t inclusion_depth) = 0; + // + // Note "local" vs. "system" is not an "either/or": "local" is an + // extra thing to do over "system". Both might get called, as per + // the C++ specification. + + // For the "system" or <>-style includes; search the "system" paths. + virtual IncludeResult* includeSystem(const char* /*headerName*/, + const char* /*includerName*/, + size_t /*inclusionDepth*/) { return nullptr; } + + // For the "local"-only aspect of a "" include. Should not search in the + // "system" paths, because on returning a failure, the parser will + // call includeSystem() to look in the "system" locations. + virtual IncludeResult* includeLocal(const char* /*headerName*/, + const char* /*includerName*/, + size_t /*inclusionDepth*/) { return nullptr; } + // Signals that the parser will no longer use the contents of the // specified IncludeResult. - virtual void releaseInclude(IncludeResult* result) = 0; -#ifdef __ANDROID__ - virtual ~Includer() {} // Pacify -Werror=non-virtual-dtor -#endif + virtual void releaseInclude(IncludeResult*) = 0; + virtual ~Includer() {} }; - // Returns an error message for any #include directive. - class ForbidInclude : public Includer { + // Fail all Includer searches + class ForbidIncluder : public Includer { public: - IncludeResult* include(const char*, IncludeType, const char*, size_t) override - { - const char* unexpected_include = "unexpected include directive"; - return new IncludeResult(std::string(""), unexpected_include, strlen(unexpected_include), nullptr); - } - virtual void releaseInclude(IncludeResult* result) override - { - delete result; - } + virtual void releaseInclude(IncludeResult*) override { } }; - bool parse(const TBuiltInResource* res, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile, - bool forwardCompatible, EShMessages messages) - { - TShader::ForbidInclude includer; - return parse(res, defaultVersion, defaultProfile, forceDefaultVersionAndProfile, forwardCompatible, messages, includer); - } - bool parse(const TBuiltInResource*, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile, bool forwardCompatible, EShMessages, Includer&); + bool parse(const TBuiltInResource* res, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile, + bool forwardCompatible, EShMessages messages) + { + TShader::ForbidIncluder includer; + return parse(res, defaultVersion, defaultProfile, forceDefaultVersionAndProfile, forwardCompatible, messages, includer); + } + // Equivalent to parse() without a default profile and without forcing defaults. - // Provided for backwards compatibility. - bool parse(const TBuiltInResource*, int defaultVersion, bool forwardCompatible, EShMessages); + bool parse(const TBuiltInResource* builtInResources, int defaultVersion, bool forwardCompatible, EShMessages messages) + { + return parse(builtInResources, defaultVersion, ENoProfile, false, forwardCompatible, messages); + } + + bool parse(const TBuiltInResource* builtInResources, int defaultVersion, bool forwardCompatible, EShMessages messages, + Includer& includer) + { + return parse(builtInResources, defaultVersion, ENoProfile, false, forwardCompatible, messages, includer); + } + bool preprocess(const TBuiltInResource* builtInResources, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile, bool forwardCompatible, EShMessages message, std::string* outputString, @@ -402,8 +539,8 @@ public: const char* getInfoLog(); const char* getInfoDebugLog(); - EShLanguage getStage() const { return stage; } + TIntermediate* getIntermediate() const { return intermediate; } protected: TPoolAllocator* pool; @@ -426,6 +563,11 @@ protected: const char* preamble; int numStrings; + // a function in the source string can be renamed FROM this TO the name given in setEntryPoint. + std::string sourceEntryPointName; + + TEnvironment environment; + friend class TProgram; private: @@ -433,8 +575,75 @@ private: }; class TReflection; +class TIoMapper; -// Make one TProgram per set of shaders that will get linked together. Add all +// Allows to customize the binding layout after linking. +// All used uniform variables will invoke at least validateBinding. +// If validateBinding returned true then the other resolveBinding, +// resolveSet, and resolveLocation are invoked to resolve the binding +// and descriptor set index respectively. +// +// Invocations happen in a particular order: +// 1) all shader inputs +// 2) all shader outputs +// 3) all uniforms with binding and set already defined +// 4) all uniforms with binding but no set defined +// 5) all uniforms with set but no binding defined +// 6) all uniforms with no binding and no set defined +// +// mapIO will use this resolver in two phases. The first +// phase is a notification phase, calling the corresponging +// notifiy callbacks, this phase ends with a call to endNotifications. +// Phase two starts directly after the call to endNotifications +// and calls all other callbacks to validate and to get the +// bindings, sets, locations, component and color indices. +// +// NOTE: that still limit checks are applied to bindings and sets +// and may result in an error. +class TIoMapResolver +{ +public: + virtual ~TIoMapResolver() {} + + // Should return true if the resulting/current binding would be okay. + // Basic idea is to do aliasing binding checks with this. + virtual bool validateBinding(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0; + // Should return a value >= 0 if the current binding should be overridden. + // Return -1 if the current binding (including no binding) should be kept. + virtual int resolveBinding(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0; + // Should return a value >= 0 if the current set should be overridden. + // Return -1 if the current set (including no set) should be kept. + virtual int resolveSet(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0; + // Should return a value >= 0 if the current location should be overridden. + // Return -1 if the current location (including no location) should be kept. + virtual int resolveUniformLocation(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0; + // Should return true if the resulting/current setup would be okay. + // Basic idea is to do aliasing checks and reject invalid semantic names. + virtual bool validateInOut(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0; + // Should return a value >= 0 if the current location should be overridden. + // Return -1 if the current location (including no location) should be kept. + virtual int resolveInOutLocation(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0; + // Should return a value >= 0 if the current component index should be overridden. + // Return -1 if the current component index (including no index) should be kept. + virtual int resolveInOutComponent(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0; + // Should return a value >= 0 if the current color index should be overridden. + // Return -1 if the current color index (including no index) should be kept. + virtual int resolveInOutIndex(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0; + // Notification of a uniform variable + virtual void notifyBinding(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0; + // Notification of a in or out variable + virtual void notifyInOut(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0; + // Called by mapIO when it has finished the notify pass + virtual void endNotifications(EShLanguage stage) = 0; + // Called by mapIO when it starts its notify pass for the given stage + virtual void beginNotifications(EShLanguage stage) = 0; + // Called by mipIO when it starts its resolve pass for the given stage + virtual void beginResolve(EShLanguage stage) = 0; + // Called by mapIO when it has finished the resolve pass + virtual void endResolve(EShLanguage stage) = 0; +}; + +// 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(). // @@ -455,21 +664,34 @@ public: // Reflection Interface bool buildReflection(); // call first, to do liveness analysis, index mapping, etc.; returns false on failure - int getNumLiveUniformVariables(); // can be used for glGetProgramiv(GL_ACTIVE_UNIFORMS) - int getNumLiveUniformBlocks(); // can be used for glGetProgramiv(GL_ACTIVE_UNIFORM_BLOCKS) - const char* getUniformName(int index); // can be used for "name" part of glGetActiveUniform() - const char* getUniformBlockName(int blockIndex); // can be used for glGetActiveUniformBlockName() - int getUniformBlockSize(int blockIndex); // can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE) - int getUniformIndex(const char* name); // can be used for glGetUniformIndices() - int getUniformBlockIndex(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_BLOCK_INDEX) - int getUniformType(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_TYPE) - int getUniformBufferOffset(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_OFFSET) - int getUniformArraySize(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_SIZE) - int getNumLiveAttributes(); // can be used for glGetProgramiv(GL_ACTIVE_ATTRIBUTES) - const char *getAttributeName(int index); // can be used for glGetActiveAttrib() - int getAttributeType(int index); // can be used for glGetActiveAttrib() + int getNumLiveUniformVariables() const; // can be used for glGetProgramiv(GL_ACTIVE_UNIFORMS) + int getNumLiveUniformBlocks() const; // can be used for glGetProgramiv(GL_ACTIVE_UNIFORM_BLOCKS) + const char* getUniformName(int index) const; // can be used for "name" part of glGetActiveUniform() + const char* getUniformBlockName(int blockIndex) const; // can be used for glGetActiveUniformBlockName() + int getUniformBlockSize(int blockIndex) const; // can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE) + int getUniformIndex(const char* name) const; // can be used for glGetUniformIndices() + int getUniformBinding(int index) const; // returns the binding number + int getUniformBlockBinding(int index) const; // returns the block binding number + int getUniformBlockIndex(int index) const; // can be used for glGetActiveUniformsiv(GL_UNIFORM_BLOCK_INDEX) + int getUniformBlockCounterIndex(int index) const; // returns block index of associated counter. + int getUniformType(int index) const; // can be used for glGetActiveUniformsiv(GL_UNIFORM_TYPE) + int getUniformBufferOffset(int index) const; // can be used for glGetActiveUniformsiv(GL_UNIFORM_OFFSET) + int getUniformArraySize(int index) const; // can be used for glGetActiveUniformsiv(GL_UNIFORM_SIZE) + int getNumLiveAttributes() const; // can be used for glGetProgramiv(GL_ACTIVE_ATTRIBUTES) + unsigned getLocalSize(int dim) const; // return dim'th local size + const char *getAttributeName(int index) const; // can be used for glGetActiveAttrib() + int getAttributeType(int index) const; // can be used for glGetActiveAttrib() + const TType* getUniformTType(int index) const; // returns a TType* + const TType* getUniformBlockTType(int index) const; // returns a TType* + const TType* getAttributeTType(int index) const; // returns a TType* + void dumpReflection(); + // 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. + bool mapIO(TIoMapResolver* resolver = NULL); + protected: bool linkStage(EShLanguage, EShMessages); @@ -479,9 +701,11 @@ protected: bool newedIntermediate[EShLangCount]; // track which intermediate were "new" versus reusing a singleton unit in a stage TInfoSink* infoSink; TReflection* reflection; + TIoMapper* ioMapper; bool linked; private: + TProgram(TProgram&); TProgram& operator=(TProgram&); }; diff --git a/Externals/glslang/gtests/AST.FromFile.cpp b/Externals/glslang/gtests/AST.FromFile.cpp old mode 100644 new mode 100755 index 6f4abef1ff..b89fc51564 --- a/Externals/glslang/gtests/AST.FromFile.cpp +++ b/Externals/glslang/gtests/AST.FromFile.cpp @@ -41,13 +41,27 @@ namespace { using CompileToAstTest = GlslangTest<::testing::TestWithParam>; +#ifdef NV_EXTENSIONS +using CompileToAstTestNV = GlslangTest<::testing::TestWithParam>; +#endif + TEST_P(CompileToAstTest, FromFile) { - loadFileCompileAndCheck(GLSLANG_TEST_DIRECTORY, GetParam(), - Source::GLSL, Semantics::OpenGL, + loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam(), + Source::GLSL, Semantics::OpenGL, glslang::EShTargetVulkan_1_0, Target::AST); } +#ifdef NV_EXTENSIONS +// Compiling GLSL to SPIR-V under OpenGL semantics (NV extensions enabled). +TEST_P(CompileToAstTestNV, FromFile) +{ + loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam(), + Source::GLSL, Semantics::OpenGL, glslang::EShTargetVulkan_1_0, + Target::AST); +} +#endif + // clang-format off INSTANTIATE_TEST_CASE_P( Glsl, CompileToAstTest, @@ -62,6 +76,7 @@ INSTANTIATE_TEST_CASE_P( "versionsErrors.frag", "versionsErrors.vert", "100.frag", + "100samplerExternal.frag", "120.vert", "120.frag", "130.vert", @@ -77,8 +92,14 @@ INSTANTIATE_TEST_CASE_P( "matrixError.vert", "cppSimple.vert", "cppIndent.vert", + "cppIntMinOverNegativeOne.frag", "cppNest.vert", + "cppBad.vert", + "cppBad2.vert", "cppComplexExpr.vert", + "cppDeepNest.frag", + "cppPassMacroName.frag", + "cppRelaxSkipTokensErrors.vert", "badChars.frag", "pointCoord.frag", "array.frag", @@ -91,6 +112,7 @@ INSTANTIATE_TEST_CASE_P( "300layout.frag", "300operations.frag", "300block.frag", + "300samplerExternal.frag", "310.comp", "310.vert", "310.geom", @@ -99,10 +121,18 @@ INSTANTIATE_TEST_CASE_P( "310.tese", "310implicitSizeArrayError.vert", "310AofA.vert", + "310runtimeArray.vert", + "320.comp", + "320.vert", + "320.geom", + "320.frag", + "320.tesc", + "320.tese", "330.frag", "330comp.frag", "constErrors.frag", "constFold.frag", + "constFoldIntMin.frag", "errors.frag", "forwardRef.frag", "uint.frag", @@ -134,6 +164,7 @@ INSTANTIATE_TEST_CASE_P( "430.vert", "430.comp", "430AofA.frag", + "435.vert", "440.vert", "440.frag", "450.vert", @@ -142,8 +173,11 @@ INSTANTIATE_TEST_CASE_P( "450.tese", "450.frag", "450.comp", + "460.frag", + "460.vert", "dce.frag", "atomic_uint.frag", + "implicitInnerAtomicUint.frag", "aggOps.frag", "always-discard.frag", "always-discard2.frag", @@ -166,17 +200,24 @@ INSTANTIATE_TEST_CASE_P( "loopsArtificial.frag", "matrix.frag", "matrix2.frag", + "mixedArrayDecls.frag", + "nonuniform.frag", "newTexture.frag", "Operations.frag", + "overlongLiteral.frag", "prepost.frag", + "runtimeArray.vert", "simpleFunctionCall.frag", + "stringToDouble.vert", "structAssignment.frag", "structDeref.frag", "structure.frag", "swizzle.frag", + "invalidSwizzle.vert", "syntaxError.frag", "test.frag", "texture.frag", + "tokenPaste.vert", "types.frag", "uniformArray.frag", "variableArrayIndex.frag", @@ -189,9 +230,20 @@ INSTANTIATE_TEST_CASE_P( "precise.tesc", "precise_struct_block.vert", "maxClipDistances.vert", + "findFunction.frag", })), FileNameAsCustomTestSuffix ); + +#ifdef NV_EXTENSIONS +INSTANTIATE_TEST_CASE_P( + Glsl, CompileToAstTestNV, + ::testing::ValuesIn(std::vector({ + "nvShaderNoperspectiveInterpolation.frag", + })), + FileNameAsCustomTestSuffix +); +#endif // clang-format on } // anonymous namespace diff --git a/Externals/glslang/gtests/BuiltInResource.FromFile.cpp b/Externals/glslang/gtests/BuiltInResource.FromFile.cpp index 4d68d873bb..da81fe98c3 100644 --- a/Externals/glslang/gtests/BuiltInResource.FromFile.cpp +++ b/Externals/glslang/gtests/BuiltInResource.FromFile.cpp @@ -46,7 +46,7 @@ using DefaultResourceTest = GlslangTest<::testing::Test>; TEST_F(DefaultResourceTest, FromFile) { - const std::string path = GLSLANG_TEST_DIRECTORY "/baseResults/test.conf"; + const std::string path = GlobalTestSettings.testRoot + "/baseResults/test.conf"; std::string expectedConfig; tryLoadFile(path, "expected resource limit", &expectedConfig); const std::string realConfig = glslang::GetDefaultTBuiltInResourceString(); diff --git a/Externals/glslang/gtests/CMakeLists.txt b/Externals/glslang/gtests/CMakeLists.txt index 4aafd11f31..15b73f4bde 100644 --- a/Externals/glslang/gtests/CMakeLists.txt +++ b/Externals/glslang/gtests/CMakeLists.txt @@ -1,40 +1,59 @@ -if (TARGET gmock) - message(STATUS "Google Mock found - building tests") +if(BUILD_TESTING) + if(TARGET gmock) + message(STATUS "Google Mock found - building tests") - set(TEST_SOURCES - # Framework related source files - ${CMAKE_CURRENT_SOURCE_DIR}/Initializer.h - ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Settings.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Settings.h - ${CMAKE_CURRENT_SOURCE_DIR}/TestFixture.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/TestFixture.h + set(TEST_SOURCES + # Framework related source files + ${CMAKE_CURRENT_SOURCE_DIR}/Initializer.h + ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Settings.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Settings.h + ${CMAKE_CURRENT_SOURCE_DIR}/TestFixture.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/TestFixture.h - # Test related source files - ${CMAKE_CURRENT_SOURCE_DIR}/AST.FromFile.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/BuiltInResource.FromFile.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Config.FromFile.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Hlsl.FromFile.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Link.FromFile.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Pp.FromFile.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Spv.FromFile.cpp - ) + # Test related source files + ${CMAKE_CURRENT_SOURCE_DIR}/AST.FromFile.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/BuiltInResource.FromFile.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Config.FromFile.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/HexFloat.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Hlsl.FromFile.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Link.FromFile.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Link.FromFile.Vk.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Pp.FromFile.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Spv.FromFile.cpp - add_executable(glslangtests ${TEST_SOURCES}) - set_property(TARGET glslangtests PROPERTY FOLDER tests) - glslang_set_link_args(glslangtests) - install(TARGETS glslangtests - RUNTIME DESTINATION bin) + # -- Remapper tests + ${CMAKE_CURRENT_SOURCE_DIR}/Remap.FromFile.cpp) - target_compile_definitions(glslangtests - PRIVATE GLSLANG_TEST_DIRECTORY="${CMAKE_CURRENT_SOURCE_DIR}/../Test") - target_include_directories(glslangtests PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} - ${PROJECT_SOURCE_DIR} - ${gmock_SOURCE_DIR}/include - ${gtest_SOURCE_DIR}/include) - target_link_libraries(glslangtests PRIVATE - glslang OSDependent OGLCompiler HLSL glslang - SPIRV glslang-default-resource-limits gmock) - add_test(NAME glslang-gtests COMMAND glslangtests) + add_executable(glslangtests ${TEST_SOURCES}) + set_property(TARGET glslangtests PROPERTY FOLDER tests) + glslang_set_link_args(glslangtests) + if(ENABLE_GLSLANG_INSTALL) + install(TARGETS glslangtests + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + endif(ENABLE_GLSLANG_INSTALL) + + set(GLSLANG_TEST_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../Test") + # Supply a default test root directory, so that manual testing + # doesn't have to specify the --test-root option in the normal + # case that you want to use the tests from the same source tree. + target_compile_definitions(glslangtests + PRIVATE GLSLANG_TEST_DIRECTORY="${GLSLANG_TEST_DIRECTORY}") + target_include_directories(glslangtests PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${PROJECT_SOURCE_DIR} + ${gmock_SOURCE_DIR}/include + ${gtest_SOURCE_DIR}/include) + + set(LIBRARIES + SPVRemapper glslang OSDependent OGLCompiler glslang + SPIRV glslang-default-resource-limits) + if(ENABLE_HLSL) + set(LIBRARIES ${LIBRARIES} HLSL) + endif(ENABLE_HLSL) + target_link_libraries(glslangtests PRIVATE ${LIBRARIES} gmock) + + add_test(NAME glslang-gtests + COMMAND glslangtests --test-root "${GLSLANG_TEST_DIRECTORY}") + endif() endif() diff --git a/Externals/glslang/gtests/Config.FromFile.cpp b/Externals/glslang/gtests/Config.FromFile.cpp index 7bc6a70e21..f3a27724d1 100644 --- a/Externals/glslang/gtests/Config.FromFile.cpp +++ b/Externals/glslang/gtests/Config.FromFile.cpp @@ -54,8 +54,8 @@ TEST_P(ConfigTest, FromFile) // Get the contents for input shader and limit configurations. std::string shaderContents, configContents; - tryLoadFile(GLSLANG_TEST_DIRECTORY "/" + testCase.input, "input", &shaderContents); - tryLoadFile(GLSLANG_TEST_DIRECTORY "/" + testCase.config, "limits config", &configContents); + tryLoadFile(GlobalTestSettings.testRoot + "/" + testCase.input, "input", &shaderContents); + tryLoadFile(GlobalTestSettings.testRoot + "/" + testCase.config, "limits config", &configContents); // Decode limit configurations. TBuiltInResource resources = {}; @@ -86,7 +86,7 @@ TEST_P(ConfigTest, FromFile) // Check with expected results. const std::string expectedOutputFname = - GLSLANG_TEST_DIRECTORY "/baseResults/" + testCase.output; + GlobalTestSettings.testRoot + "/baseResults/" + testCase.output; std::string expectedOutput; tryLoadFile(expectedOutputFname, "expected output", &expectedOutput); @@ -97,7 +97,7 @@ TEST_P(ConfigTest, FromFile) INSTANTIATE_TEST_CASE_P( Glsl, ConfigTest, ::testing::ValuesIn(std::vector({ - {"specExamples.vert", "baseResults/test.conf", "specExamples.vert.out", (EShMessages)(EShMsgAST | EShMsgCascadingErrors)}, + {"specExamples.vert", "baseResults/test.conf", "specExamplesConf.vert.out", (EShMessages)(EShMsgAST | EShMsgCascadingErrors)}, {"100Limits.vert", "100.conf", "100LimitsConf.vert.out", EShMsgCascadingErrors}, })), ); diff --git a/Externals/glslang/gtests/HexFloat.cpp b/Externals/glslang/gtests/HexFloat.cpp new file mode 100644 index 0000000000..ddbee1f464 --- /dev/null +++ b/Externals/glslang/gtests/HexFloat.cpp @@ -0,0 +1,1231 @@ +// Copyright (c) 2015-2016 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include + +#include +#include "SPIRV/hex_float.h" + +namespace { +using ::testing::Eq; +using spvutils::BitwiseCast; +using spvutils::Float16; +using spvutils::FloatProxy; +using spvutils::HexFloat; +using spvutils::ParseNormalFloat; + +// In this file "encode" means converting a number into a string, +// and "decode" means converting a string into a number. + +using HexFloatTest = + ::testing::TestWithParam, std::string>>; +using DecodeHexFloatTest = + ::testing::TestWithParam>>; +using HexDoubleTest = + ::testing::TestWithParam, std::string>>; +using DecodeHexDoubleTest = + ::testing::TestWithParam>>; + +// Hex-encodes a float value. +template +std::string EncodeViaHexFloat(const T& value) { + std::stringstream ss; + ss << spvutils::HexFloat(value); + return ss.str(); +} + +// The following two tests can't be DRY because they take different parameter +// types. + +TEST_P(HexFloatTest, EncodeCorrectly) { + EXPECT_THAT(EncodeViaHexFloat(GetParam().first), Eq(GetParam().second)); +} + +TEST_P(HexDoubleTest, EncodeCorrectly) { + EXPECT_THAT(EncodeViaHexFloat(GetParam().first), Eq(GetParam().second)); +} + +// Decodes a hex-float string. +template +FloatProxy Decode(const std::string& str) { + spvutils::HexFloat> decoded(0.f); + EXPECT_TRUE((std::stringstream(str) >> decoded).eof()); + return decoded.value(); +} + +TEST_P(HexFloatTest, DecodeCorrectly) { + EXPECT_THAT(Decode(GetParam().second), Eq(GetParam().first)); +} + +TEST_P(HexDoubleTest, DecodeCorrectly) { + EXPECT_THAT(Decode(GetParam().second), Eq(GetParam().first)); +} + +INSTANTIATE_TEST_CASE_P( + Float32Tests, HexFloatTest, + ::testing::ValuesIn(std::vector, std::string>>({ + {0.f, "0x0p+0"}, + {1.f, "0x1p+0"}, + {2.f, "0x1p+1"}, + {3.f, "0x1.8p+1"}, + {0.5f, "0x1p-1"}, + {0.25f, "0x1p-2"}, + {0.75f, "0x1.8p-1"}, + {-0.f, "-0x0p+0"}, + {-1.f, "-0x1p+0"}, + {-0.5f, "-0x1p-1"}, + {-0.25f, "-0x1p-2"}, + {-0.75f, "-0x1.8p-1"}, + + // Larger numbers + {512.f, "0x1p+9"}, + {-512.f, "-0x1p+9"}, + {1024.f, "0x1p+10"}, + {-1024.f, "-0x1p+10"}, + {1024.f + 8.f, "0x1.02p+10"}, + {-1024.f - 8.f, "-0x1.02p+10"}, + + // Small numbers + {1.0f / 512.f, "0x1p-9"}, + {1.0f / -512.f, "-0x1p-9"}, + {1.0f / 1024.f, "0x1p-10"}, + {1.0f / -1024.f, "-0x1p-10"}, + {1.0f / 1024.f + 1.0f / 8.f, "0x1.02p-3"}, + {1.0f / -1024.f - 1.0f / 8.f, "-0x1.02p-3"}, + + // lowest non-denorm + {float(ldexp(1.0f, -126)), "0x1p-126"}, + {float(ldexp(-1.0f, -126)), "-0x1p-126"}, + + // Denormalized values + {float(ldexp(1.0f, -127)), "0x1p-127"}, + {float(ldexp(1.0f, -127) / 2.0f), "0x1p-128"}, + {float(ldexp(1.0f, -127) / 4.0f), "0x1p-129"}, + {float(ldexp(1.0f, -127) / 8.0f), "0x1p-130"}, + {float(ldexp(-1.0f, -127)), "-0x1p-127"}, + {float(ldexp(-1.0f, -127) / 2.0f), "-0x1p-128"}, + {float(ldexp(-1.0f, -127) / 4.0f), "-0x1p-129"}, + {float(ldexp(-1.0f, -127) / 8.0f), "-0x1p-130"}, + + {float(ldexp(1.0, -127) + (ldexp(1.0, -127) / 2.0f)), "0x1.8p-127"}, + {float(ldexp(1.0, -127) / 2.0 + (ldexp(1.0, -127) / 4.0f)), + "0x1.8p-128"}, + + })),); + +INSTANTIATE_TEST_CASE_P( + Float32NanTests, HexFloatTest, + ::testing::ValuesIn(std::vector, std::string>>({ + // Various NAN and INF cases + {uint32_t(0xFF800000), "-0x1p+128"}, // -inf + {uint32_t(0x7F800000), "0x1p+128"}, // inf + {uint32_t(0xFFC00000), "-0x1.8p+128"}, // -nan + {uint32_t(0xFF800100), "-0x1.0002p+128"}, // -nan + {uint32_t(0xFF800c00), "-0x1.0018p+128"}, // -nan + {uint32_t(0xFF80F000), "-0x1.01ep+128"}, // -nan + {uint32_t(0xFFFFFFFF), "-0x1.fffffep+128"}, // -nan + {uint32_t(0x7FC00000), "0x1.8p+128"}, // +nan + {uint32_t(0x7F800100), "0x1.0002p+128"}, // +nan + {uint32_t(0x7f800c00), "0x1.0018p+128"}, // +nan + {uint32_t(0x7F80F000), "0x1.01ep+128"}, // +nan + {uint32_t(0x7FFFFFFF), "0x1.fffffep+128"}, // +nan + })),); + +INSTANTIATE_TEST_CASE_P( + Float64Tests, HexDoubleTest, + ::testing::ValuesIn( + std::vector, std::string>>({ + {0., "0x0p+0"}, + {1., "0x1p+0"}, + {2., "0x1p+1"}, + {3., "0x1.8p+1"}, + {0.5, "0x1p-1"}, + {0.25, "0x1p-2"}, + {0.75, "0x1.8p-1"}, + {-0., "-0x0p+0"}, + {-1., "-0x1p+0"}, + {-0.5, "-0x1p-1"}, + {-0.25, "-0x1p-2"}, + {-0.75, "-0x1.8p-1"}, + + // Larger numbers + {512., "0x1p+9"}, + {-512., "-0x1p+9"}, + {1024., "0x1p+10"}, + {-1024., "-0x1p+10"}, + {1024. + 8., "0x1.02p+10"}, + {-1024. - 8., "-0x1.02p+10"}, + + // Large outside the range of normal floats + {ldexp(1.0, 128), "0x1p+128"}, + {ldexp(1.0, 129), "0x1p+129"}, + {ldexp(-1.0, 128), "-0x1p+128"}, + {ldexp(-1.0, 129), "-0x1p+129"}, + {ldexp(1.0, 128) + ldexp(1.0, 90), "0x1.0000000004p+128"}, + {ldexp(1.0, 129) + ldexp(1.0, 120), "0x1.008p+129"}, + {ldexp(-1.0, 128) + ldexp(1.0, 90), "-0x1.fffffffff8p+127"}, + {ldexp(-1.0, 129) + ldexp(1.0, 120), "-0x1.ffp+128"}, + + // Small numbers + {1.0 / 512., "0x1p-9"}, + {1.0 / -512., "-0x1p-9"}, + {1.0 / 1024., "0x1p-10"}, + {1.0 / -1024., "-0x1p-10"}, + {1.0 / 1024. + 1.0 / 8., "0x1.02p-3"}, + {1.0 / -1024. - 1.0 / 8., "-0x1.02p-3"}, + + // Small outside the range of normal floats + {ldexp(1.0, -128), "0x1p-128"}, + {ldexp(1.0, -129), "0x1p-129"}, + {ldexp(-1.0, -128), "-0x1p-128"}, + {ldexp(-1.0, -129), "-0x1p-129"}, + {ldexp(1.0, -128) + ldexp(1.0, -90), "0x1.0000000004p-90"}, + {ldexp(1.0, -129) + ldexp(1.0, -120), "0x1.008p-120"}, + {ldexp(-1.0, -128) + ldexp(1.0, -90), "0x1.fffffffff8p-91"}, + {ldexp(-1.0, -129) + ldexp(1.0, -120), "0x1.ffp-121"}, + + // lowest non-denorm + {ldexp(1.0, -1022), "0x1p-1022"}, + {ldexp(-1.0, -1022), "-0x1p-1022"}, + + // Denormalized values + {ldexp(1.0, -1023), "0x1p-1023"}, + {ldexp(1.0, -1023) / 2.0, "0x1p-1024"}, + {ldexp(1.0, -1023) / 4.0, "0x1p-1025"}, + {ldexp(1.0, -1023) / 8.0, "0x1p-1026"}, + {ldexp(-1.0, -1024), "-0x1p-1024"}, + {ldexp(-1.0, -1024) / 2.0, "-0x1p-1025"}, + {ldexp(-1.0, -1024) / 4.0, "-0x1p-1026"}, + {ldexp(-1.0, -1024) / 8.0, "-0x1p-1027"}, + + {ldexp(1.0, -1023) + (ldexp(1.0, -1023) / 2.0), "0x1.8p-1023"}, + {ldexp(1.0, -1023) / 2.0 + (ldexp(1.0, -1023) / 4.0), + "0x1.8p-1024"}, + + })),); + +INSTANTIATE_TEST_CASE_P( + Float64NanTests, HexDoubleTest, + ::testing::ValuesIn(std::vector< + std::pair, std::string>>({ + // Various NAN and INF cases + {uint64_t(0xFFF0000000000000LL), "-0x1p+1024"}, //-inf + {uint64_t(0x7FF0000000000000LL), "0x1p+1024"}, //+inf + {uint64_t(0xFFF8000000000000LL), "-0x1.8p+1024"}, // -nan + {uint64_t(0xFFF0F00000000000LL), "-0x1.0fp+1024"}, // -nan + {uint64_t(0xFFF0000000000001LL), "-0x1.0000000000001p+1024"}, // -nan + {uint64_t(0xFFF0000300000000LL), "-0x1.00003p+1024"}, // -nan + {uint64_t(0xFFFFFFFFFFFFFFFFLL), "-0x1.fffffffffffffp+1024"}, // -nan + {uint64_t(0x7FF8000000000000LL), "0x1.8p+1024"}, // +nan + {uint64_t(0x7FF0F00000000000LL), "0x1.0fp+1024"}, // +nan + {uint64_t(0x7FF0000000000001LL), "0x1.0000000000001p+1024"}, // -nan + {uint64_t(0x7FF0000300000000LL), "0x1.00003p+1024"}, // -nan + {uint64_t(0x7FFFFFFFFFFFFFFFLL), "0x1.fffffffffffffp+1024"}, // -nan + })),); + +TEST(HexFloatStreamTest, OperatorLeftShiftPreservesFloatAndFill) { + std::stringstream s; + s << std::setw(4) << std::oct << std::setfill('x') << 8 << " " + << FloatProxy(uint32_t(0xFF800100)) << " " << std::setw(4) << 9; + EXPECT_THAT(s.str(), Eq(std::string("xx10 -0x1.0002p+128 xx11"))); +} + +TEST(HexDoubleStreamTest, OperatorLeftShiftPreservesFloatAndFill) { + std::stringstream s; + s << std::setw(4) << std::oct << std::setfill('x') << 8 << " " + << FloatProxy(uint64_t(0x7FF0F00000000000LL)) << " " << std::setw(4) + << 9; + EXPECT_THAT(s.str(), Eq(std::string("xx10 0x1.0fp+1024 xx11"))); +} + +TEST_P(DecodeHexFloatTest, DecodeCorrectly) { + EXPECT_THAT(Decode(GetParam().first), Eq(GetParam().second)); +} + +TEST_P(DecodeHexDoubleTest, DecodeCorrectly) { + EXPECT_THAT(Decode(GetParam().first), Eq(GetParam().second)); +} + +INSTANTIATE_TEST_CASE_P( + Float32DecodeTests, DecodeHexFloatTest, + ::testing::ValuesIn(std::vector>>({ + {"0x0p+000", 0.f}, + {"0x0p0", 0.f}, + {"0x0p-0", 0.f}, + + // flush to zero cases + {"0x1p-500", 0.f}, // Exponent underflows. + {"-0x1p-500", -0.f}, + {"0x0.00000000001p-126", 0.f}, // Fraction causes underflow. + {"-0x0.0000000001p-127", -0.f}, + {"-0x0.01p-142", -0.f}, // Fraction causes additional underflow. + {"0x0.01p-142", 0.f}, + + // Some floats that do not encode the same way as they decode. + {"0x2p+0", 2.f}, + {"0xFFp+0", 255.f}, + {"0x0.8p+0", 0.5f}, + {"0x0.4p+0", 0.25f}, + })),); + +INSTANTIATE_TEST_CASE_P( + Float32DecodeInfTests, DecodeHexFloatTest, + ::testing::ValuesIn(std::vector>>({ + // inf cases + {"-0x1p+128", uint32_t(0xFF800000)}, // -inf + {"0x32p+127", uint32_t(0x7F800000)}, // inf + {"0x32p+500", uint32_t(0x7F800000)}, // inf + {"-0x32p+127", uint32_t(0xFF800000)}, // -inf + })),); + +INSTANTIATE_TEST_CASE_P( + Float64DecodeTests, DecodeHexDoubleTest, + ::testing::ValuesIn( + std::vector>>({ + {"0x0p+000", 0.}, + {"0x0p0", 0.}, + {"0x0p-0", 0.}, + + // flush to zero cases + {"0x1p-5000", 0.}, // Exponent underflows. + {"-0x1p-5000", -0.}, + {"0x0.0000000000000001p-1023", 0.}, // Fraction causes underflow. + {"-0x0.000000000000001p-1024", -0.}, + {"-0x0.01p-1090", -0.f}, // Fraction causes additional underflow. + {"0x0.01p-1090", 0.}, + + // Some floats that do not encode the same way as they decode. + {"0x2p+0", 2.}, + {"0xFFp+0", 255.}, + {"0x0.8p+0", 0.5}, + {"0x0.4p+0", 0.25}, + })),); + +INSTANTIATE_TEST_CASE_P( + Float64DecodeInfTests, DecodeHexDoubleTest, + ::testing::ValuesIn( + std::vector>>({ + // inf cases + {"-0x1p+1024", uint64_t(0xFFF0000000000000)}, // -inf + {"0x32p+1023", uint64_t(0x7FF0000000000000)}, // inf + {"0x32p+5000", uint64_t(0x7FF0000000000000)}, // inf + {"-0x32p+1023", uint64_t(0xFFF0000000000000)}, // -inf + })),); + +TEST(FloatProxy, ValidConversion) { + EXPECT_THAT(FloatProxy(1.f).getAsFloat(), Eq(1.0f)); + EXPECT_THAT(FloatProxy(32.f).getAsFloat(), Eq(32.0f)); + EXPECT_THAT(FloatProxy(-1.f).getAsFloat(), Eq(-1.0f)); + EXPECT_THAT(FloatProxy(0.f).getAsFloat(), Eq(0.0f)); + EXPECT_THAT(FloatProxy(-0.f).getAsFloat(), Eq(-0.0f)); + EXPECT_THAT(FloatProxy(1.2e32f).getAsFloat(), Eq(1.2e32f)); + + EXPECT_TRUE(std::isinf(FloatProxy(uint32_t(0xFF800000)).getAsFloat())); + EXPECT_TRUE(std::isinf(FloatProxy(uint32_t(0x7F800000)).getAsFloat())); + EXPECT_TRUE(std::isnan(FloatProxy(uint32_t(0xFFC00000)).getAsFloat())); + EXPECT_TRUE(std::isnan(FloatProxy(uint32_t(0xFF800100)).getAsFloat())); + EXPECT_TRUE(std::isnan(FloatProxy(uint32_t(0xFF800c00)).getAsFloat())); + EXPECT_TRUE(std::isnan(FloatProxy(uint32_t(0xFF80F000)).getAsFloat())); + EXPECT_TRUE(std::isnan(FloatProxy(uint32_t(0xFFFFFFFF)).getAsFloat())); + EXPECT_TRUE(std::isnan(FloatProxy(uint32_t(0x7FC00000)).getAsFloat())); + EXPECT_TRUE(std::isnan(FloatProxy(uint32_t(0x7F800100)).getAsFloat())); + EXPECT_TRUE(std::isnan(FloatProxy(uint32_t(0x7f800c00)).getAsFloat())); + EXPECT_TRUE(std::isnan(FloatProxy(uint32_t(0x7F80F000)).getAsFloat())); + EXPECT_TRUE(std::isnan(FloatProxy(uint32_t(0x7FFFFFFF)).getAsFloat())); + + EXPECT_THAT(FloatProxy(uint32_t(0xFF800000)).data(), Eq(0xFF800000u)); + EXPECT_THAT(FloatProxy(uint32_t(0x7F800000)).data(), Eq(0x7F800000u)); + EXPECT_THAT(FloatProxy(uint32_t(0xFFC00000)).data(), Eq(0xFFC00000u)); + EXPECT_THAT(FloatProxy(uint32_t(0xFF800100)).data(), Eq(0xFF800100u)); + EXPECT_THAT(FloatProxy(uint32_t(0xFF800c00)).data(), Eq(0xFF800c00u)); + EXPECT_THAT(FloatProxy(uint32_t(0xFF80F000)).data(), Eq(0xFF80F000u)); + EXPECT_THAT(FloatProxy(uint32_t(0xFFFFFFFF)).data(), Eq(0xFFFFFFFFu)); + EXPECT_THAT(FloatProxy(uint32_t(0x7FC00000)).data(), Eq(0x7FC00000u)); + EXPECT_THAT(FloatProxy(uint32_t(0x7F800100)).data(), Eq(0x7F800100u)); + EXPECT_THAT(FloatProxy(uint32_t(0x7f800c00)).data(), Eq(0x7f800c00u)); + EXPECT_THAT(FloatProxy(uint32_t(0x7F80F000)).data(), Eq(0x7F80F000u)); + EXPECT_THAT(FloatProxy(uint32_t(0x7FFFFFFF)).data(), Eq(0x7FFFFFFFu)); +} + +TEST(FloatProxy, Nan) { + EXPECT_TRUE(FloatProxy(uint32_t(0xFFC00000)).isNan()); + EXPECT_TRUE(FloatProxy(uint32_t(0xFF800100)).isNan()); + EXPECT_TRUE(FloatProxy(uint32_t(0xFF800c00)).isNan()); + EXPECT_TRUE(FloatProxy(uint32_t(0xFF80F000)).isNan()); + EXPECT_TRUE(FloatProxy(uint32_t(0xFFFFFFFF)).isNan()); + EXPECT_TRUE(FloatProxy(uint32_t(0x7FC00000)).isNan()); + EXPECT_TRUE(FloatProxy(uint32_t(0x7F800100)).isNan()); + EXPECT_TRUE(FloatProxy(uint32_t(0x7f800c00)).isNan()); + EXPECT_TRUE(FloatProxy(uint32_t(0x7F80F000)).isNan()); + EXPECT_TRUE(FloatProxy(uint32_t(0x7FFFFFFF)).isNan()); +} + +TEST(FloatProxy, Negation) { + EXPECT_THAT((-FloatProxy(1.f)).getAsFloat(), Eq(-1.0f)); + EXPECT_THAT((-FloatProxy(0.f)).getAsFloat(), Eq(-0.0f)); + + EXPECT_THAT((-FloatProxy(-1.f)).getAsFloat(), Eq(1.0f)); + EXPECT_THAT((-FloatProxy(-0.f)).getAsFloat(), Eq(0.0f)); + + EXPECT_THAT((-FloatProxy(32.f)).getAsFloat(), Eq(-32.0f)); + EXPECT_THAT((-FloatProxy(-32.f)).getAsFloat(), Eq(32.0f)); + + EXPECT_THAT((-FloatProxy(1.2e32f)).getAsFloat(), Eq(-1.2e32f)); + EXPECT_THAT((-FloatProxy(-1.2e32f)).getAsFloat(), Eq(1.2e32f)); + + EXPECT_THAT( + (-FloatProxy(std::numeric_limits::infinity())).getAsFloat(), + Eq(-std::numeric_limits::infinity())); + EXPECT_THAT((-FloatProxy(-std::numeric_limits::infinity())) + .getAsFloat(), + Eq(std::numeric_limits::infinity())); +} + +// Test conversion of FloatProxy values to strings. +// +// In previous cases, we always wrapped the FloatProxy value in a HexFloat +// before conversion to a string. In the following cases, the FloatProxy +// decides for itself whether to print as a regular number or as a hex float. + +using FloatProxyFloatTest = + ::testing::TestWithParam, std::string>>; +using FloatProxyDoubleTest = + ::testing::TestWithParam, std::string>>; + +// Converts a float value to a string via a FloatProxy. +template +std::string EncodeViaFloatProxy(const T& value) { + std::stringstream ss; + ss << value; + return ss.str(); +} + +// Converts a floating point string so that the exponent prefix +// is 'e', and the exponent value does not have leading zeros. +// The Microsoft runtime library likes to write things like "2.5E+010". +// Convert that to "2.5e+10". +// We don't care what happens to strings that are not floating point +// strings. +std::string NormalizeExponentInFloatString(std::string in) { + std::string result; + // Reserve one spot for the terminating null, even when the sscanf fails. + std::vector prefix(in.size() + 1); + char e; + char plus_or_minus; + int exponent; // in base 10 + if ((4 == std::sscanf(in.c_str(), "%[-+.0123456789]%c%c%d", prefix.data(), &e, + &plus_or_minus, &exponent)) && + (e == 'e' || e == 'E') && + (plus_or_minus == '-' || plus_or_minus == '+')) { + // It looks like a floating point value with exponent. + std::stringstream out; + out << prefix.data() << 'e' << plus_or_minus << exponent; + result = out.str(); + } else { + result = in; + } + return result; +} + +TEST(NormalizeFloat, Sample) { + EXPECT_THAT(NormalizeExponentInFloatString(""), Eq("")); + EXPECT_THAT(NormalizeExponentInFloatString("1e-12"), Eq("1e-12")); + EXPECT_THAT(NormalizeExponentInFloatString("1E+14"), Eq("1e+14")); + EXPECT_THAT(NormalizeExponentInFloatString("1e-0012"), Eq("1e-12")); + EXPECT_THAT(NormalizeExponentInFloatString("1.263E+014"), Eq("1.263e+14")); +} + +// The following two tests can't be DRY because they take different parameter +// types. +TEST_P(FloatProxyFloatTest, EncodeCorrectly) { + EXPECT_THAT( + NormalizeExponentInFloatString(EncodeViaFloatProxy(GetParam().first)), + Eq(GetParam().second)); +} + +TEST_P(FloatProxyDoubleTest, EncodeCorrectly) { + EXPECT_THAT( + NormalizeExponentInFloatString(EncodeViaFloatProxy(GetParam().first)), + Eq(GetParam().second)); +} + +INSTANTIATE_TEST_CASE_P( + Float32Tests, FloatProxyFloatTest, + ::testing::ValuesIn(std::vector, std::string>>({ + // Zero + {0.f, "0"}, + // Normal numbers + {1.f, "1"}, + {-0.25f, "-0.25"}, + {1000.0f, "1000"}, + + // Still normal numbers, but with large magnitude exponents. + {float(ldexp(1.f, 126)), "8.50706e+37"}, + {float(ldexp(-1.f, -126)), "-1.17549e-38"}, + + // denormalized values are printed as hex floats. + {float(ldexp(1.0f, -127)), "0x1p-127"}, + {float(ldexp(1.5f, -128)), "0x1.8p-128"}, + {float(ldexp(1.25, -129)), "0x1.4p-129"}, + {float(ldexp(1.125, -130)), "0x1.2p-130"}, + {float(ldexp(-1.0f, -127)), "-0x1p-127"}, + {float(ldexp(-1.0f, -128)), "-0x1p-128"}, + {float(ldexp(-1.0f, -129)), "-0x1p-129"}, + {float(ldexp(-1.5f, -130)), "-0x1.8p-130"}, + + // NaNs + {FloatProxy(uint32_t(0xFFC00000)), "-0x1.8p+128"}, + {FloatProxy(uint32_t(0xFF800100)), "-0x1.0002p+128"}, + + {std::numeric_limits::infinity(), "0x1p+128"}, + {-std::numeric_limits::infinity(), "-0x1p+128"}, + })),); + +INSTANTIATE_TEST_CASE_P( + Float64Tests, FloatProxyDoubleTest, + ::testing::ValuesIn( + std::vector, std::string>>({ + {0., "0"}, + {1., "1"}, + {-0.25, "-0.25"}, + {1000.0, "1000"}, + + // Large outside the range of normal floats + {ldexp(1.0, 128), "3.40282366920938e+38"}, + {ldexp(1.5, 129), "1.02084710076282e+39"}, + {ldexp(-1.0, 128), "-3.40282366920938e+38"}, + {ldexp(-1.5, 129), "-1.02084710076282e+39"}, + + // Small outside the range of normal floats + {ldexp(1.5, -129), "2.20405190779179e-39"}, + {ldexp(-1.5, -129), "-2.20405190779179e-39"}, + + // lowest non-denorm + {ldexp(1.0, -1022), "2.2250738585072e-308"}, + {ldexp(-1.0, -1022), "-2.2250738585072e-308"}, + + // Denormalized values + {ldexp(1.125, -1023), "0x1.2p-1023"}, + {ldexp(-1.375, -1024), "-0x1.6p-1024"}, + + // NaNs + {uint64_t(0x7FF8000000000000LL), "0x1.8p+1024"}, + {uint64_t(0xFFF0F00000000000LL), "-0x1.0fp+1024"}, + + // Infinity + {std::numeric_limits::infinity(), "0x1p+1024"}, + {-std::numeric_limits::infinity(), "-0x1p+1024"}, + + })),); + +// double is used so that unbiased_exponent can be used with the output +// of ldexp directly. +int32_t unbiased_exponent(double f) { + return spvutils::HexFloat>( + static_cast(f)).getUnbiasedNormalizedExponent(); +} + +int16_t unbiased_half_exponent(uint16_t f) { + return spvutils::HexFloat>(f) + .getUnbiasedNormalizedExponent(); +} + +TEST(HexFloatOperationTest, UnbiasedExponent) { + // Float cases + EXPECT_EQ(0, unbiased_exponent(ldexp(1.0f, 0))); + EXPECT_EQ(-32, unbiased_exponent(ldexp(1.0f, -32))); + EXPECT_EQ(42, unbiased_exponent(ldexp(1.0f, 42))); + EXPECT_EQ(125, unbiased_exponent(ldexp(1.0f, 125))); + // Saturates to 128 + EXPECT_EQ(128, unbiased_exponent(ldexp(1.0f, 256))); + + EXPECT_EQ(-100, unbiased_exponent(ldexp(1.0f, -100))); + EXPECT_EQ(-127, unbiased_exponent(ldexp(1.0f, -127))); // First denorm + EXPECT_EQ(-128, unbiased_exponent(ldexp(1.0f, -128))); + EXPECT_EQ(-129, unbiased_exponent(ldexp(1.0f, -129))); + EXPECT_EQ(-140, unbiased_exponent(ldexp(1.0f, -140))); + // Smallest representable number + EXPECT_EQ(-126 - 23, unbiased_exponent(ldexp(1.0f, -126 - 23))); + // Should get rounded to 0 first. + EXPECT_EQ(0, unbiased_exponent(ldexp(1.0f, -127 - 23))); + + // Float16 cases + // The exponent is represented in the bits 0x7C00 + // The offset is -15 + EXPECT_EQ(0, unbiased_half_exponent(0x3C00)); + EXPECT_EQ(3, unbiased_half_exponent(0x4800)); + EXPECT_EQ(-1, unbiased_half_exponent(0x3800)); + EXPECT_EQ(-14, unbiased_half_exponent(0x0400)); + EXPECT_EQ(16, unbiased_half_exponent(0x7C00)); + EXPECT_EQ(10, unbiased_half_exponent(0x6400)); + + // Smallest representable number + EXPECT_EQ(-24, unbiased_half_exponent(0x0001)); +} + +// Creates a float that is the sum of 1/(2 ^ fractions[i]) for i in factions +float float_fractions(const std::vector& fractions) { + float f = 0; + for(int32_t i: fractions) { + f += std::ldexp(1.0f, -i); + } + return f; +} + +// Returns the normalized significand of a HexFloat> +// that was created by calling float_fractions with the input fractions, +// raised to the power of exp. +uint32_t normalized_significand(const std::vector& fractions, uint32_t exp) { + return spvutils::HexFloat>( + static_cast(ldexp(float_fractions(fractions), exp))) + .getNormalizedSignificand(); +} + +// Sets the bits from MSB to LSB of the significand part of a float. +// For example 0 would set the bit 23 (counting from LSB to MSB), +// and 1 would set the 22nd bit. +uint32_t bits_set(const std::vector& bits) { + const uint32_t top_bit = 1u << 22u; + uint32_t val= 0; + for(uint32_t i: bits) { + val |= top_bit >> i; + } + return val; +} + +// The same as bits_set but for a Float16 value instead of 32-bit floating +// point. +uint16_t half_bits_set(const std::vector& bits) { + const uint32_t top_bit = 1u << 9u; + uint32_t val= 0; + for(uint32_t i: bits) { + val |= top_bit >> i; + } + return static_cast(val); +} + +TEST(HexFloatOperationTest, NormalizedSignificand) { + // For normalized numbers (the following) it should be a simple matter + // of getting rid of the top implicit bit + EXPECT_EQ(bits_set({}), normalized_significand({0}, 0)); + EXPECT_EQ(bits_set({0}), normalized_significand({0, 1}, 0)); + EXPECT_EQ(bits_set({0, 1}), normalized_significand({0, 1, 2}, 0)); + EXPECT_EQ(bits_set({1}), normalized_significand({0, 2}, 0)); + EXPECT_EQ(bits_set({1}), normalized_significand({0, 2}, 32)); + EXPECT_EQ(bits_set({1}), normalized_significand({0, 2}, 126)); + + // For denormalized numbers we expect the normalized significand to + // shift as if it were normalized. This means, in practice that the + // top_most set bit will be cut off. Looks very similar to above (on purpose) + EXPECT_EQ(bits_set({}), normalized_significand({0}, -127)); + EXPECT_EQ(bits_set({3}), normalized_significand({0, 4}, -128)); + EXPECT_EQ(bits_set({3}), normalized_significand({0, 4}, -127)); + EXPECT_EQ(bits_set({}), normalized_significand({22}, -127)); + EXPECT_EQ(bits_set({0}), normalized_significand({21, 22}, -127)); +} + +// Returns the 32-bit floating point value created by +// calling setFromSignUnbiasedExponentAndNormalizedSignificand +// on a HexFloat> +float set_from_sign(bool negative, int32_t unbiased_exponent, + uint32_t significand, bool round_denorm_up) { + spvutils::HexFloat> f(0.f); + f.setFromSignUnbiasedExponentAndNormalizedSignificand( + negative, unbiased_exponent, significand, round_denorm_up); + return f.value().getAsFloat(); +} + +TEST(HexFloatOperationTests, + SetFromSignUnbiasedExponentAndNormalizedSignificand) { + + EXPECT_EQ(1.f, set_from_sign(false, 0, 0, false)); + + // Tests insertion of various denormalized numbers with and without round up. + EXPECT_EQ(static_cast(ldexp(1.f, -149)), set_from_sign(false, -149, 0, false)); + EXPECT_EQ(static_cast(ldexp(1.f, -149)), set_from_sign(false, -149, 0, true)); + EXPECT_EQ(0.f, set_from_sign(false, -150, 1, false)); + EXPECT_EQ(static_cast(ldexp(1.f, -149)), set_from_sign(false, -150, 1, true)); + + EXPECT_EQ(ldexp(1.0f, -127), set_from_sign(false, -127, 0, false)); + EXPECT_EQ(ldexp(1.0f, -128), set_from_sign(false, -128, 0, false)); + EXPECT_EQ(float_fractions({0, 1, 2, 5}), + set_from_sign(false, 0, bits_set({0, 1, 4}), false)); + EXPECT_EQ(ldexp(float_fractions({0, 1, 2, 5}), -32), + set_from_sign(false, -32, bits_set({0, 1, 4}), false)); + EXPECT_EQ(ldexp(float_fractions({0, 1, 2, 5}), -128), + set_from_sign(false, -128, bits_set({0, 1, 4}), false)); + + // The negative cases from above. + EXPECT_EQ(-1.f, set_from_sign(true, 0, 0, false)); + EXPECT_EQ(-ldexp(1.0, -127), set_from_sign(true, -127, 0, false)); + EXPECT_EQ(-ldexp(1.0, -128), set_from_sign(true, -128, 0, false)); + EXPECT_EQ(-float_fractions({0, 1, 2, 5}), + set_from_sign(true, 0, bits_set({0, 1, 4}), false)); + EXPECT_EQ(-ldexp(float_fractions({0, 1, 2, 5}), -32), + set_from_sign(true, -32, bits_set({0, 1, 4}), false)); + EXPECT_EQ(-ldexp(float_fractions({0, 1, 2, 5}), -128), + set_from_sign(true, -128, bits_set({0, 1, 4}), false)); +} + +TEST(HexFloatOperationTests, NonRounding) { + // Rounding from 32-bit hex-float to 32-bit hex-float should be trivial, + // except in the denorm case which is a bit more complex. + using HF = spvutils::HexFloat>; + bool carry_bit = false; + + spvutils::round_direction rounding[] = { + spvutils::kRoundToZero, + spvutils::kRoundToNearestEven, + spvutils::kRoundToPositiveInfinity, + spvutils::kRoundToNegativeInfinity}; + + // Everything fits, so this should be straight-forward + for (spvutils::round_direction round : rounding) { + EXPECT_EQ(bits_set({}), HF(0.f).getRoundedNormalizedSignificand( + round, &carry_bit)); + EXPECT_FALSE(carry_bit); + + EXPECT_EQ(bits_set({0}), + HF(float_fractions({0, 1})) + .getRoundedNormalizedSignificand(round, &carry_bit)); + EXPECT_FALSE(carry_bit); + + EXPECT_EQ(bits_set({1, 3}), + HF(float_fractions({0, 2, 4})) + .getRoundedNormalizedSignificand(round, &carry_bit)); + EXPECT_FALSE(carry_bit); + + EXPECT_EQ( + bits_set({0, 1, 4}), + HF(static_cast(-ldexp(float_fractions({0, 1, 2, 5}), -128))) + .getRoundedNormalizedSignificand(round, &carry_bit)); + EXPECT_FALSE(carry_bit); + + EXPECT_EQ( + bits_set({0, 1, 4, 22}), + HF(static_cast(float_fractions({0, 1, 2, 5, 23}))) + .getRoundedNormalizedSignificand(round, &carry_bit)); + EXPECT_FALSE(carry_bit); + } +} + +struct RoundSignificandCase { + float source_float; + std::pair expected_results; + spvutils::round_direction round; +}; + +using HexFloatRoundTest = + ::testing::TestWithParam; + +TEST_P(HexFloatRoundTest, RoundDownToFP16) { + using HF = spvutils::HexFloat>; + using HF16 = spvutils::HexFloat>; + + HF input_value(GetParam().source_float); + bool carry_bit = false; + EXPECT_EQ(GetParam().expected_results.first, + input_value.getRoundedNormalizedSignificand( + GetParam().round, &carry_bit)); + EXPECT_EQ(carry_bit, GetParam().expected_results.second); +} + +// clang-format off +INSTANTIATE_TEST_CASE_P(F32ToF16, HexFloatRoundTest, + ::testing::ValuesIn(std::vector( + { + {float_fractions({0}), std::make_pair(half_bits_set({}), false), spvutils::kRoundToZero}, + {float_fractions({0}), std::make_pair(half_bits_set({}), false), spvutils::kRoundToNearestEven}, + {float_fractions({0}), std::make_pair(half_bits_set({}), false), spvutils::kRoundToPositiveInfinity}, + {float_fractions({0}), std::make_pair(half_bits_set({}), false), spvutils::kRoundToNegativeInfinity}, + {float_fractions({0, 1}), std::make_pair(half_bits_set({0}), false), spvutils::kRoundToZero}, + + {float_fractions({0, 1, 11}), std::make_pair(half_bits_set({0}), false), spvutils::kRoundToZero}, + {float_fractions({0, 1, 11}), std::make_pair(half_bits_set({0, 9}), false), spvutils::kRoundToPositiveInfinity}, + {float_fractions({0, 1, 11}), std::make_pair(half_bits_set({0}), false), spvutils::kRoundToNegativeInfinity}, + {float_fractions({0, 1, 11}), std::make_pair(half_bits_set({0}), false), spvutils::kRoundToNearestEven}, + + {float_fractions({0, 1, 10, 11}), std::make_pair(half_bits_set({0, 9}), false), spvutils::kRoundToZero}, + {float_fractions({0, 1, 10, 11}), std::make_pair(half_bits_set({0, 8}), false), spvutils::kRoundToPositiveInfinity}, + {float_fractions({0, 1, 10, 11}), std::make_pair(half_bits_set({0, 9}), false), spvutils::kRoundToNegativeInfinity}, + {float_fractions({0, 1, 10, 11}), std::make_pair(half_bits_set({0, 8}), false), spvutils::kRoundToNearestEven}, + + {float_fractions({0, 1, 11, 12}), std::make_pair(half_bits_set({0}), false), spvutils::kRoundToZero}, + {float_fractions({0, 1, 11, 12}), std::make_pair(half_bits_set({0, 9}), false), spvutils::kRoundToPositiveInfinity}, + {float_fractions({0, 1, 11, 12}), std::make_pair(half_bits_set({0}), false), spvutils::kRoundToNegativeInfinity}, + {float_fractions({0, 1, 11, 12}), std::make_pair(half_bits_set({0, 9}), false), spvutils::kRoundToNearestEven}, + + {-float_fractions({0, 1, 11, 12}), std::make_pair(half_bits_set({0}), false), spvutils::kRoundToZero}, + {-float_fractions({0, 1, 11, 12}), std::make_pair(half_bits_set({0}), false), spvutils::kRoundToPositiveInfinity}, + {-float_fractions({0, 1, 11, 12}), std::make_pair(half_bits_set({0, 9}), false), spvutils::kRoundToNegativeInfinity}, + {-float_fractions({0, 1, 11, 12}), std::make_pair(half_bits_set({0, 9}), false), spvutils::kRoundToNearestEven}, + + {float_fractions({0, 1, 11, 22}), std::make_pair(half_bits_set({0}), false), spvutils::kRoundToZero}, + {float_fractions({0, 1, 11, 22}), std::make_pair(half_bits_set({0, 9}), false), spvutils::kRoundToPositiveInfinity}, + {float_fractions({0, 1, 11, 22}), std::make_pair(half_bits_set({0}), false), spvutils::kRoundToNegativeInfinity}, + {float_fractions({0, 1, 11, 22}), std::make_pair(half_bits_set({0, 9}), false), spvutils::kRoundToNearestEven}, + + // Carries + {float_fractions({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}), std::make_pair(half_bits_set({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), false), spvutils::kRoundToZero}, + {float_fractions({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}), std::make_pair(half_bits_set({}), true), spvutils::kRoundToPositiveInfinity}, + {float_fractions({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}), std::make_pair(half_bits_set({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), false), spvutils::kRoundToNegativeInfinity}, + {float_fractions({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}), std::make_pair(half_bits_set({}), true), spvutils::kRoundToNearestEven}, + + // Cases where original number was denorm. Note: this should have no effect + // the number is pre-normalized. + {static_cast(ldexp(float_fractions({0, 1, 11, 13}), -128)), std::make_pair(half_bits_set({0}), false), spvutils::kRoundToZero}, + {static_cast(ldexp(float_fractions({0, 1, 11, 13}), -129)), std::make_pair(half_bits_set({0, 9}), false), spvutils::kRoundToPositiveInfinity}, + {static_cast(ldexp(float_fractions({0, 1, 11, 13}), -131)), std::make_pair(half_bits_set({0}), false), spvutils::kRoundToNegativeInfinity}, + {static_cast(ldexp(float_fractions({0, 1, 11, 13}), -130)), std::make_pair(half_bits_set({0, 9}), false), spvutils::kRoundToNearestEven}, + })),); +// clang-format on + +struct UpCastSignificandCase { + uint16_t source_half; + uint32_t expected_result; +}; + +using HexFloatRoundUpSignificandTest = + ::testing::TestWithParam; +TEST_P(HexFloatRoundUpSignificandTest, Widening) { + using HF = spvutils::HexFloat>; + using HF16 = spvutils::HexFloat>; + bool carry_bit = false; + + spvutils::round_direction rounding[] = { + spvutils::kRoundToZero, + spvutils::kRoundToNearestEven, + spvutils::kRoundToPositiveInfinity, + spvutils::kRoundToNegativeInfinity}; + + // Everything fits, so everything should just be bit-shifts. + for (spvutils::round_direction round : rounding) { + carry_bit = false; + HF16 input_value(GetParam().source_half); + EXPECT_EQ( + GetParam().expected_result, + input_value.getRoundedNormalizedSignificand(round, &carry_bit)) + << std::hex << "0x" + << input_value.getRoundedNormalizedSignificand(round, &carry_bit) + << " 0x" << GetParam().expected_result; + EXPECT_FALSE(carry_bit); + } +} + +INSTANTIATE_TEST_CASE_P(F16toF32, HexFloatRoundUpSignificandTest, + // 0xFC00 of the source 16-bit hex value cover the sign and the exponent. + // They are ignored for this test. + ::testing::ValuesIn(std::vector( + { + {0x3F00, 0x600000}, + {0x0F00, 0x600000}, + {0x0F01, 0x602000}, + {0x0FFF, 0x7FE000}, + })),); + +struct DownCastTest { + float source_float; + uint16_t expected_half; + std::vector directions; +}; + +std::string get_round_text(spvutils::round_direction direction) { +#define CASE(round_direction) \ + case round_direction: \ + return #round_direction + + switch (direction) { + CASE(spvutils::kRoundToZero); + CASE(spvutils::kRoundToPositiveInfinity); + CASE(spvutils::kRoundToNegativeInfinity); + CASE(spvutils::kRoundToNearestEven); + } +#undef CASE + return ""; +} + +using HexFloatFP32To16Tests = ::testing::TestWithParam; + +TEST_P(HexFloatFP32To16Tests, NarrowingCasts) { + using HF = spvutils::HexFloat>; + using HF16 = spvutils::HexFloat>; + HF f(GetParam().source_float); + for (auto round : GetParam().directions) { + HF16 half(0); + f.castTo(half, round); + EXPECT_EQ(GetParam().expected_half, half.value().getAsFloat().get_value()) + << get_round_text(round) << " " << std::hex + << spvutils::BitwiseCast(GetParam().source_float) + << " cast to: " << half.value().getAsFloat().get_value(); + } +} + +const uint16_t positive_infinity = 0x7C00; +const uint16_t negative_infinity = 0xFC00; + +INSTANTIATE_TEST_CASE_P(F32ToF16, HexFloatFP32To16Tests, + ::testing::ValuesIn(std::vector( + { + // Exactly representable as half. + {0.f, 0x0, {spvutils::kRoundToZero, spvutils::kRoundToPositiveInfinity, spvutils::kRoundToNegativeInfinity, spvutils::kRoundToNearestEven}}, + {-0.f, 0x8000, {spvutils::kRoundToZero, spvutils::kRoundToPositiveInfinity, spvutils::kRoundToNegativeInfinity, spvutils::kRoundToNearestEven}}, + {1.0f, 0x3C00, {spvutils::kRoundToZero, spvutils::kRoundToPositiveInfinity, spvutils::kRoundToNegativeInfinity, spvutils::kRoundToNearestEven}}, + {-1.0f, 0xBC00, {spvutils::kRoundToZero, spvutils::kRoundToPositiveInfinity, spvutils::kRoundToNegativeInfinity, spvutils::kRoundToNearestEven}}, + + {float_fractions({0, 1, 10}) , 0x3E01, {spvutils::kRoundToZero, spvutils::kRoundToPositiveInfinity, spvutils::kRoundToNegativeInfinity, spvutils::kRoundToNearestEven}}, + {-float_fractions({0, 1, 10}) , 0xBE01, {spvutils::kRoundToZero, spvutils::kRoundToPositiveInfinity, spvutils::kRoundToNegativeInfinity, spvutils::kRoundToNearestEven}}, + {static_cast(ldexp(float_fractions({0, 1, 10}), 3)), 0x4A01, {spvutils::kRoundToZero, spvutils::kRoundToPositiveInfinity, spvutils::kRoundToNegativeInfinity, spvutils::kRoundToNearestEven}}, + {static_cast(-ldexp(float_fractions({0, 1, 10}), 3)), 0xCA01, {spvutils::kRoundToZero, spvutils::kRoundToPositiveInfinity, spvutils::kRoundToNegativeInfinity, spvutils::kRoundToNearestEven}}, + + + // Underflow + {static_cast(ldexp(1.0f, -25)), 0x0, {spvutils::kRoundToZero, spvutils::kRoundToNegativeInfinity, spvutils::kRoundToNearestEven}}, + {static_cast(ldexp(1.0f, -25)), 0x1, {spvutils::kRoundToPositiveInfinity}}, + {static_cast(-ldexp(1.0f, -25)), 0x8000, {spvutils::kRoundToZero, spvutils::kRoundToPositiveInfinity, spvutils::kRoundToNearestEven}}, + {static_cast(-ldexp(1.0f, -25)), 0x8001, {spvutils::kRoundToNegativeInfinity}}, + {static_cast(ldexp(1.0f, -24)), 0x1, {spvutils::kRoundToZero, spvutils::kRoundToPositiveInfinity, spvutils::kRoundToNegativeInfinity, spvutils::kRoundToNearestEven}}, + + // Overflow + {static_cast(ldexp(1.0f, 16)), positive_infinity, {spvutils::kRoundToZero, spvutils::kRoundToPositiveInfinity, spvutils::kRoundToNegativeInfinity, spvutils::kRoundToNearestEven}}, + {static_cast(ldexp(1.0f, 18)), positive_infinity, {spvutils::kRoundToZero, spvutils::kRoundToPositiveInfinity, spvutils::kRoundToNegativeInfinity, spvutils::kRoundToNearestEven}}, + {static_cast(ldexp(1.3f, 16)), positive_infinity, {spvutils::kRoundToZero, spvutils::kRoundToPositiveInfinity, spvutils::kRoundToNegativeInfinity, spvutils::kRoundToNearestEven}}, + {static_cast(-ldexp(1.0f, 16)), negative_infinity, {spvutils::kRoundToZero, spvutils::kRoundToPositiveInfinity, spvutils::kRoundToNegativeInfinity, spvutils::kRoundToNearestEven}}, + {static_cast(-ldexp(1.0f, 18)), negative_infinity, {spvutils::kRoundToZero, spvutils::kRoundToPositiveInfinity, spvutils::kRoundToNegativeInfinity, spvutils::kRoundToNearestEven}}, + {static_cast(-ldexp(1.3f, 16)), negative_infinity, {spvutils::kRoundToZero, spvutils::kRoundToPositiveInfinity, spvutils::kRoundToNegativeInfinity, spvutils::kRoundToNearestEven}}, + + // Transfer of Infinities + {std::numeric_limits::infinity(), positive_infinity, {spvutils::kRoundToZero, spvutils::kRoundToPositiveInfinity, spvutils::kRoundToNegativeInfinity, spvutils::kRoundToNearestEven}}, + {-std::numeric_limits::infinity(), negative_infinity, {spvutils::kRoundToZero, spvutils::kRoundToPositiveInfinity, spvutils::kRoundToNegativeInfinity, spvutils::kRoundToNearestEven}}, + + // Nans are below because we cannot test for equality. + })),); + +struct UpCastCase{ + uint16_t source_half; + float expected_float; +}; + +using HexFloatFP16To32Tests = ::testing::TestWithParam; +TEST_P(HexFloatFP16To32Tests, WideningCasts) { + using HF = spvutils::HexFloat>; + using HF16 = spvutils::HexFloat>; + HF16 f(GetParam().source_half); + + spvutils::round_direction rounding[] = { + spvutils::kRoundToZero, + spvutils::kRoundToNearestEven, + spvutils::kRoundToPositiveInfinity, + spvutils::kRoundToNegativeInfinity}; + + // Everything fits, so everything should just be bit-shifts. + for (spvutils::round_direction round : rounding) { + HF flt(0.f); + f.castTo(flt, round); + EXPECT_EQ(GetParam().expected_float, flt.value().getAsFloat()) + << get_round_text(round) << " " << std::hex + << spvutils::BitwiseCast(GetParam().source_half) + << " cast to: " << flt.value().getAsFloat(); + } +} + +INSTANTIATE_TEST_CASE_P(F16ToF32, HexFloatFP16To32Tests, + ::testing::ValuesIn(std::vector( + { + {0x0000, 0.f}, + {0x8000, -0.f}, + {0x3C00, 1.0f}, + {0xBC00, -1.0f}, + {0x3F00, float_fractions({0, 1, 2})}, + {0xBF00, -float_fractions({0, 1, 2})}, + {0x3F01, float_fractions({0, 1, 2, 10})}, + {0xBF01, -float_fractions({0, 1, 2, 10})}, + + // denorm + {0x0001, static_cast(ldexp(1.0, -24))}, + {0x0002, static_cast(ldexp(1.0, -23))}, + {0x8001, static_cast(-ldexp(1.0, -24))}, + {0x8011, static_cast(-ldexp(1.0, -20) + -ldexp(1.0, -24))}, + + // inf + {0x7C00, std::numeric_limits::infinity()}, + {0xFC00, -std::numeric_limits::infinity()}, + })),); + +TEST(HexFloatOperationTests, NanTests) { + using HF = spvutils::HexFloat>; + using HF16 = spvutils::HexFloat>; + spvutils::round_direction rounding[] = { + spvutils::kRoundToZero, + spvutils::kRoundToNearestEven, + spvutils::kRoundToPositiveInfinity, + spvutils::kRoundToNegativeInfinity}; + + // Everything fits, so everything should just be bit-shifts. + for (spvutils::round_direction round : rounding) { + HF16 f16(0); + HF f(0.f); + HF(std::numeric_limits::quiet_NaN()).castTo(f16, round); + EXPECT_TRUE(f16.value().isNan()); + HF(std::numeric_limits::signaling_NaN()).castTo(f16, round); + EXPECT_TRUE(f16.value().isNan()); + + HF16(0x7C01).castTo(f, round); + EXPECT_TRUE(f.value().isNan()); + HF16(0x7C11).castTo(f, round); + EXPECT_TRUE(f.value().isNan()); + HF16(0xFC01).castTo(f, round); + EXPECT_TRUE(f.value().isNan()); + HF16(0x7C10).castTo(f, round); + EXPECT_TRUE(f.value().isNan()); + HF16(0xFF00).castTo(f, round); + EXPECT_TRUE(f.value().isNan()); + } +} + +// A test case for parsing good and bad HexFloat> literals. +template +struct FloatParseCase { + std::string literal; + bool negate_value; + bool expect_success; + HexFloat> expected_value; +}; + +using ParseNormalFloatTest = ::testing::TestWithParam>; + +TEST_P(ParseNormalFloatTest, Samples) { + std::stringstream input(GetParam().literal); + HexFloat> parsed_value(0.0f); + ParseNormalFloat(input, GetParam().negate_value, parsed_value); + EXPECT_NE(GetParam().expect_success, input.fail()) + << " literal: " << GetParam().literal + << " negate: " << GetParam().negate_value; + if (GetParam().expect_success) { + EXPECT_THAT(parsed_value.value(), Eq(GetParam().expected_value.value())) + << " literal: " << GetParam().literal + << " negate: " << GetParam().negate_value; + } +} + +// Returns a FloatParseCase with expected failure. +template +FloatParseCase BadFloatParseCase(std::string literal, bool negate_value, + T expected_value) { + HexFloat> proxy_expected_value(expected_value); + return FloatParseCase{literal, negate_value, false, proxy_expected_value}; +} + +// Returns a FloatParseCase that should successfully parse to a given value. +template +FloatParseCase GoodFloatParseCase(std::string literal, bool negate_value, + T expected_value) { + HexFloat> proxy_expected_value(expected_value); + return FloatParseCase{literal, negate_value, true, proxy_expected_value}; +} + +INSTANTIATE_TEST_CASE_P( + FloatParse, ParseNormalFloatTest, + ::testing::ValuesIn(std::vector>{ + // Failing cases due to trivially incorrect syntax. + BadFloatParseCase("abc", false, 0.0f), + BadFloatParseCase("abc", true, 0.0f), + + // Valid cases. + GoodFloatParseCase("0", false, 0.0f), + GoodFloatParseCase("0.0", false, 0.0f), + GoodFloatParseCase("-0.0", false, -0.0f), + GoodFloatParseCase("2.0", false, 2.0f), + GoodFloatParseCase("-2.0", false, -2.0f), + GoodFloatParseCase("+2.0", false, 2.0f), + // Cases with negate_value being true. + GoodFloatParseCase("0.0", true, -0.0f), + GoodFloatParseCase("2.0", true, -2.0f), + + // When negate_value is true, we should not accept a + // leading minus or plus. + BadFloatParseCase("-0.0", true, 0.0f), + BadFloatParseCase("-2.0", true, 0.0f), + BadFloatParseCase("+0.0", true, 0.0f), + BadFloatParseCase("+2.0", true, 0.0f), + + // Overflow is an error for 32-bit float parsing. + BadFloatParseCase("1e40", false, FLT_MAX), + BadFloatParseCase("1e40", true, -FLT_MAX), + BadFloatParseCase("-1e40", false, -FLT_MAX), + // We can't have -1e40 and negate_value == true since + // that represents an original case of "--1e40" which + // is invalid. + }),); + +using ParseNormalFloat16Test = + ::testing::TestWithParam>; + +TEST_P(ParseNormalFloat16Test, Samples) { + std::stringstream input(GetParam().literal); + HexFloat> parsed_value(0); + ParseNormalFloat(input, GetParam().negate_value, parsed_value); + EXPECT_NE(GetParam().expect_success, input.fail()) + << " literal: " << GetParam().literal + << " negate: " << GetParam().negate_value; + if (GetParam().expect_success) { + EXPECT_THAT(parsed_value.value(), Eq(GetParam().expected_value.value())) + << " literal: " << GetParam().literal + << " negate: " << GetParam().negate_value; + } +} + +INSTANTIATE_TEST_CASE_P( + Float16Parse, ParseNormalFloat16Test, + ::testing::ValuesIn(std::vector>{ + // Failing cases due to trivially incorrect syntax. + BadFloatParseCase("abc", false, uint16_t{0}), + BadFloatParseCase("abc", true, uint16_t{0}), + + // Valid cases. + GoodFloatParseCase("0", false, uint16_t{0}), + GoodFloatParseCase("0.0", false, uint16_t{0}), + GoodFloatParseCase("-0.0", false, uint16_t{0x8000}), + GoodFloatParseCase("2.0", false, uint16_t{0x4000}), + GoodFloatParseCase("-2.0", false, uint16_t{0xc000}), + GoodFloatParseCase("+2.0", false, uint16_t{0x4000}), + // Cases with negate_value being true. + GoodFloatParseCase("0.0", true, uint16_t{0x8000}), + GoodFloatParseCase("2.0", true, uint16_t{0xc000}), + + // When negate_value is true, we should not accept a leading minus or + // plus. + BadFloatParseCase("-0.0", true, uint16_t{0}), + BadFloatParseCase("-2.0", true, uint16_t{0}), + BadFloatParseCase("+0.0", true, uint16_t{0}), + BadFloatParseCase("+2.0", true, uint16_t{0}), + }),); + +// A test case for detecting infinities. +template +struct OverflowParseCase { + std::string input; + bool expect_success; + T expected_value; +}; + +using FloatProxyParseOverflowFloatTest = + ::testing::TestWithParam>; + +TEST_P(FloatProxyParseOverflowFloatTest, Sample) { + std::istringstream input(GetParam().input); + HexFloat> value(0.0f); + input >> value; + EXPECT_NE(GetParam().expect_success, input.fail()); + if (GetParam().expect_success) { + EXPECT_THAT(value.value().getAsFloat(), GetParam().expected_value); + } +} + +INSTANTIATE_TEST_CASE_P( + FloatOverflow, FloatProxyParseOverflowFloatTest, + ::testing::ValuesIn(std::vector>({ + {"0", true, 0.0f}, + {"0.0", true, 0.0f}, + {"1.0", true, 1.0f}, + {"1e38", true, 1e38f}, + {"-1e38", true, -1e38f}, + {"1e40", false, FLT_MAX}, + {"-1e40", false, -FLT_MAX}, + {"1e400", false, FLT_MAX}, + {"-1e400", false, -FLT_MAX}, + })),); + +using FloatProxyParseOverflowDoubleTest = + ::testing::TestWithParam>; + +TEST_P(FloatProxyParseOverflowDoubleTest, Sample) { + std::istringstream input(GetParam().input); + HexFloat> value(0.0); + input >> value; + EXPECT_NE(GetParam().expect_success, input.fail()); + if (GetParam().expect_success) { + EXPECT_THAT(value.value().getAsFloat(), Eq(GetParam().expected_value)); + } +} + +INSTANTIATE_TEST_CASE_P( + DoubleOverflow, FloatProxyParseOverflowDoubleTest, + ::testing::ValuesIn(std::vector>({ + {"0", true, 0.0}, + {"0.0", true, 0.0}, + {"1.0", true, 1.0}, + {"1e38", true, 1e38}, + {"-1e38", true, -1e38}, + {"1e40", true, 1e40}, + {"-1e40", true, -1e40}, + {"1e400", false, DBL_MAX}, + {"-1e400", false, -DBL_MAX}, + })),); + +using FloatProxyParseOverflowFloat16Test = + ::testing::TestWithParam>; + +TEST_P(FloatProxyParseOverflowFloat16Test, Sample) { + std::istringstream input(GetParam().input); + HexFloat> value(0); + input >> value; + EXPECT_NE(GetParam().expect_success, input.fail()) << " literal: " + << GetParam().input; + if (GetParam().expect_success) { + EXPECT_THAT(value.value().data(), Eq(GetParam().expected_value)) + << " literal: " << GetParam().input; + } +} + +INSTANTIATE_TEST_CASE_P( + Float16Overflow, FloatProxyParseOverflowFloat16Test, + ::testing::ValuesIn(std::vector>({ + {"0", true, uint16_t{0}}, + {"0.0", true, uint16_t{0}}, + {"1.0", true, uint16_t{0x3c00}}, + // Overflow for 16-bit float is an error, and returns max or + // lowest value. + {"1e38", false, uint16_t{0x7bff}}, + {"1e40", false, uint16_t{0x7bff}}, + {"1e400", false, uint16_t{0x7bff}}, + {"-1e38", false, uint16_t{0xfbff}}, + {"-1e40", false, uint16_t{0xfbff}}, + {"-1e400", false, uint16_t{0xfbff}}, + })),); + +TEST(FloatProxy, Max) { + EXPECT_THAT(FloatProxy::max().getAsFloat().get_value(), + Eq(uint16_t{0x7bff})); + EXPECT_THAT(FloatProxy::max().getAsFloat(), + Eq(std::numeric_limits::max())); + EXPECT_THAT(FloatProxy::max().getAsFloat(), + Eq(std::numeric_limits::max())); +} + +TEST(FloatProxy, Lowest) { + EXPECT_THAT(FloatProxy::lowest().getAsFloat().get_value(), + Eq(uint16_t{0xfbff})); + EXPECT_THAT(FloatProxy::lowest().getAsFloat(), + Eq(std::numeric_limits::lowest())); + EXPECT_THAT(FloatProxy::lowest().getAsFloat(), + Eq(std::numeric_limits::lowest())); +} + +// TODO(awoloszyn): Add fp16 tests and HexFloatTraits. +} // anonymous namespace diff --git a/Externals/glslang/gtests/Hlsl.FromFile.cpp b/Externals/glslang/gtests/Hlsl.FromFile.cpp index 5a6be40d6d..861c098837 100644 --- a/Externals/glslang/gtests/Hlsl.FromFile.cpp +++ b/Externals/glslang/gtests/Hlsl.FromFile.cpp @@ -58,42 +58,228 @@ std::string FileNameAsCustomTestSuffix( } using HlslCompileTest = GlslangTest<::testing::TestWithParam>; +using HlslVulkan1_1CompileTest = GlslangTest<::testing::TestWithParam>; +using HlslCompileAndFlattenTest = GlslangTest<::testing::TestWithParam>; +using HlslLegalizeTest = GlslangTest<::testing::TestWithParam>; -// Compiling HLSL to SPIR-V under Vulkan semantics. Expected to successfully -// generate both AST and SPIR-V. +// Compiling HLSL to pre-legalized SPIR-V under Vulkan semantics. Expected +// to successfully generate both AST and SPIR-V. TEST_P(HlslCompileTest, FromFile) { - loadFileCompileAndCheck(GLSLANG_TEST_DIRECTORY, GetParam().fileName, - Source::HLSL, Semantics::Vulkan, - Target::BothASTAndSpv, GetParam().entryPoint); + loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam().fileName, + Source::HLSL, Semantics::Vulkan, glslang::EShTargetVulkan_1_0, + Target::BothASTAndSpv, true, GetParam().entryPoint); +} + +TEST_P(HlslVulkan1_1CompileTest, FromFile) +{ + loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam().fileName, + Source::HLSL, Semantics::Vulkan, glslang::EShTargetVulkan_1_1, + Target::BothASTAndSpv, true, GetParam().entryPoint); +} + +TEST_P(HlslCompileAndFlattenTest, FromFile) +{ + loadFileCompileFlattenUniformsAndCheck(GlobalTestSettings.testRoot, GetParam().fileName, + Source::HLSL, Semantics::Vulkan, + Target::BothASTAndSpv, GetParam().entryPoint); +} + +// Compiling HLSL to legal SPIR-V under Vulkan semantics. Expected to +// successfully generate SPIR-V. +TEST_P(HlslLegalizeTest, FromFile) +{ + loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam().fileName, + Source::HLSL, Semantics::Vulkan, glslang::EShTargetVulkan_1_0, + Target::Spv, true, GetParam().entryPoint, + "/baseLegalResults/", true); } // clang-format off INSTANTIATE_TEST_CASE_P( ToSpirv, HlslCompileTest, ::testing::ValuesIn(std::vector{ + {"hlsl.amend.frag", "f1"}, + {"hlsl.aliasOpaque.frag", "main"}, {"hlsl.array.frag", "PixelShaderFunction"}, + {"hlsl.array.implicit-size.frag", "PixelShaderFunction"}, + {"hlsl.array.multidim.frag", "main"}, {"hlsl.assoc.frag", "PixelShaderFunction"}, {"hlsl.attribute.frag", "PixelShaderFunction"}, + {"hlsl.attribute.expression.comp", "main"}, + {"hlsl.attributeC11.frag", "main"}, + {"hlsl.attributeGlobalBuffer.frag", "main"}, + {"hlsl.basic.comp", "main"}, + {"hlsl.basic.geom", "main"}, + {"hlsl.boolConv.vert", "main"}, + {"hlsl.buffer.frag", "PixelShaderFunction"}, + {"hlsl.calculatelod.dx10.frag", "main"}, + {"hlsl.calculatelodunclamped.dx10.frag", "main"}, {"hlsl.cast.frag", "PixelShaderFunction"}, + {"hlsl.cbuffer-identifier.vert", "main"}, + {"hlsl.charLit.vert", "main"}, + {"hlsl.clip.frag", "main"}, + {"hlsl.clipdistance-1.frag", "main"}, + {"hlsl.clipdistance-1.geom", "main"}, + {"hlsl.clipdistance-1.vert", "main"}, + {"hlsl.clipdistance-2.frag", "main"}, + {"hlsl.clipdistance-2.geom", "main"}, + {"hlsl.clipdistance-2.vert", "main"}, + {"hlsl.clipdistance-3.frag", "main"}, + {"hlsl.clipdistance-3.geom", "main"}, + {"hlsl.clipdistance-3.vert", "main"}, + {"hlsl.clipdistance-4.frag", "main"}, + {"hlsl.clipdistance-4.geom", "main"}, + {"hlsl.clipdistance-4.vert", "main"}, + {"hlsl.clipdistance-5.frag", "main"}, + {"hlsl.clipdistance-5.vert", "main"}, + {"hlsl.clipdistance-6.frag", "main"}, + {"hlsl.clipdistance-6.vert", "main"}, + {"hlsl.clipdistance-7.frag", "main"}, + {"hlsl.clipdistance-7.vert", "main"}, + {"hlsl.clipdistance-8.frag", "main"}, + {"hlsl.clipdistance-8.vert", "main"}, + {"hlsl.clipdistance-9.frag", "main"}, + {"hlsl.clipdistance-9.vert", "main"}, + {"hlsl.color.hull.tesc", "main"}, + {"hlsl.comparison.vec.frag", "main"}, + {"hlsl.conditional.frag", "PixelShaderFunction"}, + {"hlsl.constantbuffer.frag", "main"}, + {"hlsl.constructArray.vert", "main"}, + {"hlsl.constructexpr.frag", "main"}, + {"hlsl.constructimat.frag", "main"}, + {"hlsl.coverage.frag", "main"}, + {"hlsl.depthGreater.frag", "PixelShaderFunction"}, + {"hlsl.depthLess.frag", "PixelShaderFunction"}, {"hlsl.discard.frag", "PixelShaderFunction"}, {"hlsl.doLoop.frag", "PixelShaderFunction"}, + {"hlsl.emptystructreturn.frag", "main"}, + {"hlsl.emptystructreturn.vert", "main"}, + {"hlsl.emptystruct.init.vert", "main"}, + {"hlsl.entry-in.frag", "PixelShaderFunction"}, + {"hlsl.entry-out.frag", "PixelShaderFunction"}, + {"hlsl.fraggeom.frag", "main"}, {"hlsl.float1.frag", "PixelShaderFunction"}, {"hlsl.float4.frag", "PixelShaderFunction"}, + {"hlsl.flatten.return.frag", "main"}, + {"hlsl.flattenOpaque.frag", "main"}, + {"hlsl.flattenOpaqueInit.vert", "main"}, + {"hlsl.flattenOpaqueInitMix.vert", "main"}, + {"hlsl.flattenSubset.frag", "main"}, + {"hlsl.flattenSubset2.frag", "main"}, {"hlsl.forLoop.frag", "PixelShaderFunction"}, + {"hlsl.gather.array.dx10.frag", "main"}, + {"hlsl.gather.basic.dx10.frag", "main"}, + {"hlsl.gather.basic.dx10.vert", "main"}, + {"hlsl.gather.offset.dx10.frag", "main"}, + {"hlsl.gather.offsetarray.dx10.frag", "main"}, + {"hlsl.gathercmpRGBA.offset.dx10.frag", "main"}, + {"hlsl.gatherRGBA.array.dx10.frag", "main"}, + {"hlsl.gatherRGBA.basic.dx10.frag", "main"}, + {"hlsl.gatherRGBA.offset.dx10.frag", "main"}, + {"hlsl.gatherRGBA.offsetarray.dx10.frag", "main"}, + {"hlsl.getdimensions.dx10.frag", "main"}, + {"hlsl.getdimensions.rw.dx10.frag", "main"}, + {"hlsl.getdimensions.dx10.vert", "main"}, + {"hlsl.getsampleposition.dx10.frag", "main"}, + {"hlsl.global-const-init.frag", "main"}, + {"hlsl.gs-hs-mix.tesc", "HSMain"}, + {"hlsl.domain.1.tese", "main"}, + {"hlsl.domain.2.tese", "main"}, + {"hlsl.domain.3.tese", "main"}, + {"hlsl.function.frag", "main"}, + {"hlsl.hull.1.tesc", "main"}, + {"hlsl.hull.2.tesc", "main"}, + {"hlsl.hull.3.tesc", "main"}, + {"hlsl.hull.4.tesc", "main"}, + {"hlsl.hull.5.tesc", "main"}, + {"hlsl.hull.void.tesc", "main"}, + {"hlsl.hull.ctrlpt-1.tesc", "main"}, + {"hlsl.hull.ctrlpt-2.tesc", "main"}, + {"hlsl.groupid.comp", "main"}, + {"hlsl.identifier.sample.frag", "main"}, {"hlsl.if.frag", "PixelShaderFunction"}, + {"hlsl.imagefetch-subvec4.comp", "main"}, + {"hlsl.implicitBool.frag", "main"}, + {"hlsl.inf.vert", "main"}, {"hlsl.inoutquals.frag", "main"}, {"hlsl.init.frag", "ShaderFunction"}, + {"hlsl.init2.frag", "main"}, + {"hlsl.isfinite.frag", "main"}, {"hlsl.intrinsics.barriers.comp", "ComputeShaderFunction"}, {"hlsl.intrinsics.comp", "ComputeShaderFunction"}, {"hlsl.intrinsics.evalfns.frag", "main"}, + {"hlsl.intrinsics.d3dcolortoubyte4.frag", "main"}, {"hlsl.intrinsics.double.frag", "PixelShaderFunction"}, - {"hlsl.intrinsics.f1632.frag", "PixelShaderFunction"}, - {"hlsl.intrinsics.frag", "PixelShaderFunction"}, + {"hlsl.intrinsics.f1632.frag", "main"}, + {"hlsl.intrinsics.f3216.frag", "main"}, + {"hlsl.intrinsics.frag", "main"}, + {"hlsl.intrinsic.frexp.frag", "main"}, {"hlsl.intrinsics.lit.frag", "PixelShaderFunction"}, {"hlsl.intrinsics.negative.comp", "ComputeShaderFunction"}, {"hlsl.intrinsics.negative.frag", "PixelShaderFunction"}, {"hlsl.intrinsics.negative.vert", "VertexShaderFunction"}, + {"hlsl.intrinsics.promote.frag", "main"}, + {"hlsl.intrinsics.promote.down.frag", "main"}, + {"hlsl.intrinsics.promote.outputs.frag", "main"}, + {"hlsl.layout.frag", "main"}, + {"hlsl.layoutOverride.vert", "main"}, + {"hlsl.load.2dms.dx10.frag", "main"}, + {"hlsl.load.array.dx10.frag", "main"}, + {"hlsl.load.basic.dx10.frag", "main"}, + {"hlsl.load.basic.dx10.vert", "main"}, + {"hlsl.load.buffer.dx10.frag", "main"}, + {"hlsl.load.buffer.float.dx10.frag", "main"}, + {"hlsl.load.rwbuffer.dx10.frag", "main"}, + {"hlsl.load.rwtexture.dx10.frag", "main"}, + {"hlsl.load.rwtexture.array.dx10.frag", "main"}, + {"hlsl.load.offset.dx10.frag", "main"}, + {"hlsl.load.offsetarray.dx10.frag", "main"}, + {"hlsl.localStructuredBuffer.comp", "main"}, + {"hlsl.logical.binary.frag", "main"}, + {"hlsl.logical.binary.vec.frag", "main"}, + {"hlsl.logicalConvert.frag", "main"}, + {"hlsl.logical.unary.frag", "main"}, + {"hlsl.loopattr.frag", "main"}, + {"hlsl.matpack-pragma.frag", "main"}, + {"hlsl.mip.operator.frag", "main"}, + {"hlsl.mip.negative.frag", "main"}, + {"hlsl.mip.negative2.frag", "main"}, + {"hlsl.namespace.frag", "main"}, + {"hlsl.nonint-index.frag", "main"}, + {"hlsl.matNx1.frag", "main"}, + {"hlsl.matpack-1.frag", "main"}, + {"hlsl.matrixSwizzle.vert", "ShaderFunction"}, + {"hlsl.memberFunCall.frag", "main"}, + {"hlsl.mintypes.frag", "main"}, + {"hlsl.mul-truncate.frag", "main"}, + {"hlsl.multiEntry.vert", "RealEntrypoint"}, + {"hlsl.multiReturn.frag", "main"}, + {"hlsl.matrixindex.frag", "main"}, + {"hlsl.nonstaticMemberFunction.frag", "main"}, + {"hlsl.numericsuffixes.frag", "main"}, + {"hlsl.numthreads.comp", "main_aux2"}, + {"hlsl.overload.frag", "PixelShaderFunction"}, + {"hlsl.opaque-type-bug.frag", "main"}, + {"hlsl.params.default.frag", "main"}, + {"hlsl.params.default.negative.frag", "main"}, + {"hlsl.partialInit.frag", "PixelShaderFunction"}, + {"hlsl.partialFlattenLocal.vert", "main"}, + {"hlsl.PointSize.geom", "main"}, + {"hlsl.PointSize.vert", "main"}, + {"hlsl.pp.vert", "main"}, + {"hlsl.pp.line.frag", "main"}, + {"hlsl.precise.frag", "main"}, + {"hlsl.promote.atomic.frag", "main"}, + {"hlsl.promote.binary.frag", "main"}, + {"hlsl.promote.vec1.frag", "main"}, + {"hlsl.promotions.frag", "main"}, + {"hlsl.rw.atomics.frag", "main"}, + {"hlsl.rw.bracket.frag", "main"}, + {"hlsl.rw.register.frag", "main"}, + {"hlsl.rw.scalar.bracket.frag", "main"}, + {"hlsl.rw.swizzle.frag", "main"}, + {"hlsl.rw.vec2.bracket.frag", "main"}, {"hlsl.sample.array.dx10.frag", "main"}, {"hlsl.sample.basic.dx10.frag", "main"}, {"hlsl.sample.offset.dx10.frag", "main"}, @@ -102,29 +288,150 @@ INSTANTIATE_TEST_CASE_P( {"hlsl.samplebias.basic.dx10.frag", "main"}, {"hlsl.samplebias.offset.dx10.frag", "main"}, {"hlsl.samplebias.offsetarray.dx10.frag", "main"}, + {"hlsl.samplecmp.array.dx10.frag", "main"}, + {"hlsl.samplecmp.basic.dx10.frag", "main"}, + {"hlsl.samplecmp.dualmode.frag", "main"}, + {"hlsl.samplecmp.offset.dx10.frag", "main"}, + {"hlsl.samplecmp.offsetarray.dx10.frag", "main"}, + {"hlsl.samplecmp.negative.frag", "main"}, + {"hlsl.samplecmp.negative2.frag", "main"}, + {"hlsl.samplecmplevelzero.array.dx10.frag", "main"}, + {"hlsl.samplecmplevelzero.basic.dx10.frag", "main"}, + {"hlsl.samplecmplevelzero.offset.dx10.frag", "main"}, + {"hlsl.samplecmplevelzero.offsetarray.dx10.frag", "main"}, {"hlsl.samplegrad.array.dx10.frag", "main"}, {"hlsl.samplegrad.basic.dx10.frag", "main"}, {"hlsl.samplegrad.basic.dx10.vert", "main"}, {"hlsl.samplegrad.offset.dx10.frag", "main"}, {"hlsl.samplegrad.offsetarray.dx10.frag", "main"}, + {"hlsl.samplelevel.array.dx10.frag", "main"}, + {"hlsl.samplelevel.basic.dx10.frag", "main"}, + {"hlsl.samplelevel.basic.dx10.vert", "main"}, + {"hlsl.samplelevel.offset.dx10.frag", "main"}, + {"hlsl.samplelevel.offsetarray.dx10.frag", "main"}, + {"hlsl.sample.sub-vec4.dx10.frag", "main"}, + {"hlsl.scalar-length.frag", "main"}, + {"hlsl.scalarCast.vert", "main"}, + {"hlsl.semicolons.frag", "main"}, + {"hlsl.shapeConv.frag", "main"}, + {"hlsl.shapeConvRet.frag", "main"}, + {"hlsl.self_cast.frag", "main"}, + {"hlsl.snorm.uav.comp", "main"}, + {"hlsl.staticMemberFunction.frag", "main"}, + {"hlsl.store.rwbyteaddressbuffer.type.comp", "main"}, + {"hlsl.stringtoken.frag", "main"}, + {"hlsl.string.frag", "main"}, + {"hlsl.struct.split-1.vert", "main"}, + {"hlsl.struct.split.array.geom", "main"}, + {"hlsl.struct.split.assign.frag", "main"}, + {"hlsl.struct.split.call.vert", "main"}, + {"hlsl.struct.split.nested.geom", "main"}, + {"hlsl.struct.split.trivial.geom", "main"}, + {"hlsl.struct.split.trivial.vert", "main"}, + {"hlsl.structarray.flatten.frag", "main"}, + {"hlsl.structarray.flatten.geom", "main"}, + {"hlsl.structbuffer.frag", "main"}, + {"hlsl.structbuffer.append.frag", "main"}, + {"hlsl.structbuffer.append.fn.frag", "main"}, + {"hlsl.structbuffer.atomics.frag", "main"}, + {"hlsl.structbuffer.byte.frag", "main"}, + {"hlsl.structbuffer.coherent.frag", "main"}, + {"hlsl.structbuffer.floatidx.comp", "main"}, + {"hlsl.structbuffer.incdec.frag", "main"}, + {"hlsl.structbuffer.fn.frag", "main"}, + {"hlsl.structbuffer.fn2.comp", "main"}, + {"hlsl.structbuffer.rw.frag", "main"}, + {"hlsl.structbuffer.rwbyte.frag", "main"}, + {"hlsl.structin.vert", "main"}, + {"hlsl.structIoFourWay.frag", "main"}, + {"hlsl.structStructName.frag", "main"}, + {"hlsl.subpass.frag", "main"}, + {"hlsl.synthesizeInput.frag", "main"}, + {"hlsl.texturebuffer.frag", "main"}, + {"hlsl.texture.struct.frag", "main"}, + {"hlsl.texture.subvec4.frag", "main"}, + {"hlsl.this.frag", "main"}, {"hlsl.intrinsics.vert", "VertexShaderFunction"}, + {"hlsl.intrinsic.frexp.vert", "VertexShaderFunction"}, {"hlsl.matType.frag", "PixelShaderFunction"}, + {"hlsl.matType.bool.frag", "main"}, + {"hlsl.matType.int.frag", "main"}, {"hlsl.max.frag", "PixelShaderFunction"}, + {"hlsl.preprocessor.frag", "main"}, {"hlsl.precedence.frag", "PixelShaderFunction"}, {"hlsl.precedence2.frag", "PixelShaderFunction"}, + {"hlsl.scalar2matrix.frag", "main"}, + {"hlsl.semantic.geom", "main"}, + {"hlsl.semantic.vert", "main"}, + {"hlsl.semantic-1.vert", "main"}, {"hlsl.scope.frag", "PixelShaderFunction"}, {"hlsl.sin.frag", "PixelShaderFunction"}, {"hlsl.struct.frag", "PixelShaderFunction"}, {"hlsl.switch.frag", "PixelShaderFunction"}, {"hlsl.swizzle.frag", "PixelShaderFunction"}, + {"hlsl.target.frag", "main"}, + {"hlsl.targetStruct1.frag", "main"}, + {"hlsl.targetStruct2.frag", "main"}, {"hlsl.templatetypes.frag", "PixelShaderFunction"}, + {"hlsl.tristream-append.geom", "main"}, + {"hlsl.tx.bracket.frag", "main"}, + {"hlsl.tx.overload.frag", "main"}, + {"hlsl.type.half.frag", "main"}, + {"hlsl.type.identifier.frag", "main"}, + {"hlsl.typeGraphCopy.vert", "main"}, {"hlsl.typedef.frag", "PixelShaderFunction"}, {"hlsl.whileLoop.frag", "PixelShaderFunction"}, - {"hlsl.void.frag", "PixelShaderFunction"}, + {"hlsl.void.frag", "PixelShaderFunction"} }), FileNameAsCustomTestSuffix ); // clang-format on +// clang-format off +INSTANTIATE_TEST_CASE_P( + ToSpirv, HlslVulkan1_1CompileTest, + ::testing::ValuesIn(std::vector{ + {"hlsl.wavebroadcast.comp", "CSMain"}, + {"hlsl.waveprefix.comp", "CSMain"}, + {"hlsl.wavequad.comp", "CSMain"}, + {"hlsl.wavequery.comp", "CSMain"}, + {"hlsl.wavequery.frag", "PixelShaderFunction"}, + {"hlsl.wavereduction.comp", "CSMain"}, + {"hlsl.wavevote.comp", "CSMain"}, + }), + FileNameAsCustomTestSuffix +); +// clang-format on + +// clang-format off +INSTANTIATE_TEST_CASE_P( + ToSpirv, HlslCompileAndFlattenTest, + ::testing::ValuesIn(std::vector{ + {"hlsl.array.flatten.frag", "main"}, + {"hlsl.partialFlattenMixed.vert", "main"}, + }), + FileNameAsCustomTestSuffix +); +// clang-format on + +#if ENABLE_OPT +// clang-format off +INSTANTIATE_TEST_CASE_P( + ToSpirv, HlslLegalizeTest, + ::testing::ValuesIn(std::vector{ + {"hlsl.aliasOpaque.frag", "main"}, + {"hlsl.flattenOpaque.frag", "main"}, + {"hlsl.flattenOpaqueInit.vert", "main"}, + {"hlsl.flattenOpaqueInitMix.vert", "main"}, + {"hlsl.flattenSubset.frag", "main"}, + {"hlsl.flattenSubset2.frag", "main"}, + {"hlsl.partialFlattenLocal.vert", "main"}, + {"hlsl.partialFlattenMixed.vert", "main"} + }), + FileNameAsCustomTestSuffix +); +// clang-format on +#endif + } // anonymous namespace } // namespace glslangtest diff --git a/Externals/glslang/gtests/Initializer.h b/Externals/glslang/gtests/Initializer.h index 34af9ad9a1..b46b3f55dc 100644 --- a/Externals/glslang/gtests/Initializer.h +++ b/Externals/glslang/gtests/Initializer.h @@ -40,46 +40,14 @@ namespace glslangtest { // Initializes glslang on creation, and destroys it on completion. -// And provides .Acquire() as a way to reinitialize glslang if semantics change. // This object is expected to be a singleton, so that internal glslang state // can be correctly handled. // -// TODO(antiagainst): It's a known bug that some of the internal states need to -// be reset if semantics change: -// https://github.com/KhronosGroup/glslang/issues/166 -// Therefore, the following mechanism is needed. Remove this once the above bug -// gets fixed. class GlslangInitializer { public: - GlslangInitializer() : lastMessages(EShMsgCascadingErrors) - { - glslang::InitializeProcess(); - } + GlslangInitializer() { glslang::InitializeProcess(); } ~GlslangInitializer() { glslang::FinalizeProcess(); } - - // A token indicates that the glslang is reinitialized (if necessary) to the - // required semantics. And that won't change until the token is destroyed. - class InitializationToken { - }; - - // Re-initializes glsl state iff the previous messages and the current - // messages are incompatible. We assume external synchronization, i.e. - // there is at most one acquired token at any one time. - InitializationToken acquire(EShMessages new_messages) - { - if ((lastMessages ^ new_messages) & - (EShMsgVulkanRules | EShMsgSpvRules | EShMsgReadHlsl)) { - glslang::FinalizeProcess(); - glslang::InitializeProcess(); - } - lastMessages = new_messages; - return InitializationToken(); - } - -private: - - EShMessages lastMessages; }; } // namespace glslangtest diff --git a/Externals/glslang/gtests/Link.FromFile.Vk.cpp b/Externals/glslang/gtests/Link.FromFile.Vk.cpp new file mode 100644 index 0000000000..0a616d827f --- /dev/null +++ b/Externals/glslang/gtests/Link.FromFile.Vk.cpp @@ -0,0 +1,114 @@ +// +// Copyright (C) 2016-2017 Google, 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 Google Inc. 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. + +#include + +#include + +#include "TestFixture.h" + +namespace glslangtest { +namespace { + +using LinkTestVulkan = GlslangTest< + ::testing::TestWithParam>>; + +TEST_P(LinkTestVulkan, FromFile) +{ + const auto& fileNames = GetParam(); + const size_t fileCount = fileNames.size(); + const EShMessages controls = DeriveOptions(Source::GLSL, Semantics::Vulkan, Target::AST); + GlslangResult result; + + // Compile each input shader file. + bool success = true; + std::vector> shaders; + for (size_t i = 0; i < fileCount; ++i) { + std::string contents; + tryLoadFile(GlobalTestSettings.testRoot + "/" + fileNames[i], + "input", &contents); + shaders.emplace_back( + new glslang::TShader(GetShaderStage(GetSuffix(fileNames[i])))); + auto* shader = shaders.back().get(); + shader->setAutoMapLocations(true); + success &= compile(shader, contents, "", controls); + result.shaderResults.push_back( + {fileNames[i], shader->getInfoLog(), shader->getInfoDebugLog()}); + } + + // Link all of them. + glslang::TProgram program; + for (const auto& shader : shaders) program.addShader(shader.get()); + success &= program.link(controls); + result.linkingOutput = program.getInfoLog(); + result.linkingError = program.getInfoDebugLog(); + + if (success && (controls & EShMsgSpvRules)) { + spv::SpvBuildLogger logger; + std::vector spirv_binary; + glslang::SpvOptions options; + options.disableOptimizer = true; + glslang::GlslangToSpv(*program.getIntermediate(shaders.front()->getStage()), + spirv_binary, &logger, &options); + + std::ostringstream disassembly_stream; + spv::Parameterize(); + spv::Disassemble(disassembly_stream, spirv_binary); + result.spirvWarningsErrors = logger.getAllMessages(); + result.spirv = disassembly_stream.str(); + } + + std::ostringstream stream; + outputResultToStream(&stream, result, controls); + + // Check with expected results. + const std::string expectedOutputFname = + GlobalTestSettings.testRoot + "/baseResults/" + fileNames.front() + ".out"; + std::string expectedOutput; + tryLoadFile(expectedOutputFname, "expected output", &expectedOutput); + + checkEqAndUpdateIfRequested(expectedOutput, stream.str(), expectedOutputFname); +} + +// clang-format off +INSTANTIATE_TEST_CASE_P( + Glsl, LinkTestVulkan, + ::testing::ValuesIn(std::vector>({ + {"link1.vk.frag", "link2.vk.frag"}, + })), +); +// clang-format on + +} // anonymous namespace +} // namespace glslangtest diff --git a/Externals/glslang/gtests/Link.FromFile.cpp b/Externals/glslang/gtests/Link.FromFile.cpp index b324b9ab07..ab845bf59e 100644 --- a/Externals/glslang/gtests/Link.FromFile.cpp +++ b/Externals/glslang/gtests/Link.FromFile.cpp @@ -55,7 +55,7 @@ TEST_P(LinkTest, FromFile) std::vector> shaders; for (size_t i = 0; i < fileCount; ++i) { std::string contents; - tryLoadFile(GLSLANG_TEST_DIRECTORY "/" + fileNames[i], + tryLoadFile(GlobalTestSettings.testRoot + "/" + fileNames[i], "input", &contents); shaders.emplace_back( new glslang::TShader(GetShaderStage(GetSuffix(fileNames[i])))); @@ -77,7 +77,7 @@ TEST_P(LinkTest, FromFile) // Check with expected results. const std::string expectedOutputFname = - GLSLANG_TEST_DIRECTORY "/baseResults/" + fileNames.front() + ".out"; + GlobalTestSettings.testRoot + "/baseResults/" + fileNames.front() + ".out"; std::string expectedOutput; tryLoadFile(expectedOutputFname, "expected output", &expectedOutput); @@ -99,6 +99,7 @@ INSTANTIATE_TEST_CASE_P( {"150.tesc", "150.tese", "400.tesc", "400.tese", "410.tesc", "420.tesc", "420.tese"}, {"max_vertices_0.geom"}, {"es-link1.frag", "es-link2.frag"}, + {"missingBodies.vert"} })), ); // clang-format on diff --git a/Externals/glslang/gtests/Pp.FromFile.cpp b/Externals/glslang/gtests/Pp.FromFile.cpp index 04ac3f7578..13daac0d67 100644 --- a/Externals/glslang/gtests/Pp.FromFile.cpp +++ b/Externals/glslang/gtests/Pp.FromFile.cpp @@ -43,7 +43,7 @@ using PreprocessingTest = GlslangTest<::testing::TestWithParam>; TEST_P(PreprocessingTest, FromFile) { - loadFilePreprocessAndCheck(GLSLANG_TEST_DIRECTORY, GetParam()); + loadFilePreprocessAndCheck(GlobalTestSettings.testRoot, GetParam()); } // clang-format off diff --git a/Externals/glslang/gtests/Remap.FromFile.cpp b/Externals/glslang/gtests/Remap.FromFile.cpp new file mode 100644 index 0000000000..50bce8e357 --- /dev/null +++ b/Externals/glslang/gtests/Remap.FromFile.cpp @@ -0,0 +1,118 @@ +// +// Copyright (C) 2016 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 Google Inc. 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. + +#include + +#include "TestFixture.h" + +namespace glslangtest { +namespace { + +struct RemapTestArgs { + const char* fileName; + const char* entryPoint; + Source sourceLanguage; + unsigned int remapOpts; +}; + +// We are using FileNameEntryPointPair objects as parameters for instantiating +// the template, so the global FileNameAsCustomTestSuffix() won't work since +// it assumes std::string as parameters. Thus, an overriding one here. +std::string FileNameAsCustomTestSuffix( + const ::testing::TestParamInfo& info) { + std::string name = info.param.fileName; + // A valid test case suffix cannot have '.' and '-' inside. + std::replace(name.begin(), name.end(), '.', '_'); + std::replace(name.begin(), name.end(), '-', '_'); + return name; +} + +using RemapTest = GlslangTest<::testing::TestWithParam>; + +// Remapping SPIR-V modules. +TEST_P(RemapTest, FromFile) +{ + if (GetSuffix(GetParam().fileName) == "spv") { + loadFileRemapAndCheck(GlobalTestSettings.testRoot, GetParam().fileName, + GetParam().sourceLanguage, + Semantics::Vulkan, + Target::Spv, + GetParam().remapOpts); + } else { + loadFileCompileRemapAndCheck(GlobalTestSettings.testRoot, GetParam().fileName, + GetParam().sourceLanguage, + Semantics::Vulkan, + Target::Spv, + GetParam().entryPoint, + GetParam().remapOpts); + } +} + +// clang-format off +INSTANTIATE_TEST_CASE_P( + ToSpirv, RemapTest, + ::testing::ValuesIn(std::vector{ + // GLSL remapper tests + // testname entry language remapper_options + { "remap.basic.none.frag", "main", Source::GLSL, spv::spirvbin_t::NONE }, + { "remap.basic.everything.frag", "main", Source::GLSL, spv::spirvbin_t::DO_EVERYTHING }, + { "remap.basic.dcefunc.frag", "main", Source::GLSL, spv::spirvbin_t::DCE_FUNCS }, + { "remap.basic.strip.frag", "main", Source::GLSL, spv::spirvbin_t::STRIP }, + { "remap.specconst.comp", "main", Source::GLSL, spv::spirvbin_t::DO_EVERYTHING }, + { "remap.switch.none.frag", "main", Source::GLSL, spv::spirvbin_t::NONE }, + { "remap.switch.everything.frag", "main", Source::GLSL, spv::spirvbin_t::DO_EVERYTHING }, + { "remap.literal64.none.spv", "main", Source::GLSL, spv::spirvbin_t::NONE }, + { "remap.literal64.everything.spv", "main", Source::GLSL, spv::spirvbin_t::DO_EVERYTHING }, + { "remap.if.none.frag", "main", Source::GLSL, spv::spirvbin_t::NONE }, + { "remap.if.everything.frag", "main", Source::GLSL, spv::spirvbin_t::DO_EVERYTHING }, + { "remap.similar_1a.none.frag", "main", Source::GLSL, spv::spirvbin_t::NONE }, + { "remap.similar_1b.none.frag", "main", Source::GLSL, spv::spirvbin_t::NONE }, + { "remap.similar_1a.everything.frag", "main", Source::GLSL, spv::spirvbin_t::DO_EVERYTHING }, + { "remap.similar_1b.everything.frag", "main", Source::GLSL, spv::spirvbin_t::DO_EVERYTHING }, + { "remap.uniformarray.none.frag", "main", Source::GLSL, spv::spirvbin_t::NONE }, + { "remap.uniformarray.everything.frag", "main", Source::GLSL, spv::spirvbin_t::DO_EVERYTHING }, + + // HLSL remapper tests + { "remap.hlsl.sample.basic.strip.frag", "main", Source::HLSL, spv::spirvbin_t::STRIP }, + { "remap.hlsl.sample.basic.everything.frag", "main", Source::HLSL, spv::spirvbin_t::DO_EVERYTHING }, + { "remap.hlsl.sample.basic.none.frag", "main", Source::HLSL, spv::spirvbin_t::NONE }, + { "remap.hlsl.templatetypes.none.frag", "main", Source::HLSL, spv::spirvbin_t::NONE }, + { "remap.hlsl.templatetypes.everything.frag", "main", Source::HLSL, spv::spirvbin_t::DO_EVERYTHING }, + }), + FileNameAsCustomTestSuffix +); +// clang-format on + +} // anonymous namespace +} // namespace glslangtest diff --git a/Externals/glslang/gtests/Settings.cpp b/Externals/glslang/gtests/Settings.cpp index 4ba7989b4a..0ac58449c6 100644 --- a/Externals/glslang/gtests/Settings.cpp +++ b/Externals/glslang/gtests/Settings.cpp @@ -36,6 +36,16 @@ namespace glslangtest { -GTestSettings GlobalTestSettings = {nullptr, false}; +// We need CMake to provide us the absolute path to the directory containing +// test files, so we are certain to find those files no matter where the test +// harness binary is generated. This provides out-of-source build capability. +// This will be used as the default test root, but can be overridden with +// the --test-root argument. +#ifndef GLSLANG_TEST_DIRECTORY +#error \ + "GLSLANG_TEST_DIRECTORY needs to be defined for gtest to locate test files." +#endif + +GTestSettings GlobalTestSettings = {nullptr, false, GLSLANG_TEST_DIRECTORY}; } // namespace glslangtest diff --git a/Externals/glslang/gtests/Settings.h b/Externals/glslang/gtests/Settings.h index 30056a7bac..c38474ccf9 100644 --- a/Externals/glslang/gtests/Settings.h +++ b/Externals/glslang/gtests/Settings.h @@ -35,6 +35,8 @@ #ifndef GLSLANG_GTESTS_SETTINGS_H #define GLSLANG_GTESTS_SETTINGS_H +#include + namespace glslangtest { class GlslangInitializer; @@ -45,6 +47,8 @@ struct GTestSettings { // An indicator of whether GTest should write real output to the file for // the expected output. bool updateMode; + // The root directory for test files. + std::string testRoot; }; extern GTestSettings GlobalTestSettings; diff --git a/Externals/glslang/gtests/Spv.FromFile.cpp b/Externals/glslang/gtests/Spv.FromFile.cpp old mode 100644 new mode 100755 index dbe0507df4..4b1ff462cc --- a/Externals/glslang/gtests/Spv.FromFile.cpp +++ b/Externals/glslang/gtests/Spv.FromFile.cpp @@ -1,4 +1,4 @@ -// + // // Copyright (C) 2016 Google, Inc. // // All rights reserved. @@ -41,18 +41,56 @@ namespace glslangtest { namespace { +struct IoMapData { + const char* fileName; + const char* entryPoint; + int baseSamplerBinding; + int baseTextureBinding; + int baseImageBinding; + int baseUboBinding; + int baseSsboBinding; + bool autoMapBindings; + bool flattenUniforms; +}; + +std::string FileNameAsCustomTestSuffixIoMap( + const ::testing::TestParamInfo& info) { + std::string name = info.param.fileName; + // A valid test case suffix cannot have '.' and '-' inside. + std::replace(name.begin(), name.end(), '.', '_'); + std::replace(name.begin(), name.end(), '-', '_'); + return name; +} + using CompileVulkanToSpirvTest = GlslangTest<::testing::TestWithParam>; +using CompileVulkan1_1ToSpirvTest = GlslangTest<::testing::TestWithParam>; using CompileOpenGLToSpirvTest = GlslangTest<::testing::TestWithParam>; using VulkanSemantics = GlslangTest<::testing::TestWithParam>; using OpenGLSemantics = GlslangTest<::testing::TestWithParam>; using VulkanAstSemantics = GlslangTest<::testing::TestWithParam>; +using HlslIoMap = GlslangTest<::testing::TestWithParam>; +using GlslIoMap = GlslangTest<::testing::TestWithParam>; +#ifdef AMD_EXTENSIONS +using CompileVulkanToSpirvTestAMD = GlslangTest<::testing::TestWithParam>; +#endif +#ifdef NV_EXTENSIONS +using CompileVulkanToSpirvTestNV = GlslangTest<::testing::TestWithParam>; +#endif +using CompileUpgradeTextureToSampledTextureAndDropSamplersTest = GlslangTest<::testing::TestWithParam>; // Compiling GLSL to SPIR-V under Vulkan semantics. Expected to successfully // generate SPIR-V. TEST_P(CompileVulkanToSpirvTest, FromFile) { - loadFileCompileAndCheck(GLSLANG_TEST_DIRECTORY, GetParam(), - Source::GLSL, Semantics::Vulkan, + loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam(), + Source::GLSL, Semantics::Vulkan, glslang::EShTargetVulkan_1_0, + Target::Spv); +} + +TEST_P(CompileVulkan1_1ToSpirvTest, FromFile) +{ + loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam(), + Source::GLSL, Semantics::Vulkan, glslang::EShTargetVulkan_1_1, Target::Spv); } @@ -60,8 +98,8 @@ TEST_P(CompileVulkanToSpirvTest, FromFile) // generate SPIR-V. TEST_P(CompileOpenGLToSpirvTest, FromFile) { - loadFileCompileAndCheck(GLSLANG_TEST_DIRECTORY, GetParam(), - Source::GLSL, Semantics::OpenGL, + loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam(), + Source::GLSL, Semantics::OpenGL, glslang::EShTargetVulkan_1_0, Target::Spv); } @@ -69,28 +107,89 @@ TEST_P(CompileOpenGLToSpirvTest, FromFile) // SPIR-V. TEST_P(VulkanSemantics, FromFile) { - loadFileCompileAndCheck(GLSLANG_TEST_DIRECTORY, GetParam(), - Source::GLSL, Semantics::Vulkan, - Target::Spv); + loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam(), + Source::GLSL, Semantics::Vulkan, glslang::EShTargetVulkan_1_0, + Target::Spv, false); } // GLSL-level Vulkan semantics test. Expected to error out before generating // SPIR-V. TEST_P(OpenGLSemantics, FromFile) { - loadFileCompileAndCheck(GLSLANG_TEST_DIRECTORY, GetParam(), - Source::GLSL, Semantics::OpenGL, - Target::Spv); + loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam(), + Source::GLSL, Semantics::OpenGL, glslang::EShTargetVulkan_1_0, + Target::Spv, false); } // GLSL-level Vulkan semantics test that need to see the AST for validation. TEST_P(VulkanAstSemantics, FromFile) { - loadFileCompileAndCheck(GLSLANG_TEST_DIRECTORY, GetParam(), - Source::GLSL, Semantics::Vulkan, + loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam(), + Source::GLSL, Semantics::Vulkan, glslang::EShTargetVulkan_1_0, Target::AST); } +// HLSL-level Vulkan semantics tests. +TEST_P(HlslIoMap, FromFile) +{ + loadFileCompileIoMapAndCheck(GlobalTestSettings.testRoot, GetParam().fileName, + Source::HLSL, Semantics::Vulkan, + Target::Spv, GetParam().entryPoint, + GetParam().baseSamplerBinding, + GetParam().baseTextureBinding, + GetParam().baseImageBinding, + GetParam().baseUboBinding, + GetParam().baseSsboBinding, + GetParam().autoMapBindings, + GetParam().flattenUniforms); +} + +// GLSL-level Vulkan semantics tests. +TEST_P(GlslIoMap, FromFile) +{ + loadFileCompileIoMapAndCheck(GlobalTestSettings.testRoot, GetParam().fileName, + Source::GLSL, Semantics::Vulkan, + Target::Spv, GetParam().entryPoint, + GetParam().baseSamplerBinding, + GetParam().baseTextureBinding, + GetParam().baseImageBinding, + GetParam().baseUboBinding, + GetParam().baseSsboBinding, + GetParam().autoMapBindings, + GetParam().flattenUniforms); +} + +#ifdef AMD_EXTENSIONS +// Compiling GLSL to SPIR-V under Vulkan semantics (AMD extensions enabled). +// Expected to successfully generate SPIR-V. +TEST_P(CompileVulkanToSpirvTestAMD, FromFile) +{ + loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam(), + Source::GLSL, Semantics::Vulkan, glslang::EShTargetVulkan_1_0, + Target::Spv); +} +#endif + +#ifdef NV_EXTENSIONS +// Compiling GLSL to SPIR-V under Vulkan semantics (NV extensions enabled). +// Expected to successfully generate SPIR-V. +TEST_P(CompileVulkanToSpirvTestNV, FromFile) +{ + loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam(), + Source::GLSL, Semantics::Vulkan, glslang::EShTargetVulkan_1_0, + Target::Spv); +} +#endif + +TEST_P(CompileUpgradeTextureToSampledTextureAndDropSamplersTest, FromFile) +{ + loadCompileUpgradeTextureToSampledTextureAndDropSamplersAndCheck(GlobalTestSettings.testRoot, + GetParam(), + Source::GLSL, + Semantics::Vulkan, + Target::Spv); +} + // clang-format off INSTANTIATE_TEST_CASE_P( Glsl, CompileVulkanToSpirvTest, @@ -98,6 +197,7 @@ INSTANTIATE_TEST_CASE_P( // Test looping constructs. // No tests yet for making sure break and continue from a nested loop // goes to the innermost target. + "spv.barrier.vert", "spv.do-simple.vert", "spv.do-while-continue-break.vert", "spv.for-complex-condition.vert", @@ -129,15 +229,22 @@ INSTANTIATE_TEST_CASE_P( "spv.430.frag", "spv.430.vert", "spv.450.tesc", + "spv.450.geom", + "spv.450.noRedecl.tesc", "spv.accessChain.frag", "spv.aggOps.frag", "spv.always-discard.frag", "spv.always-discard2.frag", + "spv.arbPostDepthCoverage.frag", + "spv.arbPostDepthCoverage_Error.frag", "spv.bitCast.frag", "spv.bool.vert", "spv.boolInBlock.frag", "spv.branch-return.vert", + "spv.builtInXFB.vert", "spv.conditionalDiscard.frag", + "spv.constStruct.vert", + "spv.controlFlowAttributes.frag", "spv.conversion.frag", "spv.dataOut.frag", "spv.dataOutIndirect.frag", @@ -147,13 +254,19 @@ INSTANTIATE_TEST_CASE_P( "spv.discard-dce.frag", "spv.doWhileLoop.frag", "spv.earlyReturnDiscard.frag", + "spv.extPostDepthCoverage.frag", + "spv.extPostDepthCoverage_Error.frag", "spv.flowControl.frag", "spv.forLoop.frag", "spv.forwardFun.frag", + "spv.fullyCovered.frag", "spv.functionCall.frag", + "spv.functionNestedOpaque.vert", "spv.functionSemantics.frag", + "spv.GeometryShaderPassthrough.geom", "spv.interpOps.frag", "spv.int64.frag", + "spv.intOps.vert", "spv.layoutNested.vert", "spv.length.frag", "spv.localAggregates.frag", @@ -164,16 +277,28 @@ INSTANTIATE_TEST_CASE_P( "spv.matrix2.frag", "spv.memoryQualifier.frag", "spv.merge-unreachable.frag", + "spv.multiStruct.comp", + "spv.multiStructFuncall.frag", "spv.newTexture.frag", "spv.noDeadDecorations.vert", "spv.nonSquare.vert", + "spv.nonuniform.frag", + "spv.noWorkgroup.comp", + "spv.offsets.frag", "spv.Operations.frag", - "spv.intOps.vert", + "spv.paramMemory.frag", "spv.precision.frag", + "spv.precisionNonESSamp.frag", "spv.prepost.frag", "spv.qualifiers.vert", + "spv.sample.frag", + "spv.sampleId.frag", + "spv.samplePosition.frag", + "spv.sampleMaskOverrideCoverage.frag", "spv.shaderBallot.comp", + "spv.shaderDrawParams.vert", "spv.shaderGroupVote.comp", + "spv.shaderStencilExport.frag", "spv.shiftOps.frag", "spv.simpleFunctionCall.frag", "spv.simpleMat.vert", @@ -184,10 +309,12 @@ INSTANTIATE_TEST_CASE_P( "spv.structure.frag", "spv.switch.frag", "spv.swizzle.frag", + "spv.swizzleInversion.frag", "spv.test.frag", "spv.test.vert", "spv.texture.frag", "spv.texture.vert", + "spv.textureBuffer.vert", "spv.image.frag", "spv.types.frag", "spv.uint.frag", @@ -195,6 +322,7 @@ INSTANTIATE_TEST_CASE_P( "spv.variableArrayIndex.frag", "spv.varyingArray.frag", "spv.varyingArrayIndirect.frag", + "spv.vecMatConstruct.frag", "spv.voidFunction.frag", "spv.whileLoop.frag", "spv.AofA.frag", @@ -202,24 +330,99 @@ INSTANTIATE_TEST_CASE_P( "spv.separate.frag", "spv.shortCircuit.frag", "spv.pushConstant.vert", + "spv.pushConstantAnon.vert", "spv.subpass.frag", "spv.specConstant.vert", "spv.specConstant.comp", "spv.specConstantComposite.vert", "spv.specConstantOperations.vert", + "spv.storageBuffer.vert", "spv.precise.tese", "spv.precise.tesc", + "spv.vulkan100.subgroupArithmetic.comp", + "spv.vulkan100.subgroupPartitioned.comp", + "spv.xfb.vert", + "spv.xfb2.vert", + "spv.xfb3.vert", })), FileNameAsCustomTestSuffix ); +// clang-format off +INSTANTIATE_TEST_CASE_P( + Glsl, CompileVulkan1_1ToSpirvTest, + ::testing::ValuesIn(std::vector({ + "spv.deviceGroup.frag", + "spv.drawParams.vert", + "spv.int8.frag", + "spv.vulkan110.int16.frag", + "spv.int32.frag", + "spv.explicittypes.frag", + "spv.float32.frag", + "spv.float64.frag", + "spv.multiView.frag", + "spv.subgroup.frag", + "spv.subgroup.geom", + "spv.subgroup.tesc", + "spv.subgroup.tese", + "spv.subgroup.vert", + "spv.subgroupArithmetic.comp", + "spv.subgroupBasic.comp", + "spv.subgroupBallot.comp", + "spv.subgroupClustered.comp", + "spv.subgroupClusteredNeg.comp", + "spv.subgroupPartitioned.comp", + "spv.subgroupShuffle.comp", + "spv.subgroupShuffleRelative.comp", + "spv.subgroupQuad.comp", + "spv.subgroupVote.comp", + "spv.vulkan110.storageBuffer.vert", + })), + FileNameAsCustomTestSuffix +); + +// clang-format off +INSTANTIATE_TEST_CASE_P( + Hlsl, HlslIoMap, + ::testing::ValuesIn(std::vector{ + { "spv.register.autoassign.frag", "main_ep", 5, 10, 0, 20, 30, true, false }, + { "spv.register.noautoassign.frag", "main_ep", 5, 10, 0, 15, 30, false, false }, + { "spv.register.autoassign-2.frag", "main", 5, 10, 0, 15, 30, true, true }, + { "spv.register.subpass.frag", "main", 0, 20, 0, 0, 0, true, true }, + { "spv.buffer.autoassign.frag", "main", 5, 10, 0, 15, 30, true, true }, + { "spv.ssbo.autoassign.frag", "main", 5, 10, 0, 15, 30, true, true }, + { "spv.ssboAlias.frag", "main", 0, 0, 0, 0, 83, true, false }, + { "spv.rw.autoassign.frag", "main", 5, 10, 20, 15, 30, true, true }, + { "spv.register.autoassign.rangetest.frag", "main", + glslang::TQualifier::layoutBindingEnd-2, + glslang::TQualifier::layoutBindingEnd+5, + 20, 30, true, false }, + }), + FileNameAsCustomTestSuffixIoMap +); + +// clang-format off +INSTANTIATE_TEST_CASE_P( + Hlsl, GlslIoMap, + ::testing::ValuesIn(std::vector{ + { "spv.glsl.register.autoassign.frag", "main", 5, 10, 0, 20, 30, true, false }, + { "spv.glsl.register.noautoassign.frag", "main", 5, 10, 0, 15, 30, false, false }, + }), + FileNameAsCustomTestSuffixIoMap +); + // clang-format off INSTANTIATE_TEST_CASE_P( Glsl, CompileOpenGLToSpirvTest, ::testing::ValuesIn(std::vector({ + "spv.460.frag", + "spv.460.vert", + "spv.460.comp", "spv.atomic.comp", "spv.glFragColor.frag", + "spv.rankShift.comp", "spv.specConst.vert", + "spv.OVR_multiview.vert", })), FileNameAsCustomTestSuffix ); @@ -253,6 +456,49 @@ INSTANTIATE_TEST_CASE_P( })), FileNameAsCustomTestSuffix ); + +#ifdef AMD_EXTENSIONS +INSTANTIATE_TEST_CASE_P( + Glsl, CompileVulkanToSpirvTestAMD, + ::testing::ValuesIn(std::vector({ + "spv.float16.frag", + "spv.float16Fetch.frag", + "spv.imageLoadStoreLod.frag", + "spv.int16.frag", + "spv.int16.amd.frag", + "spv.shaderBallotAMD.comp", + "spv.shaderFragMaskAMD.frag", + "spv.textureGatherBiasLod.frag", + })), + FileNameAsCustomTestSuffix +); +#endif + +#ifdef NV_EXTENSIONS +INSTANTIATE_TEST_CASE_P( + Glsl, CompileVulkanToSpirvTestNV, + ::testing::ValuesIn(std::vector({ + "spv.sampleMaskOverrideCoverage.frag", + "spv.GeometryShaderPassthrough.geom", + "spv.viewportArray2.vert", + "spv.viewportArray2.tesc", + "spv.stereoViewRendering.vert", + "spv.stereoViewRendering.tesc", + "spv.multiviewPerViewAttributes.vert", + "spv.multiviewPerViewAttributes.tesc", + "spv.atomicInt64.comp", +})), +FileNameAsCustomTestSuffix +); +#endif + +INSTANTIATE_TEST_CASE_P( + Glsl, CompileUpgradeTextureToSampledTextureAndDropSamplersTest, + ::testing::ValuesIn(std::vector({ + "spv.texture.sampler.transform.frag", + })), + FileNameAsCustomTestSuffix +); // clang-format on } // anonymous namespace diff --git a/Externals/glslang/gtests/TestFixture.cpp b/Externals/glslang/gtests/TestFixture.cpp index f170f368db..77bada5f7d 100644 --- a/Externals/glslang/gtests/TestFixture.cpp +++ b/Externals/glslang/gtests/TestFixture.cpp @@ -74,7 +74,7 @@ EShMessages DeriveOptions(Source source, Semantics semantics, Target target) case Source::GLSL: break; case Source::HLSL: - result = EShMsgReadHlsl; + result = static_cast(result | EShMsgReadHlsl); break; } @@ -84,9 +84,11 @@ EShMessages DeriveOptions(Source source, Semantics semantics, Target target) break; case Target::Spv: result = static_cast(result | EShMsgSpvRules); + result = static_cast(result | EShMsgKeepUncalled); break; case Target::BothASTAndSpv: result = static_cast(result | EShMsgSpvRules | EShMsgAST); + result = static_cast(result | EShMsgKeepUncalled); break; }; @@ -98,6 +100,8 @@ EShMessages DeriveOptions(Source source, Semantics semantics, Target target) break; } + result = static_cast(result | EShMsgHlslLegalization); + return result; } @@ -116,6 +120,32 @@ std::pair ReadFile(const std::string& path) return std::make_pair(false, ""); } +std::pair > ReadSpvBinaryFile(const std::string& path) +{ + std::ifstream fstream(path, std::fstream::in | std::fstream::binary); + + if (!fstream) + return std::make_pair(false, std::vector()); + + std::vector contents; + + // Reserve space (for efficiency, not for correctness) + fstream.seekg(0, fstream.end); + contents.reserve(size_t(fstream.tellg()) / sizeof(std::uint32_t)); + fstream.seekg(0, fstream.beg); + + // There is no istream iterator traversing by uint32_t, so we must loop. + while (!fstream.eof()) { + std::uint32_t inWord; + fstream.read((char *)&inWord, sizeof(inWord)); + + if (!fstream.eof()) + contents.push_back(inWord); + } + + return std::make_pair(true, contents); // hopefully, c++11 move semantics optimizes the copy away. +} + bool WriteFile(const std::string& path, const std::string& contents) { std::ofstream fstream(path, std::ios::out); diff --git a/Externals/glslang/gtests/TestFixture.h b/Externals/glslang/gtests/TestFixture.h index 8dffb8050f..a58978d339 100644 --- a/Externals/glslang/gtests/TestFixture.h +++ b/Externals/glslang/gtests/TestFixture.h @@ -35,31 +35,25 @@ #ifndef GLSLANG_GTESTS_TEST_FIXTURE_H #define GLSLANG_GTESTS_TEST_FIXTURE_H -#include +#include #include #include #include #include +#include #include #include "SPIRV/GlslangToSpv.h" #include "SPIRV/disassemble.h" #include "SPIRV/doc.h" +#include "SPIRV/SPVRemapper.h" #include "StandAlone/ResourceLimits.h" #include "glslang/Public/ShaderLang.h" #include "Initializer.h" #include "Settings.h" -// We need CMake to provide us the absolute path to the directory containing -// test files, so we are certain to find those files no matter where the test -// harness binary is generated. This provides out-of-source build capability. -#ifndef GLSLANG_TEST_DIRECTORY -#error \ - "GLSLANG_TEST_DIRECTORY needs to be defined for gtest to locate test files." -#endif - namespace glslangtest { // This function is used to provide custom test name suffixes based on the @@ -76,7 +70,7 @@ enum class Source { // Enum for shader compilation semantics. enum class Semantics { OpenGL, - Vulkan, + Vulkan }; // Enum for compilation target. @@ -93,6 +87,7 @@ EShMessages DeriveOptions(Source, Semantics, Target); // Reads the content of the file at the given |path|. On success, returns true // and the contents; otherwise, returns false and an empty string. std::pair ReadFile(const std::string& path); +std::pair > ReadSpvBinaryFile(const std::string& path); // Writes the given |contents| into the file at the given |path|. Returns true // on successful output. @@ -128,6 +123,16 @@ public: ASSERT_TRUE(fileReadOk) << "Cannot open " << tag << " file: " << path; } + // Tries to load the contents from the file at the given |path|. On success, + // writes the contents into |contents|. On failure, errors out. + void tryLoadSpvFile(const std::string& path, const std::string& tag, + std::vector& contents) + { + bool fileReadOk; + std::tie(fileReadOk, contents) = ReadSpvBinaryFile(path); + ASSERT_TRUE(fileReadOk) << "Cannot open " << tag << " file: " << path; + } + // Checks the equality of |expected| and |real|. If they are not equal, // write |real| to the given file named as |fname| if update mode is on. void checkEqAndUpdateIfRequested(const std::string& expected, @@ -179,8 +184,6 @@ public: shader->setStringsWithLengths(&shaderStrings, &shaderLengths, 1); if (!entryPointName.empty()) shader->setEntryPoint(entryPointName.c_str()); - // Reinitialize glslang if the semantics change. - GlobalTestSettings.initializer->acquire(controls); return shader->parse( (resources ? resources : &glslang::DefaultTBuiltInResource), defaultVersion, isForwardCompatible, controls); @@ -193,11 +196,41 @@ public: // the result and returns disassembly text. GlslangResult compileAndLink( const std::string shaderName, const std::string& code, - const std::string& entryPointName, EShMessages controls) + const std::string& entryPointName, EShMessages controls, + glslang::EShTargetClientVersion clientTargetVersion, + bool flattenUniformArrays = false, + EShTextureSamplerTransformMode texSampTransMode = EShTexSampTransKeep, + bool enableOptimizer = false, + bool automap = true) { - const EShLanguage kind = GetShaderStage(GetSuffix(shaderName)); + const EShLanguage stage = GetShaderStage(GetSuffix(shaderName)); + + glslang::TShader shader(stage); + if (automap) { + shader.setAutoMapLocations(true); + shader.setAutoMapBindings(true); + } + shader.setTextureSamplerTransformMode(texSampTransMode); + shader.setFlattenUniformArrays(flattenUniformArrays); + + if (controls & EShMsgSpvRules) { + if (controls & EShMsgVulkanRules) { + shader.setEnvInput((controls & EShMsgReadHlsl) ? glslang::EShSourceHlsl + : glslang::EShSourceGlsl, + stage, glslang::EShClientVulkan, 100); + shader.setEnvClient(glslang::EShClientVulkan, clientTargetVersion); + shader.setEnvTarget(glslang::EShTargetSpv, + clientTargetVersion == glslang::EShTargetVulkan_1_1 ? glslang::EShTargetSpv_1_3 + : glslang::EShTargetSpv_1_0); + } else { + shader.setEnvInput((controls & EShMsgReadHlsl) ? glslang::EShSourceHlsl + : glslang::EShSourceGlsl, + stage, glslang::EShClientOpenGL, 100); + shader.setEnvClient(glslang::EShClientOpenGL, clientTargetVersion); + shader.setEnvTarget(glslang::EshTargetSpv, glslang::EShTargetSpv_1_0); + } + } - glslang::TShader shader(kind); bool success = compile(&shader, code, entryPointName, controls); glslang::TProgram program; @@ -208,7 +241,64 @@ public: if (success && (controls & EShMsgSpvRules)) { std::vector spirv_binary; - glslang::GlslangToSpv(*program.getIntermediate(kind), + glslang::SpvOptions options; + options.disableOptimizer = !enableOptimizer; + glslang::GlslangToSpv(*program.getIntermediate(stage), + spirv_binary, &logger, &options); + + std::ostringstream disassembly_stream; + spv::Parameterize(); + spv::Disassemble(disassembly_stream, spirv_binary); + return {{{shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},}, + program.getInfoLog(), program.getInfoDebugLog(), + logger.getAllMessages(), disassembly_stream.str()}; + } else { + return {{{shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},}, + program.getInfoLog(), program.getInfoDebugLog(), "", ""}; + } + } + + // Compiles and links the given source |code| of the given shader + // |stage| into the target under the semantics specified via |controls|. + // Returns a GlslangResult instance containing all the information generated + // during the process. If the target includes SPIR-V, also disassembles + // the result and returns disassembly text. + GlslangResult compileLinkIoMap( + const std::string shaderName, const std::string& code, + const std::string& entryPointName, EShMessages controls, + int baseSamplerBinding, + int baseTextureBinding, + int baseImageBinding, + int baseUboBinding, + int baseSsboBinding, + bool autoMapBindings, + bool flattenUniformArrays) + { + const EShLanguage stage = GetShaderStage(GetSuffix(shaderName)); + + glslang::TShader shader(stage); + shader.setShiftSamplerBinding(baseSamplerBinding); + shader.setShiftTextureBinding(baseTextureBinding); + shader.setShiftImageBinding(baseImageBinding); + shader.setShiftUboBinding(baseUboBinding); + shader.setShiftSsboBinding(baseSsboBinding); + shader.setAutoMapBindings(autoMapBindings); + shader.setAutoMapLocations(true); + shader.setFlattenUniformArrays(flattenUniformArrays); + + bool success = compile(&shader, code, entryPointName, controls); + + glslang::TProgram program; + program.addShader(&shader); + + success &= program.link(controls); + success &= program.mapIO(); + + spv::SpvBuildLogger logger; + + if (success && (controls & EShMsgSpvRules)) { + std::vector spirv_binary; + glslang::GlslangToSpv(*program.getIntermediate(stage), spirv_binary, &logger); std::ostringstream disassembly_stream; @@ -223,6 +313,71 @@ public: } } + // This is like compileAndLink but with remapping of the SPV binary + // through spirvbin_t::remap(). While technically this could be merged + // with compileAndLink() above (with the remap step optionally being a no-op) + // it is given separately here for ease of future extraction. + GlslangResult compileLinkRemap( + const std::string shaderName, const std::string& code, + const std::string& entryPointName, EShMessages controls, + const unsigned int remapOptions = spv::spirvbin_t::NONE) + { + const EShLanguage stage = GetShaderStage(GetSuffix(shaderName)); + + glslang::TShader shader(stage); + shader.setAutoMapBindings(true); + shader.setAutoMapLocations(true); + + bool success = compile(&shader, code, entryPointName, controls); + + glslang::TProgram program; + program.addShader(&shader); + success &= program.link(controls); + + spv::SpvBuildLogger logger; + + if (success && (controls & EShMsgSpvRules)) { + std::vector spirv_binary; + glslang::GlslangToSpv(*program.getIntermediate(stage), + spirv_binary, &logger); + + spv::spirvbin_t(0 /*verbosity*/).remap(spirv_binary, remapOptions); + + std::ostringstream disassembly_stream; + spv::Parameterize(); + spv::Disassemble(disassembly_stream, spirv_binary); + return {{{shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},}, + program.getInfoLog(), program.getInfoDebugLog(), + logger.getAllMessages(), disassembly_stream.str()}; + } else { + return {{{shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},}, + program.getInfoLog(), program.getInfoDebugLog(), "", ""}; + } + } + + // remap the binary in 'code' with the options in remapOptions + GlslangResult remap( + const std::string shaderName, const std::vector& code, + EShMessages controls, + const unsigned int remapOptions = spv::spirvbin_t::NONE) + { + if ((controls & EShMsgSpvRules)) { + std::vector spirv_binary(code); // scratch copy + + spv::spirvbin_t(0 /*verbosity*/).remap(spirv_binary, remapOptions); + + std::ostringstream disassembly_stream; + spv::Parameterize(); + spv::Disassemble(disassembly_stream, spirv_binary); + + return {{{shaderName, "", ""},}, + "", "", + "", disassembly_stream.str()}; + } else { + return {{{shaderName, "", ""},}, "", "", "", ""}; + } + } + void outputResultToStream(std::ostringstream* stream, const GlslangResult& result, EShMessages controls) @@ -252,8 +407,41 @@ public: const std::string& testName, Source source, Semantics semantics, + glslang::EShTargetClientVersion clientTargetVersion, Target target, - const std::string& entryPointName="") + bool automap = true, + const std::string& entryPointName="", + const std::string& baseDir="/baseResults/", + const bool enableOptimizer = false) + { + const std::string inputFname = testDir + "/" + testName; + const std::string expectedOutputFname = + testDir + baseDir + testName + ".out"; + std::string input, expectedOutput; + + tryLoadFile(inputFname, "input", &input); + tryLoadFile(expectedOutputFname, "expected output", &expectedOutput); + + EShMessages controls = DeriveOptions(source, semantics, target); + if (enableOptimizer) + controls = static_cast(controls & ~EShMsgHlslLegalization); + GlslangResult result = compileAndLink(testName, input, entryPointName, controls, clientTargetVersion, false, + EShTexSampTransKeep, enableOptimizer, automap); + + // Generate the hybrid output in the way of glslangValidator. + std::ostringstream stream; + outputResultToStream(&stream, result, controls); + + checkEqAndUpdateIfRequested(expectedOutput, stream.str(), + expectedOutputFname); + } + + void loadFileCompileFlattenUniformsAndCheck(const std::string& testDir, + const std::string& testName, + Source source, + Semantics semantics, + Target target, + const std::string& entryPointName="") { const std::string inputFname = testDir + "/" + testName; const std::string expectedOutputFname = @@ -264,7 +452,99 @@ public: tryLoadFile(expectedOutputFname, "expected output", &expectedOutput); const EShMessages controls = DeriveOptions(source, semantics, target); - GlslangResult result = compileAndLink(testName, input, entryPointName, controls); + GlslangResult result = compileAndLink(testName, input, entryPointName, controls, + glslang::EShTargetVulkan_1_0, true); + + // Generate the hybrid output in the way of glslangValidator. + std::ostringstream stream; + outputResultToStream(&stream, result, controls); + + checkEqAndUpdateIfRequested(expectedOutput, stream.str(), + expectedOutputFname); + } + + void loadFileCompileIoMapAndCheck(const std::string& testDir, + const std::string& testName, + Source source, + Semantics semantics, + Target target, + const std::string& entryPointName, + int baseSamplerBinding, + int baseTextureBinding, + int baseImageBinding, + int baseUboBinding, + int baseSsboBinding, + bool autoMapBindings, + bool flattenUniformArrays) + { + const std::string inputFname = testDir + "/" + testName; + const std::string expectedOutputFname = + testDir + "/baseResults/" + testName + ".out"; + std::string input, expectedOutput; + + tryLoadFile(inputFname, "input", &input); + tryLoadFile(expectedOutputFname, "expected output", &expectedOutput); + + const EShMessages controls = DeriveOptions(source, semantics, target); + GlslangResult result = compileLinkIoMap(testName, input, entryPointName, controls, + baseSamplerBinding, baseTextureBinding, baseImageBinding, + baseUboBinding, baseSsboBinding, + autoMapBindings, + flattenUniformArrays); + + // Generate the hybrid output in the way of glslangValidator. + std::ostringstream stream; + outputResultToStream(&stream, result, controls); + + checkEqAndUpdateIfRequested(expectedOutput, stream.str(), + expectedOutputFname); + } + + void loadFileCompileRemapAndCheck(const std::string& testDir, + const std::string& testName, + Source source, + Semantics semantics, + Target target, + const std::string& entryPointName="", + const unsigned int remapOptions = spv::spirvbin_t::NONE) + { + const std::string inputFname = testDir + "/" + testName; + const std::string expectedOutputFname = + testDir + "/baseResults/" + testName + ".out"; + std::string input, expectedOutput; + + tryLoadFile(inputFname, "input", &input); + tryLoadFile(expectedOutputFname, "expected output", &expectedOutput); + + const EShMessages controls = DeriveOptions(source, semantics, target); + GlslangResult result = compileLinkRemap(testName, input, entryPointName, controls, remapOptions); + + // Generate the hybrid output in the way of glslangValidator. + std::ostringstream stream; + outputResultToStream(&stream, result, controls); + + checkEqAndUpdateIfRequested(expectedOutput, stream.str(), + expectedOutputFname); + } + + void loadFileRemapAndCheck(const std::string& testDir, + const std::string& testName, + Source source, + Semantics semantics, + Target target, + const unsigned int remapOptions = spv::spirvbin_t::NONE) + { + const std::string inputFname = testDir + "/" + testName; + const std::string expectedOutputFname = + testDir + "/baseResults/" + testName + ".out"; + std::vector input; + std::string expectedOutput; + + tryLoadSpvFile(inputFname, "input", input); + tryLoadFile(expectedOutputFname, "expected output", &expectedOutput); + + const EShMessages controls = DeriveOptions(source, semantics, target); + GlslangResult result = remap(testName, input, controls, remapOptions); // Generate the hybrid output in the way of glslangValidator. std::ostringstream stream; @@ -286,7 +566,7 @@ public: glslang::TShader shader(EShLangVertex); shader.setStringsWithLengths(&shaderStrings, &shaderLengths, 1); std::string ppShader; - glslang::TShader::ForbidInclude includer; + glslang::TShader::ForbidIncluder includer; const bool success = shader.preprocess( &glslang::DefaultTBuiltInResource, defaultVersion, defaultProfile, forceVersionProfile, isForwardCompatible, (EShMessages)(EShMsgOnlyPreprocessor | EShMsgCascadingErrors), @@ -327,6 +607,33 @@ public: expectedErrorFname); } + void loadCompileUpgradeTextureToSampledTextureAndDropSamplersAndCheck(const std::string& testDir, + const std::string& testName, + Source source, + Semantics semantics, + Target target, + const std::string& entryPointName = "") + { + const std::string inputFname = testDir + "/" + testName; + const std::string expectedOutputFname = testDir + "/baseResults/" + testName + ".out"; + std::string input, expectedOutput; + + tryLoadFile(inputFname, "input", &input); + tryLoadFile(expectedOutputFname, "expected output", &expectedOutput); + + const EShMessages controls = DeriveOptions(source, semantics, target); + GlslangResult result = compileAndLink(testName, input, entryPointName, controls, + glslang::EShTargetVulkan_1_0, false, + EShTexSampTransUpgradeTextureRemoveSampler); + + // Generate the hybrid output in the way of glslangValidator. + std::ostringstream stream; + outputResultToStream(&stream, result, controls); + + checkEqAndUpdateIfRequested(expectedOutput, stream.str(), + expectedOutputFname); + } + private: const int defaultVersion; const EProfile defaultProfile; diff --git a/Externals/glslang/gtests/main.cpp b/Externals/glslang/gtests/main.cpp index b9806aa255..9cd06d1d4f 100644 --- a/Externals/glslang/gtests/main.cpp +++ b/Externals/glslang/gtests/main.cpp @@ -33,6 +33,7 @@ // POSSIBILITY OF SUCH DAMAGE. #include +#include #include @@ -49,9 +50,24 @@ int main(int argc, char** argv) glslangtest::GlobalTestSettings.initializer = initializer.get(); for (int i = 1; i < argc; ++i) { - if (!strncmp("--update-mode", argv[i], 13)) { + if (std::string("--update-mode") == argv[i]) { glslangtest::GlobalTestSettings.updateMode = true; - break; + } + if (std::string("--test-root") == argv[i]) { + // Allow the user set the test root directory. This is useful + // for testing with files from another source tree. + if (i + 1 < argc) { + glslangtest::GlobalTestSettings.testRoot = argv[i + 1]; + i++; + } else { + printf("error: --test-root requires an argument\n"); + return 1; + } + } + if (std::string("--help") == argv[i]) { + printf("\nExtra options:\n\n"); + printf(" --update-mode\n Update the golden results for the tests.\n"); + printf(" --test-root \n Specify the test root directory (useful for testing with\n files from another source tree).\n"); } } diff --git a/Externals/glslang/hlsl/CMakeLists.txt b/Externals/glslang/hlsl/CMakeLists.txt index c7537e2712..6d1d8e6ae5 100755 --- a/Externals/glslang/hlsl/CMakeLists.txt +++ b/Externals/glslang/hlsl/CMakeLists.txt @@ -1,4 +1,5 @@ set(SOURCES + hlslAttributes.cpp hlslParseHelper.cpp hlslScanContext.cpp hlslOpMap.cpp @@ -7,6 +8,7 @@ set(SOURCES hlslParseables.cpp) set(HEADERS + hlslAttributes.h hlslParseHelper.h hlslTokens.h hlslScanContext.h @@ -15,12 +17,25 @@ set(HEADERS hlslGrammar.h hlslParseables.h) -add_library(HLSL STATIC ${SOURCES} ${HEADERS}) +add_library(HLSL ${LIB_TYPE} ${SOURCES} ${HEADERS}) set_property(TARGET HLSL PROPERTY FOLDER hlsl) +set_property(TARGET HLSL PROPERTY POSITION_INDEPENDENT_CODE ON) + +if(WIN32 AND BUILD_SHARED_LIBS) + set_target_properties(HLSL PROPERTIES PREFIX "") +endif() if(WIN32) source_group("Source" FILES ${SOURCES} ${HEADERS}) endif(WIN32) -install(TARGETS HLSL - ARCHIVE DESTINATION lib) +if(ENABLE_GLSLANG_INSTALL) + if(BUILD_SHARED_LIBS) + install(TARGETS HLSL + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + else() + install(TARGETS HLSL + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif() +endif(ENABLE_GLSLANG_INSTALL) diff --git a/Externals/glslang/hlsl/hlslAttributes.cpp b/Externals/glslang/hlsl/hlslAttributes.cpp new file mode 100644 index 0000000000..261cec346f --- /dev/null +++ b/Externals/glslang/hlsl/hlslAttributes.cpp @@ -0,0 +1,106 @@ +// +// Copyright (C) 2016 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 Google, Inc., 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. +// + +#include "hlslAttributes.h" +#include "hlslParseHelper.h" + +namespace glslang { + // Map the given string to an attribute enum from TAttributeType, + // or EatNone if invalid. + TAttributeType HlslParseContext::attributeFromName(const TString& nameSpace, const TString& name) const + { + // handle names within a namespace + + if (nameSpace == "vk") { + if (name == "input_attachment_index") + return EatInputAttachment; + else if (name == "location") + return EatLocation; + else if (name == "binding") + return EatBinding; + else if (name == "global_cbuffer_binding") + return EatGlobalBinding; + else if (name == "builtin") + return EatBuiltIn; + else if (name == "constant_id") + return EatConstantId; + else if (name == "push_constant") + return EatPushConstant; + } else if (nameSpace.size() > 0) + return EatNone; + + // handle names with no namespace + + if (name == "allow_uav_condition") + return EatAllow_uav_condition; + else if (name == "branch") + return EatBranch; + else if (name == "call") + return EatCall; + else if (name == "domain") + return EatDomain; + else if (name == "earlydepthstencil") + return EatEarlyDepthStencil; + else if (name == "fastopt") + return EatFastOpt; + else if (name == "flatten") + return EatFlatten; + else if (name == "forcecase") + return EatForceCase; + else if (name == "instance") + return EatInstance; + else if (name == "maxtessfactor") + return EatMaxTessFactor; + else if (name == "maxvertexcount") + return EatMaxVertexCount; + else if (name == "numthreads") + return EatNumThreads; + else if (name == "outputcontrolpoints") + return EatOutputControlPoints; + else if (name == "outputtopology") + return EatOutputTopology; + else if (name == "partitioning") + return EatPartitioning; + else if (name == "patchconstantfunc") + return EatPatchConstantFunc; + else if (name == "unroll") + return EatUnroll; + else if (name == "loop") + return EatLoop; + else + return EatNone; + } + +} // end namespace glslang diff --git a/Externals/glslang/hlsl/hlslAttributes.h b/Externals/glslang/hlsl/hlslAttributes.h new file mode 100644 index 0000000000..b1cc0372e5 --- /dev/null +++ b/Externals/glslang/hlsl/hlslAttributes.h @@ -0,0 +1,59 @@ +// +// Copyright (C) 2016 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 Google, Inc., 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 HLSLATTRIBUTES_H_ +#define HLSLATTRIBUTES_H_ + +#include +#include + +#include "../glslang/MachineIndependent/attribute.h" +#include "../glslang/MachineIndependent/SymbolTable.h" +#include "hlslScanContext.h" + +namespace glslang { + + class TFunctionDeclarator { + public: + TFunctionDeclarator() : function(nullptr), body(nullptr) { } + TSourceLoc loc; + TFunction* function; + TAttributes attributes; + TVector* body; + }; + +} // end namespace glslang + +#endif // HLSLATTRIBUTES_H_ diff --git a/Externals/glslang/hlsl/hlslGrammar.cpp b/Externals/glslang/hlsl/hlslGrammar.cpp index c149b1c251..cb05877917 100755 --- a/Externals/glslang/hlsl/hlslGrammar.cpp +++ b/Externals/glslang/hlsl/hlslGrammar.cpp @@ -1,12 +1,12 @@ // -//Copyright (C) 2016 Google, Inc. -//Copyright (C) 2016 LunarG, Inc. +// Copyright (C) 2016 Google, Inc. +// Copyright (C) 2016 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,18 +20,18 @@ // 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. +// 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. // // @@ -53,6 +53,7 @@ #include "hlslTokens.h" #include "hlslGrammar.h" +#include "hlslAttributes.h" namespace glslang { @@ -74,44 +75,103 @@ void HlslGrammar::unimplemented(const char* error) parseContext.error(token.loc, "Unimplemented", error, ""); } +// IDENTIFIER +// THIS +// type that can be used as IDENTIFIER +// // Only process the next token if it is an identifier. // Return true if it was an identifier. bool HlslGrammar::acceptIdentifier(HlslToken& idToken) { + // IDENTIFIER if (peekTokenClass(EHTokIdentifier)) { idToken = token; advanceToken(); return true; } - return false; + // THIS + // -> maps to the IDENTIFIER spelled with the internal special name for 'this' + if (peekTokenClass(EHTokThis)) { + idToken = token; + advanceToken(); + idToken.tokenClass = EHTokIdentifier; + idToken.string = NewPoolTString(intermediate.implicitThisName); + return true; + } + + // type that can be used as IDENTIFIER + + // Even though "sample", "bool", "float", etc keywords (for types, interpolation modifiers), + // they ARE still accepted as identifiers. This is not a dense space: e.g, "void" is not a + // valid identifier, nor is "linear". This code special cases the known instances of this, so + // e.g, "int sample;" or "float float;" is accepted. Other cases can be added here if needed. + + const char* idString = getTypeString(peek()); + if (idString == nullptr) + return false; + + token.string = NewPoolTString(idString); + token.tokenClass = EHTokIdentifier; + idToken = token; + typeIdentifiers = true; + + advanceToken(); + + return true; } // compilationUnit -// : list of externalDeclaration +// : declaration_list EOF // bool HlslGrammar::acceptCompilationUnit() { TIntermNode* unitNode = nullptr; - while (! peekTokenClass(EHTokNone)) { - // externalDeclaration - TIntermNode* declarationNode; - if (! acceptDeclaration(declarationNode)) - return false; + if (! acceptDeclarationList(unitNode)) + return false; - // hook it up - unitNode = intermediate.growAggregate(unitNode, declarationNode); - } + if (! peekTokenClass(EHTokNone)) + return false; // set root of AST + if (unitNode && !unitNode->getAsAggregate()) + unitNode = intermediate.growAggregate(nullptr, unitNode); intermediate.setTreeRoot(unitNode); return true; } +// Recognize the following, but with the extra condition that it can be +// successfully terminated by EOF or '}'. +// +// declaration_list +// : list of declaration_or_semicolon followed by EOF or RIGHT_BRACE +// +// declaration_or_semicolon +// : declaration +// : SEMICOLON +// +bool HlslGrammar::acceptDeclarationList(TIntermNode*& nodeList) +{ + do { + // HLSL allows extra semicolons between global declarations + do { } while (acceptTokenClass(EHTokSemicolon)); + + // EOF or RIGHT_BRACE + if (peekTokenClass(EHTokNone) || peekTokenClass(EHTokRightBrace)) + return true; + + // declaration + if (! acceptDeclaration(nodeList)) + return false; + } while (true); + + return true; +} + // sampler_state -// : LEFT_BRACE [sampler_state_assignment ... ] RIGHT_BRACE +// : LEFT_BRACE [sampler_state_assignment ... ] RIGHT_BRACE // // sampler_state_assignment // : sampler_state_identifier EQUAL value SEMICOLON @@ -136,7 +196,7 @@ bool HlslGrammar::acceptSamplerState() return true; parseContext.warn(token.loc, "unimplemented", "immediate sampler state", ""); - + do { // read state name HlslToken state; @@ -215,7 +275,7 @@ bool HlslGrammar::acceptSamplerDeclarationDX9(TType& /*type*/) { if (! acceptTokenClass(EHTokSampler)) return false; - + // TODO: remove this when DX9 style declarations are implemented. unimplemented("Direct3D 9 sampler declaration"); @@ -234,10 +294,14 @@ bool HlslGrammar::acceptSamplerDeclarationDX9(TType& /*type*/) return false; } - // declaration +// : attributes attributed_declaration +// | NAMESPACE IDENTIFIER LEFT_BRACE declaration_list RIGHT_BRACE +// +// attributed_declaration // : sampler_declaration_dx9 post_decls SEMICOLON -// | fully_specified_type declarator_list SEMICOLON +// | fully_specified_type // for cbuffer/tbuffer +// | fully_specified_type declarator_list SEMICOLON // for non cbuffer/tbuffer // | fully_specified_type identifier function_parameters post_decls compound_statement // function definition // | fully_specified_type identifier sampler_state post_decls compound_statement // sampler definition // | typedef declaration @@ -255,74 +319,146 @@ bool HlslGrammar::acceptSamplerDeclarationDX9(TType& /*type*/) // as above. (The 'identifier' in the first item in init_declarator list is the // same as 'identifier' for function declarations.) // -// 'node' could get populated if the declaration creates code, like an initializer -// or a function body. +// This can generate more than one subtree, one per initializer or a function body. +// All initializer subtrees are put in their own aggregate node, making one top-level +// node for all the initializers. Each function created is a top-level node to grow +// into the passed-in nodeList. // -bool HlslGrammar::acceptDeclaration(TIntermNode*& node) +// If 'nodeList' is passed in as non-null, it must an aggregate to extend for +// each top-level node the declaration creates. Otherwise, if only one top-level +// node in generated here, that is want is returned in nodeList. +// +bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList) { - node = nullptr; - bool list = false; + // NAMESPACE IDENTIFIER LEFT_BRACE declaration_list RIGHT_BRACE + if (acceptTokenClass(EHTokNamespace)) { + HlslToken namespaceToken; + if (!acceptIdentifier(namespaceToken)) { + expected("namespace name"); + return false; + } + parseContext.pushNamespace(*namespaceToken.string); + if (!acceptTokenClass(EHTokLeftBrace)) { + expected("{"); + return false; + } + if (!acceptDeclarationList(nodeList)) { + expected("declaration list"); + return false; + } + if (!acceptTokenClass(EHTokRightBrace)) { + expected("}"); + return false; + } + parseContext.popNamespace(); + return true; + } + + bool declarator_list = false; // true when processing comma separation + + // attributes + TFunctionDeclarator declarator; + acceptAttributes(declarator.attributes); // typedef bool typedefDecl = acceptTokenClass(EHTokTypedef); - TType type; + TType declaredType; // DX9 sampler declaration use a different syntax - if (acceptSamplerDeclarationDX9(type)) - return true; + // DX9 shaders need to run through HLSL compiler (fxc) via a back compat mode, it isn't going to + // be possible to simultaneously compile D3D10+ style shaders and DX9 shaders. If we want to compile DX9 + // HLSL shaders, this will have to be a master level switch + // As such, the sampler keyword in D3D10+ turns into an automatic sampler type, and is commonly used + // For that reason, this line is commented out + // if (acceptSamplerDeclarationDX9(declaredType)) + // return true; + bool forbidDeclarators = (peekTokenClass(EHTokCBuffer) || peekTokenClass(EHTokTBuffer)); // fully_specified_type - if (! acceptFullySpecifiedType(type)) + if (! acceptFullySpecifiedType(declaredType, nodeList, declarator.attributes, forbidDeclarators)) return false; - if (type.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel()) { - if (type.getBasicType() == EbtSampler) { - // Sampler/textures are uniform by default (if no explicit qualifier is present) in - // HLSL. This line silently converts samplers *explicitly* declared static to uniform, - // which is incorrect but harmless. - type.getQualifier().storage = EvqUniform; - } else { - type.getQualifier().storage = EvqGlobal; - } - } + // cbuffer and tbuffer end with the closing '}'. + // No semicolon is included. + if (forbidDeclarators) + return true; - // identifier + // declarator_list + // : declarator + // : identifier HlslToken idToken; + TIntermAggregate* initializers = nullptr; while (acceptIdentifier(idToken)) { - // function_parameters - TFunction* function = new TFunction(idToken.string, type); - if (acceptFunctionParameters(*function)) { + TString *fullName = idToken.string; + if (parseContext.symbolTable.atGlobalLevel()) + parseContext.getFullNamespaceName(fullName); + if (peekTokenClass(EHTokLeftParen)) { + // looks like function parameters + + // merge in the attributes into the return type + parseContext.transferTypeAttributes(token.loc, declarator.attributes, declaredType, true); + + // Potentially rename shader entry point function. No-op most of the time. + parseContext.renameShaderFunction(fullName); + + // function_parameters + declarator.function = new TFunction(fullName, declaredType); + if (!acceptFunctionParameters(*declarator.function)) { + expected("function parameter list"); + return false; + } + // post_decls - acceptPostDecls(type); + acceptPostDecls(declarator.function->getWritableType().getQualifier()); // compound_statement (function body definition) or just a prototype? + declarator.loc = token.loc; if (peekTokenClass(EHTokLeftBrace)) { - if (list) + if (declarator_list) parseContext.error(idToken.loc, "function body can't be in a declarator list", "{", ""); if (typedefDecl) parseContext.error(idToken.loc, "function body can't be in a typedef", "{", ""); - return acceptFunctionDefinition(*function, node); + return acceptFunctionDefinition(declarator, nodeList, nullptr); } else { if (typedefDecl) parseContext.error(idToken.loc, "function typedefs not implemented", "{", ""); - parseContext.handleFunctionDeclarator(idToken.loc, *function, true); + parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, true); } } else { - // a variable declaration + // A variable declaration. - // array_specifier + // merge in the attributes, the first time around, into the shared type + if (! declarator_list) + parseContext.transferTypeAttributes(token.loc, declarator.attributes, declaredType); + + // Fix the storage qualifier if it's a global. + if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel()) + declaredType.getQualifier().storage = EvqUniform; + + // recognize array_specifier TArraySizes* arraySizes = nullptr; acceptArraySpecifier(arraySizes); + // We can handle multiple variables per type declaration, so + // the number of types can expand when arrayness is different. + TType variableType; + variableType.shallowCopy(declaredType); + + // In the most general case, arrayness is potentially coming both from the + // declared type and from the variable: "int[] a[];" or just one or the other. + // Merge it all to the variableType, so all arrayness is part of the variableType. + variableType.transferArraySizes(arraySizes); + variableType.copyArrayInnerSizes(declaredType.getArraySizes()); + // samplers accept immediate sampler state - if (type.getBasicType() == EbtSampler) { + if (variableType.getBasicType() == EbtSampler) { if (! acceptSamplerState()) return false; } // post_decls - acceptPostDecls(type); + acceptPostDecls(variableType.getQualifier()); // EQUAL assignment_expression TIntermTyped* expressionNode = nullptr; @@ -335,35 +471,62 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node) } } - if (typedefDecl) - parseContext.declareTypedef(idToken.loc, *idToken.string, type, arraySizes); - else { - // Declare the variable and add any initializer code to the AST. - // The top-level node is always made into an aggregate, as that's - // historically how the AST has been. - node = intermediate.growAggregate(node, - parseContext.declareVariable(idToken.loc, *idToken.string, type, - arraySizes, expressionNode), - idToken.loc); + // TODO: things scoped within an annotation need their own name space; + // TODO: strings are not yet handled. + if (variableType.getBasicType() != EbtString && parseContext.getAnnotationNestingLevel() == 0) { + if (typedefDecl) + parseContext.declareTypedef(idToken.loc, *fullName, variableType); + else if (variableType.getBasicType() == EbtBlock) { + if (expressionNode) + parseContext.error(idToken.loc, "buffer aliasing not yet supported", "block initializer", ""); + parseContext.declareBlock(idToken.loc, variableType, fullName); + parseContext.declareStructBufferCounter(idToken.loc, variableType, *fullName); + } else { + if (variableType.getQualifier().storage == EvqUniform && ! variableType.containsOpaque()) { + // this isn't really an individual variable, but a member of the $Global buffer + parseContext.growGlobalUniformBlock(idToken.loc, variableType, *fullName); + } else { + // Declare the variable and add any initializer code to the AST. + // The top-level node is always made into an aggregate, as that's + // historically how the AST has been. + initializers = intermediate.growAggregate(initializers, + parseContext.declareVariable(idToken.loc, *fullName, variableType, expressionNode), + idToken.loc); + } + } } } - if (acceptTokenClass(EHTokComma)) { - list = true; - continue; - } - }; + // COMMA + if (acceptTokenClass(EHTokComma)) + declarator_list = true; + } - // The top-level node is a sequence. - if (node != nullptr) - node->getAsAggregate()->setOperator(EOpSequence); + // The top-level initializer node is a sequence. + if (initializers != nullptr) + initializers->setOperator(EOpSequence); + + // Add the initializers' aggregate to the nodeList we were handed. + if (nodeList) + nodeList = intermediate.growAggregate(nodeList, initializers); + else + nodeList = initializers; // SEMICOLON if (! acceptTokenClass(EHTokSemicolon)) { - expected(";"); - return false; + // This may have been a false detection of what appeared to be a declaration, but + // was actually an assignment such as "float = 4", where "float" is an identifier. + // We put the token back to let further parsing happen for cases where that may + // happen. This errors on the side of caution, and mostly triggers the error. + if (peek() == EHTokAssign || peek() == EHTokLeftBracket || peek() == EHTokDot || peek() == EHTokComma) { + recedeToken(); + return false; + } else { + expected(";"); + return false; + } } - + return true; } @@ -373,12 +536,22 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node) bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node) { node = nullptr; + TAttributes attributes; // fully_specified_type TType type; - if (! acceptFullySpecifiedType(type)) + if (! acceptFullySpecifiedType(type, attributes)) return false; + if (attributes.size() > 0) + parseContext.warn(token.loc, "attributes don't apply to control declaration", "", ""); + + // filter out type casts + if (peekTokenClass(EHTokLeftParen)) { + recedeToken(); + return false; + } + // identifier HlslToken idToken; if (! acceptIdentifier(idToken)) { @@ -399,7 +572,7 @@ bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node) return false; } - node = parseContext.declareVariable(idToken.loc, *idToken.string, type, 0, expressionNode); + node = parseContext.declareVariable(idToken.loc, *idToken.string, type, expressionNode); return true; } @@ -408,17 +581,62 @@ bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node) // : type_specifier // | type_qualifier type_specifier // -bool HlslGrammar::acceptFullySpecifiedType(TType& type) +bool HlslGrammar::acceptFullySpecifiedType(TType& type, const TAttributes& attributes) +{ + TIntermNode* nodeList = nullptr; + return acceptFullySpecifiedType(type, nodeList, attributes); +} +bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList, const TAttributes& attributes, bool forbidDeclarators) { // type_qualifier TQualifier qualifier; qualifier.clear(); - acceptQualifier(qualifier); + if (! acceptQualifier(qualifier)) + return false; + TSourceLoc loc = token.loc; // type_specifier - if (! acceptType(type)) + if (! acceptType(type, nodeList)) { + // If this is not a type, we may have inadvertently gone down a wrong path + // by parsing "sample", which can be treated like either an identifier or a + // qualifier. Back it out, if we did. + if (qualifier.sample) + recedeToken(); + return false; - type.getQualifier() = qualifier; + } + + if (type.getBasicType() == EbtBlock) { + // the type was a block, which set some parts of the qualifier + parseContext.mergeQualifiers(type.getQualifier(), qualifier); + + // merge in the attributes + parseContext.transferTypeAttributes(token.loc, attributes, type); + + // further, it can create an anonymous instance of the block + // (cbuffer and tbuffer don't consume the next identifier, and + // should set forbidDeclarators) + if (forbidDeclarators || peek() != EHTokIdentifier) + parseContext.declareBlock(loc, type); + } else { + // Some qualifiers are set when parsing the type. Merge those with + // whatever comes from acceptQualifier. + assert(qualifier.layoutFormat == ElfNone); + + qualifier.layoutFormat = type.getQualifier().layoutFormat; + qualifier.precision = type.getQualifier().precision; + + if (type.getQualifier().storage == EvqOut || + type.getQualifier().storage == EvqBuffer) { + qualifier.storage = type.getQualifier().storage; + qualifier.readonly = type.getQualifier().readonly; + } + + if (type.isBuiltIn()) + qualifier.builtIn = type.getQualifier().builtIn; + + type.getQualifier() = qualifier; + } return true; } @@ -428,12 +646,12 @@ bool HlslGrammar::acceptFullySpecifiedType(TType& type) // // Zero or more of these, so this can't return false. // -void HlslGrammar::acceptQualifier(TQualifier& qualifier) +bool HlslGrammar::acceptQualifier(TQualifier& qualifier) { do { switch (peek()) { case EHTokStatic: - // normal glslang default + qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; break; case EHTokExtern: // TODO: no meaning in glslang? @@ -454,7 +672,6 @@ void HlslGrammar::acceptQualifier(TQualifier& qualifier) qualifier.volatil = true; break; case EHTokLinear: - qualifier.storage = EvqVaryingIn; qualifier.smooth = true; break; case EHTokCentroid: @@ -470,30 +687,118 @@ void HlslGrammar::acceptQualifier(TQualifier& qualifier) qualifier.sample = true; break; case EHTokRowMajor: - qualifier.layoutMatrix = ElmRowMajor; + qualifier.layoutMatrix = ElmColumnMajor; break; case EHTokColumnMajor: - qualifier.layoutMatrix = ElmColumnMajor; + qualifier.layoutMatrix = ElmRowMajor; break; case EHTokPrecise: qualifier.noContraction = true; break; case EHTokIn: - qualifier.storage = EvqIn; + qualifier.storage = (qualifier.storage == EvqOut) ? EvqInOut : EvqIn; break; case EHTokOut: - qualifier.storage = EvqOut; + qualifier.storage = (qualifier.storage == EvqIn) ? EvqInOut : EvqOut; break; case EHTokInOut: qualifier.storage = EvqInOut; break; + case EHTokLayout: + if (! acceptLayoutQualifierList(qualifier)) + return false; + continue; + case EHTokGloballyCoherent: + qualifier.coherent = true; + break; + case EHTokInline: + // TODO: map this to SPIR-V function control + break; + + // GS geometries: these are specified on stage input variables, and are an error (not verified here) + // for output variables. + case EHTokPoint: + qualifier.storage = EvqIn; + if (!parseContext.handleInputGeometry(token.loc, ElgPoints)) + return false; + break; + case EHTokLine: + qualifier.storage = EvqIn; + if (!parseContext.handleInputGeometry(token.loc, ElgLines)) + return false; + break; + case EHTokTriangle: + qualifier.storage = EvqIn; + if (!parseContext.handleInputGeometry(token.loc, ElgTriangles)) + return false; + break; + case EHTokLineAdj: + qualifier.storage = EvqIn; + if (!parseContext.handleInputGeometry(token.loc, ElgLinesAdjacency)) + return false; + break; + case EHTokTriangleAdj: + qualifier.storage = EvqIn; + if (!parseContext.handleInputGeometry(token.loc, ElgTrianglesAdjacency)) + return false; + break; + default: - return; + return true; } advanceToken(); } while (true); } +// layout_qualifier_list +// : LAYOUT LEFT_PAREN layout_qualifier COMMA layout_qualifier ... RIGHT_PAREN +// +// layout_qualifier +// : identifier +// | identifier EQUAL expression +// +// Zero or more of these, so this can't return false. +// +bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier) +{ + if (! acceptTokenClass(EHTokLayout)) + return false; + + // LEFT_PAREN + if (! acceptTokenClass(EHTokLeftParen)) + return false; + + do { + // identifier + HlslToken idToken; + if (! acceptIdentifier(idToken)) + break; + + // EQUAL expression + if (acceptTokenClass(EHTokAssign)) { + TIntermTyped* expr; + if (! acceptConditionalExpression(expr)) { + expected("expression"); + return false; + } + parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string, expr); + } else + parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string); + + // COMMA + if (! acceptTokenClass(EHTokComma)) + break; + } while (true); + + // RIGHT_PAREN + if (! acceptTokenClass(EHTokRightParen)) { + expected(")"); + return false; + } + + return true; +} + // template_type // : FLOAT // | DOUBLE @@ -502,7 +807,7 @@ void HlslGrammar::acceptQualifier(TQualifier& qualifier) // | UINT // | BOOL // -bool HlslGrammar::acceptTemplateType(TBasicType& basicType) +bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType) { switch (peek()) { case EHTokFloat: @@ -546,7 +851,7 @@ bool HlslGrammar::acceptVectorTemplateType(TType& type) } TBasicType basicType; - if (! acceptTemplateType(basicType)) { + if (! acceptTemplateVecMatBasicType(basicType)) { expected("scalar type"); return false; } @@ -598,7 +903,7 @@ bool HlslGrammar::acceptMatrixTemplateType(TType& type) } TBasicType basicType; - if (! acceptTemplateType(basicType)) { + if (! acceptTemplateVecMatBasicType(basicType)) { expected("scalar type"); return false; } @@ -624,7 +929,7 @@ bool HlslGrammar::acceptMatrixTemplateType(TType& type) expected(","); return false; } - + // integer cols if (! peekTokenClass(EHTokIntConstant)) { expected("literal integer"); @@ -636,8 +941,8 @@ bool HlslGrammar::acceptMatrixTemplateType(TType& type) return false; new(&type) TType(basicType, EvqTemporary, 0, - cols->getAsConstantUnion()->getConstArray()[0].getIConst(), - rows->getAsConstantUnion()->getConstArray()[0].getIConst()); + rows->getAsConstantUnion()->getConstArray()[0].getIConst(), + cols->getAsConstantUnion()->getConstArray()[0].getIConst()); if (!acceptTokenClass(EHTokRightAngle)) { expected("right angle bracket"); @@ -647,6 +952,215 @@ bool HlslGrammar::acceptMatrixTemplateType(TType& type) return true; } +// layout_geometry +// : LINESTREAM +// | POINTSTREAM +// | TRIANGLESTREAM +// +bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry) +{ + // read geometry type + const EHlslTokenClass geometryType = peek(); + + switch (geometryType) { + case EHTokPointStream: geometry = ElgPoints; break; + case EHTokLineStream: geometry = ElgLineStrip; break; + case EHTokTriangleStream: geometry = ElgTriangleStrip; break; + default: + return false; // not a layout geometry + } + + advanceToken(); // consume the layout keyword + return true; +} + +// tessellation_decl_type +// : INPUTPATCH +// | OUTPUTPATCH +// +bool HlslGrammar::acceptTessellationDeclType(TBuiltInVariable& patchType) +{ + // read geometry type + const EHlslTokenClass tessType = peek(); + + switch (tessType) { + case EHTokInputPatch: patchType = EbvInputPatch; break; + case EHTokOutputPatch: patchType = EbvOutputPatch; break; + default: + return false; // not a tessellation decl + } + + advanceToken(); // consume the keyword + return true; +} + +// tessellation_patch_template_type +// : tessellation_decl_type LEFT_ANGLE type comma integer_literal RIGHT_ANGLE +// +bool HlslGrammar::acceptTessellationPatchTemplateType(TType& type) +{ + TBuiltInVariable patchType; + + if (! acceptTessellationDeclType(patchType)) + return false; + + if (! acceptTokenClass(EHTokLeftAngle)) + return false; + + if (! acceptType(type)) { + expected("tessellation patch type"); + return false; + } + + if (! acceptTokenClass(EHTokComma)) + return false; + + // integer size + if (! peekTokenClass(EHTokIntConstant)) { + expected("literal integer"); + return false; + } + + TIntermTyped* size; + if (! acceptLiteral(size)) + return false; + + TArraySizes* arraySizes = new TArraySizes; + arraySizes->addInnerSize(size->getAsConstantUnion()->getConstArray()[0].getIConst()); + type.transferArraySizes(arraySizes); + type.getQualifier().builtIn = patchType; + + if (! acceptTokenClass(EHTokRightAngle)) { + expected("right angle bracket"); + return false; + } + + return true; +} + +// stream_out_template_type +// : output_primitive_geometry_type LEFT_ANGLE type RIGHT_ANGLE +// +bool HlslGrammar::acceptStreamOutTemplateType(TType& type, TLayoutGeometry& geometry) +{ + geometry = ElgNone; + + if (! acceptOutputPrimitiveGeometry(geometry)) + return false; + + if (! acceptTokenClass(EHTokLeftAngle)) + return false; + + if (! acceptType(type)) { + expected("stream output type"); + return false; + } + + type.getQualifier().storage = EvqOut; + type.getQualifier().builtIn = EbvGsOutputStream; + + if (! acceptTokenClass(EHTokRightAngle)) { + expected("right angle bracket"); + return false; + } + + return true; +} + +// annotations +// : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE +// +bool HlslGrammar::acceptAnnotations(TQualifier&) +{ + if (! acceptTokenClass(EHTokLeftAngle)) + return false; + + // note that we are nesting a name space + parseContext.nestAnnotations(); + + // declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE + do { + // eat any extra SEMI_COLON; don't know if the grammar calls for this or not + while (acceptTokenClass(EHTokSemicolon)) + ; + + if (acceptTokenClass(EHTokRightAngle)) + break; + + // declaration + TIntermNode* node = nullptr; + if (! acceptDeclaration(node)) { + expected("declaration in annotation"); + return false; + } + } while (true); + + parseContext.unnestAnnotations(); + return true; +} + +// subpass input type +// : SUBPASSINPUT +// | SUBPASSINPUT VECTOR LEFT_ANGLE template_type RIGHT_ANGLE +// | SUBPASSINPUTMS +// | SUBPASSINPUTMS VECTOR LEFT_ANGLE template_type RIGHT_ANGLE +bool HlslGrammar::acceptSubpassInputType(TType& type) +{ + // read subpass type + const EHlslTokenClass subpassInputType = peek(); + + bool multisample; + + switch (subpassInputType) { + case EHTokSubpassInput: multisample = false; break; + case EHTokSubpassInputMS: multisample = true; break; + default: + return false; // not a subpass input declaration + } + + advanceToken(); // consume the sampler type keyword + + TType subpassType(EbtFloat, EvqUniform, 4); // default type is float4 + + if (acceptTokenClass(EHTokLeftAngle)) { + if (! acceptType(subpassType)) { + expected("scalar or vector type"); + return false; + } + + const TBasicType basicRetType = subpassType.getBasicType() ; + + switch (basicRetType) { + case EbtFloat: + case EbtUint: + case EbtInt: + case EbtStruct: + break; + default: + unimplemented("basic type in subpass input"); + return false; + } + + if (! acceptTokenClass(EHTokRightAngle)) { + expected("right angle bracket"); + return false; + } + } + + const TBasicType subpassBasicType = subpassType.isStruct() ? (*subpassType.getStruct())[0].type->getBasicType() + : subpassType.getBasicType(); + + TSampler sampler; + sampler.setSubpass(subpassBasicType, multisample); + + // Remember the declared return type. Function returns false on error. + if (!parseContext.setTextureReturnType(sampler, subpassType, token.loc)) + return false; + + type.shallowCopy(TType(sampler, EvqUniform)); + + return true; +} // sampler_type // : SAMPLER @@ -661,16 +1175,19 @@ bool HlslGrammar::acceptSamplerType(TType& type) // read sampler type const EHlslTokenClass samplerType = peek(); - TSamplerDim dim = EsdNone; + // TODO: for DX9 + // TSamplerDim dim = EsdNone; + + bool isShadow = false; switch (samplerType) { case EHTokSampler: break; - case EHTokSampler1d: dim = Esd1D; break; - case EHTokSampler2d: dim = Esd2D; break; - case EHTokSampler3d: dim = Esd3D; break; - case EHTokSamplerCube: dim = EsdCube; break; + case EHTokSampler1d: /*dim = Esd1D*/; break; + case EHTokSampler2d: /*dim = Esd2D*/; break; + case EHTokSampler3d: /*dim = Esd3D*/; break; + case EHTokSamplerCube: /*dim = EsdCube*/; break; case EHTokSamplerState: break; - case EHTokSamplerComparisonState: break; + case EHTokSamplerComparisonState: isShadow = true; break; default: return false; // not a sampler declaration } @@ -678,10 +1195,9 @@ bool HlslGrammar::acceptSamplerType(TType& type) advanceToken(); // consume the sampler type keyword TArraySizes* arraySizes = nullptr; // TODO: array - bool shadow = false; // TODO: shadow TSampler sampler; - sampler.setPureSampler(shadow); + sampler.setPureSampler(isShadow); type.shallowCopy(TType(sampler, EvqUniform, arraySizes)); @@ -699,6 +1215,13 @@ bool HlslGrammar::acceptSamplerType(TType& type) // | TEXTURECUBEARRAY // | TEXTURE2DMS // | TEXTURE2DMSARRAY +// | RWBUFFER +// | RWTEXTURE1D +// | RWTEXTURE1DARRAY +// | RWTEXTURE2D +// | RWTEXTURE2DARRAY +// | RWTEXTURE3D + bool HlslGrammar::acceptTextureType(TType& type) { const EHlslTokenClass textureType = peek(); @@ -706,18 +1229,26 @@ bool HlslGrammar::acceptTextureType(TType& type) TSamplerDim dim = EsdNone; bool array = false; bool ms = false; + bool image = false; + bool combined = true; switch (textureType) { - case EHTokBuffer: dim = EsdBuffer; break; + case EHTokBuffer: dim = EsdBuffer; combined = false; break; case EHTokTexture1d: dim = Esd1D; break; case EHTokTexture1darray: dim = Esd1D; array = true; break; case EHTokTexture2d: dim = Esd2D; break; case EHTokTexture2darray: dim = Esd2D; array = true; break; - case EHTokTexture3d: dim = Esd3D; break; + case EHTokTexture3d: dim = Esd3D; break; case EHTokTextureCube: dim = EsdCube; break; case EHTokTextureCubearray: dim = EsdCube; array = true; break; case EHTokTexture2DMS: dim = Esd2D; ms = true; break; case EHTokTexture2DMSarray: dim = Esd2D; array = true; ms = true; break; + case EHTokRWBuffer: dim = EsdBuffer; image=true; break; + case EHTokRWTexture1d: dim = Esd1D; array=false; image=true; break; + case EHTokRWTexture1darray: dim = Esd1D; array=true; image=true; break; + case EHTokRWTexture2d: dim = Esd2D; array=false; image=true; break; + case EHTokRWTexture2darray: dim = Esd2D; array=true; image=true; break; + case EHTokRWTexture3d: dim = Esd3D; array=false; image=true; break; default: return false; // not a texture declaration } @@ -725,10 +1256,10 @@ bool HlslGrammar::acceptTextureType(TType& type) advanceToken(); // consume the texture object keyword TType txType(EbtFloat, EvqUniform, 4); // default type is float4 - + TIntermTyped* msCount = nullptr; - // texture type: required for multisample types! + // texture type: required for multisample types and RWBuffer/RWTextures! if (acceptTokenClass(EHTokLeftAngle)) { if (! acceptType(txType)) { expected("scalar or vector type"); @@ -737,19 +1268,31 @@ bool HlslGrammar::acceptTextureType(TType& type) const TBasicType basicRetType = txType.getBasicType() ; - if (basicRetType != EbtFloat && basicRetType != EbtUint && basicRetType != EbtInt) { + switch (basicRetType) { + case EbtFloat: + case EbtUint: + case EbtInt: + case EbtStruct: + break; + default: unimplemented("basic type in texture"); return false; } - if (!txType.isScalar() && !txType.isVector()) { - expected("scalar or vector type"); + // Buffers can handle small mats if they fit in 4 components + if (dim == EsdBuffer && txType.isMatrix()) { + if ((txType.getMatrixCols() * txType.getMatrixRows()) > 4) { + expected("components < 4 in matrix buffer type"); + return false; + } + + // TODO: except we don't handle it yet... + unimplemented("matrix type in buffer"); return false; } - if (txType.getVectorSize() != 1 && txType.getVectorSize() != 4) { - // TODO: handle vec2/3 types - expected("vector size not yet supported in texture type"); + if (!txType.isScalar() && !txType.isVector() && !txType.isStruct()) { + expected("scalar, vector, or struct type"); return false; } @@ -771,25 +1314,99 @@ bool HlslGrammar::acceptTextureType(TType& type) } else if (ms) { expected("texture type for multisample"); return false; + } else if (image) { + expected("type for RWTexture/RWBuffer"); + return false; } TArraySizes* arraySizes = nullptr; - const bool shadow = txType.isScalar() || (txType.isVector() && txType.getVectorSize() == 1); + const bool shadow = false; // declared on the sampler TSampler sampler; - sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms); - + TLayoutFormat format = ElfNone; + + // Buffer, RWBuffer and RWTexture (images) require a TLayoutFormat. We handle only a limit set. + if (image || dim == EsdBuffer) + format = parseContext.getLayoutFromTxType(token.loc, txType); + + const TBasicType txBasicType = txType.isStruct() ? (*txType.getStruct())[0].type->getBasicType() + : txType.getBasicType(); + + // Non-image Buffers are combined + if (dim == EsdBuffer && !image) { + sampler.set(txType.getBasicType(), dim, array); + } else { + // DX10 textures are separated. TODO: DX9. + if (image) { + sampler.setImage(txBasicType, dim, array, shadow, ms); + } else { + sampler.setTexture(txBasicType, dim, array, shadow, ms); + } + } + + // Remember the declared return type. Function returns false on error. + if (!parseContext.setTextureReturnType(sampler, txType, token.loc)) + return false; + + // Force uncombined, if necessary + if (!combined) + sampler.combined = false; + type.shallowCopy(TType(sampler, EvqUniform, arraySizes)); + type.getQualifier().layoutFormat = format; return true; } - // If token is for a type, update 'type' with the type information, // and return true and advance. // Otherwise, return false, and don't advance bool HlslGrammar::acceptType(TType& type) { + TIntermNode* nodeList = nullptr; + return acceptType(type, nodeList); +} +bool HlslGrammar::acceptType(TType& type, TIntermNode*& nodeList) +{ + // Basic types for min* types, use native halfs if the option allows them. + bool enable16BitTypes = parseContext.hlslEnable16BitTypes(); + + const TBasicType min16float_bt = enable16BitTypes ? EbtFloat16 : EbtFloat; + const TBasicType min10float_bt = enable16BitTypes ? EbtFloat16 : EbtFloat; + const TBasicType half_bt = enable16BitTypes ? EbtFloat16 : EbtFloat; + const TBasicType min16int_bt = enable16BitTypes ? EbtInt16 : EbtInt; + const TBasicType min12int_bt = enable16BitTypes ? EbtInt16 : EbtInt; + const TBasicType min16uint_bt = enable16BitTypes ? EbtUint16 : EbtUint; + + // Some types might have turned into identifiers. Take the hit for checking + // when this has happened. + if (typeIdentifiers) { + const char* identifierString = getTypeString(peek()); + if (identifierString != nullptr) { + TString name = identifierString; + // if it's an identifier, it's not a type + if (parseContext.symbolTable.find(name) != nullptr) + return false; + } + } + + bool isUnorm = false; + bool isSnorm = false; + + // Accept snorm and unorm. Presently, this is ignored, save for an error check below. + switch (peek()) { + case EHTokUnorm: + isUnorm = true; + advanceToken(); // eat the token + break; + case EHTokSNorm: + isSnorm = true; + advanceToken(); // eat the token + break; + default: + break; + } + switch (peek()) { case EHTokVector: return acceptVectorTemplateType(type); @@ -799,6 +1416,29 @@ bool HlslGrammar::acceptType(TType& type) return acceptMatrixTemplateType(type); break; + case EHTokPointStream: // fall through + case EHTokLineStream: // ... + case EHTokTriangleStream: // ... + { + TLayoutGeometry geometry; + if (! acceptStreamOutTemplateType(type, geometry)) + return false; + + if (! parseContext.handleOutputGeometry(token.loc, geometry)) + return false; + + return true; + } + + case EHTokInputPatch: // fall through + case EHTokOutputPatch: // ... + { + if (! acceptTessellationPatchTemplateType(type)) + return false; + + return true; + } + case EHTokSampler: // fall through case EHTokSampler1d: // ... case EHTokSampler2d: // ... @@ -809,6 +1449,11 @@ bool HlslGrammar::acceptType(TType& type) return acceptSamplerType(type); break; + case EHTokSubpassInput: // fall through + case EHTokSubpassInputMS: // ... + return acceptSubpassInputType(type); + break; + case EHTokBuffer: // fall through case EHTokTexture1d: // ... case EHTokTexture1darray: // ... @@ -819,20 +1464,42 @@ bool HlslGrammar::acceptType(TType& type) case EHTokTextureCubearray: // ... case EHTokTexture2DMS: // ... case EHTokTexture2DMSarray: // ... + case EHTokRWTexture1d: // ... + case EHTokRWTexture1darray: // ... + case EHTokRWTexture2d: // ... + case EHTokRWTexture2darray: // ... + case EHTokRWTexture3d: // ... + case EHTokRWBuffer: // ... return acceptTextureType(type); break; - case EHTokStruct: - return acceptStruct(type); + case EHTokAppendStructuredBuffer: + case EHTokByteAddressBuffer: + case EHTokConsumeStructuredBuffer: + case EHTokRWByteAddressBuffer: + case EHTokRWStructuredBuffer: + case EHTokStructuredBuffer: + return acceptStructBufferType(type); break; + case EHTokTextureBuffer: + return acceptTextureBufferType(type); + break; + + case EHTokConstantBuffer: + return acceptConstantBufferType(type); + + case EHTokClass: + case EHTokStruct: + case EHTokCBuffer: + case EHTokTBuffer: + return acceptStruct(type, nodeList); + case EHTokIdentifier: // An identifier could be for a user-defined type. // Note we cache the symbol table lookup, to save for a later rule // when this is not a type. - token.symbol = parseContext.symbolTable.find(*token.string); - if (token.symbol && token.symbol->getAsVariable() && token.symbol->getAsVariable()->isUserType()) { - type.shallowCopy(token.symbol->getType()); + if (parseContext.lookupUserType(*token.string, type) != nullptr) { advanceToken(); return true; } else @@ -842,6 +1509,10 @@ bool HlslGrammar::acceptType(TType& type) new(&type) TType(EbtVoid); break; + case EHTokString: + new(&type) TType(EbtString); + break; + case EHTokFloat: new(&type) TType(EbtFloat); break; @@ -911,6 +1582,9 @@ bool HlslGrammar::acceptType(TType& type) new(&type) TType(EbtUint, EvqTemporary, 4); break; + case EHTokUint64: + new(&type) TType(EbtUint64); + break; case EHTokBool: new(&type) TType(EbtBool); @@ -929,50 +1603,152 @@ bool HlslGrammar::acceptType(TType& type) new(&type) TType(EbtBool, EvqTemporary, 4); break; + case EHTokHalf: + new(&type) TType(half_bt, EvqTemporary); + break; + case EHTokHalf1: + new(&type) TType(half_bt, EvqTemporary); + type.makeVector(); + break; + case EHTokHalf2: + new(&type) TType(half_bt, EvqTemporary, 2); + break; + case EHTokHalf3: + new(&type) TType(half_bt, EvqTemporary, 3); + break; + case EHTokHalf4: + new(&type) TType(half_bt, EvqTemporary, 4); + break; + + case EHTokMin16float: + new(&type) TType(min16float_bt, EvqTemporary, EpqMedium); + break; + case EHTokMin16float1: + new(&type) TType(min16float_bt, EvqTemporary, EpqMedium); + type.makeVector(); + break; + case EHTokMin16float2: + new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 2); + break; + case EHTokMin16float3: + new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 3); + break; + case EHTokMin16float4: + new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 4); + break; + + case EHTokMin10float: + new(&type) TType(min10float_bt, EvqTemporary, EpqMedium); + break; + case EHTokMin10float1: + new(&type) TType(min10float_bt, EvqTemporary, EpqMedium); + type.makeVector(); + break; + case EHTokMin10float2: + new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 2); + break; + case EHTokMin10float3: + new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 3); + break; + case EHTokMin10float4: + new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 4); + break; + + case EHTokMin16int: + new(&type) TType(min16int_bt, EvqTemporary, EpqMedium); + break; + case EHTokMin16int1: + new(&type) TType(min16int_bt, EvqTemporary, EpqMedium); + type.makeVector(); + break; + case EHTokMin16int2: + new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 2); + break; + case EHTokMin16int3: + new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 3); + break; + case EHTokMin16int4: + new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 4); + break; + + case EHTokMin12int: + new(&type) TType(min12int_bt, EvqTemporary, EpqMedium); + break; + case EHTokMin12int1: + new(&type) TType(min12int_bt, EvqTemporary, EpqMedium); + type.makeVector(); + break; + case EHTokMin12int2: + new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 2); + break; + case EHTokMin12int3: + new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 3); + break; + case EHTokMin12int4: + new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 4); + break; + + case EHTokMin16uint: + new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium); + break; + case EHTokMin16uint1: + new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium); + type.makeVector(); + break; + case EHTokMin16uint2: + new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 2); + break; + case EHTokMin16uint3: + new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 3); + break; + case EHTokMin16uint4: + new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 4); + break; + case EHTokInt1x1: new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1); break; case EHTokInt1x2: - new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1); + new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2); break; case EHTokInt1x3: - new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1); + new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3); break; case EHTokInt1x4: - new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1); + new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4); break; case EHTokInt2x1: - new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2); + new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1); break; case EHTokInt2x2: new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2); break; case EHTokInt2x3: - new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2); + new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3); break; case EHTokInt2x4: - new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2); + new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4); break; case EHTokInt3x1: - new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3); + new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1); break; case EHTokInt3x2: - new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3); + new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2); break; case EHTokInt3x3: new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3); break; case EHTokInt3x4: - new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3); + new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4); break; case EHTokInt4x1: - new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4); + new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1); break; case EHTokInt4x2: - new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4); + new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2); break; case EHTokInt4x3: - new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4); + new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3); break; case EHTokInt4x4: new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4); @@ -982,46 +1758,46 @@ bool HlslGrammar::acceptType(TType& type) new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1); break; case EHTokUint1x2: - new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1); + new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2); break; case EHTokUint1x3: - new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1); + new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3); break; case EHTokUint1x4: - new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1); + new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4); break; case EHTokUint2x1: - new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2); + new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1); break; case EHTokUint2x2: new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2); break; case EHTokUint2x3: - new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2); + new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3); break; case EHTokUint2x4: - new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2); + new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4); break; case EHTokUint3x1: - new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3); + new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1); break; case EHTokUint3x2: - new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3); + new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2); break; case EHTokUint3x3: new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3); break; case EHTokUint3x4: - new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3); + new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4); break; case EHTokUint4x1: - new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4); + new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1); break; case EHTokUint4x2: - new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4); + new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2); break; case EHTokUint4x3: - new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4); + new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3); break; case EHTokUint4x4: new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4); @@ -1031,46 +1807,46 @@ bool HlslGrammar::acceptType(TType& type) new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1); break; case EHTokBool1x2: - new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1); + new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2); break; case EHTokBool1x3: - new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1); + new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3); break; case EHTokBool1x4: - new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1); + new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4); break; case EHTokBool2x1: - new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2); + new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1); break; case EHTokBool2x2: new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2); break; case EHTokBool2x3: - new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2); + new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3); break; case EHTokBool2x4: - new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2); + new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4); break; case EHTokBool3x1: - new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3); + new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1); break; case EHTokBool3x2: - new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3); + new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2); break; case EHTokBool3x3: new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3); break; case EHTokBool3x4: - new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3); + new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4); break; case EHTokBool4x1: - new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4); + new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1); break; case EHTokBool4x2: - new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4); + new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2); break; case EHTokBool4x3: - new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4); + new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3); break; case EHTokBool4x4: new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4); @@ -1080,95 +1856,144 @@ bool HlslGrammar::acceptType(TType& type) new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1); break; case EHTokFloat1x2: - new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1); + new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2); break; case EHTokFloat1x3: - new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1); + new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3); break; case EHTokFloat1x4: - new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1); + new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4); break; case EHTokFloat2x1: - new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2); + new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1); break; case EHTokFloat2x2: new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2); break; case EHTokFloat2x3: - new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2); + new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3); break; case EHTokFloat2x4: - new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2); + new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4); break; case EHTokFloat3x1: - new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3); + new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1); break; case EHTokFloat3x2: - new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3); + new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2); break; case EHTokFloat3x3: new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3); break; case EHTokFloat3x4: - new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3); + new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4); break; case EHTokFloat4x1: - new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4); + new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1); break; case EHTokFloat4x2: - new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4); + new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2); break; case EHTokFloat4x3: - new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4); + new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3); break; case EHTokFloat4x4: new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4); break; + case EHTokHalf1x1: + new(&type) TType(half_bt, EvqTemporary, 0, 1, 1); + break; + case EHTokHalf1x2: + new(&type) TType(half_bt, EvqTemporary, 0, 1, 2); + break; + case EHTokHalf1x3: + new(&type) TType(half_bt, EvqTemporary, 0, 1, 3); + break; + case EHTokHalf1x4: + new(&type) TType(half_bt, EvqTemporary, 0, 1, 4); + break; + case EHTokHalf2x1: + new(&type) TType(half_bt, EvqTemporary, 0, 2, 1); + break; + case EHTokHalf2x2: + new(&type) TType(half_bt, EvqTemporary, 0, 2, 2); + break; + case EHTokHalf2x3: + new(&type) TType(half_bt, EvqTemporary, 0, 2, 3); + break; + case EHTokHalf2x4: + new(&type) TType(half_bt, EvqTemporary, 0, 2, 4); + break; + case EHTokHalf3x1: + new(&type) TType(half_bt, EvqTemporary, 0, 3, 1); + break; + case EHTokHalf3x2: + new(&type) TType(half_bt, EvqTemporary, 0, 3, 2); + break; + case EHTokHalf3x3: + new(&type) TType(half_bt, EvqTemporary, 0, 3, 3); + break; + case EHTokHalf3x4: + new(&type) TType(half_bt, EvqTemporary, 0, 3, 4); + break; + case EHTokHalf4x1: + new(&type) TType(half_bt, EvqTemporary, 0, 4, 1); + break; + case EHTokHalf4x2: + new(&type) TType(half_bt, EvqTemporary, 0, 4, 2); + break; + case EHTokHalf4x3: + new(&type) TType(half_bt, EvqTemporary, 0, 4, 3); + break; + case EHTokHalf4x4: + new(&type) TType(half_bt, EvqTemporary, 0, 4, 4); + break; + case EHTokDouble1x1: new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1); break; case EHTokDouble1x2: - new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1); + new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2); break; case EHTokDouble1x3: - new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1); + new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3); break; case EHTokDouble1x4: - new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1); + new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4); break; case EHTokDouble2x1: - new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2); + new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1); break; case EHTokDouble2x2: new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2); break; case EHTokDouble2x3: - new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2); + new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3); break; case EHTokDouble2x4: - new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2); + new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4); break; case EHTokDouble3x1: - new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3); + new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1); break; case EHTokDouble3x2: - new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3); + new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2); break; case EHTokDouble3x3: new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3); break; case EHTokDouble3x4: - new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3); + new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4); break; case EHTokDouble4x1: - new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4); + new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1); break; case EHTokDouble4x2: - new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4); + new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2); break; case EHTokDouble4x3: - new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4); + new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3); break; case EHTokDouble4x4: new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4); @@ -1180,35 +2005,89 @@ bool HlslGrammar::acceptType(TType& type) advanceToken(); + if ((isUnorm || isSnorm) && !type.isFloatingDomain()) { + parseContext.error(token.loc, "unorm and snorm only valid in floating point domain", "", ""); + return false; + } + return true; } // struct -// : STRUCT IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE -// | STRUCT LEFT_BRACE struct_declaration_list RIGHT_BRACE +// : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE +// | struct_type post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE +// | struct_type IDENTIFIER // use of previously declared struct type // -bool HlslGrammar::acceptStruct(TType& type) +// struct_type +// : STRUCT +// | CLASS +// | CBUFFER +// | TBUFFER +// +bool HlslGrammar::acceptStruct(TType& type, TIntermNode*& nodeList) { - // STRUCT - if (! acceptTokenClass(EHTokStruct)) - return false; + // This storage qualifier will tell us whether it's an AST + // block type or just a generic structure type. + TStorageQualifier storageQualifier = EvqTemporary; + bool readonly = false; - // IDENTIFIER + if (acceptTokenClass(EHTokCBuffer)) { + // CBUFFER + storageQualifier = EvqUniform; + } else if (acceptTokenClass(EHTokTBuffer)) { + // TBUFFER + storageQualifier = EvqBuffer; + readonly = true; + } else if (! acceptTokenClass(EHTokClass) && ! acceptTokenClass(EHTokStruct)) { + // Neither CLASS nor STRUCT + return false; + } + + // Now known to be one of CBUFFER, TBUFFER, CLASS, or STRUCT + + + // IDENTIFIER. It might also be a keyword which can double as an identifier. + // For example: 'cbuffer ConstantBuffer' or 'struct ConstantBuffer' is legal. + // 'cbuffer int' is also legal, and 'struct int' appears rejected only because + // it attempts to redefine the 'int' type. + const char* idString = getTypeString(peek()); TString structName = ""; - if (peekTokenClass(EHTokIdentifier)) { - structName = *token.string; + if (peekTokenClass(EHTokIdentifier) || idString != nullptr) { + if (idString != nullptr) + structName = *idString; + else + structName = *token.string; advanceToken(); } - // LEFT_BRACE + // post_decls + TQualifier postDeclQualifier; + postDeclQualifier.clear(); + bool postDeclsFound = acceptPostDecls(postDeclQualifier); + + // LEFT_BRACE, or + // struct_type IDENTIFIER if (! acceptTokenClass(EHTokLeftBrace)) { - expected("{"); - return false; + if (structName.size() > 0 && !postDeclsFound && parseContext.lookupUserType(structName, type) != nullptr) { + // struct_type IDENTIFIER + return true; + } else { + expected("{"); + return false; + } } + // struct_declaration_list TTypeList* typeList; - if (! acceptStructDeclarationList(typeList)) { + // Save each member function so they can be processed after we have a fully formed 'this'. + TVector functionDeclarators; + + parseContext.pushNamespace(structName); + bool acceptedList = acceptStructDeclarationList(typeList, nodeList, functionDeclarators); + parseContext.popNamespace(); + + if (! acceptedList) { expected("struct member declarations"); return false; } @@ -1220,16 +2099,218 @@ bool HlslGrammar::acceptStruct(TType& type) } // create the user-defined type - new(&type) TType(typeList, structName); - - // If it was named, which means it can be reused later, add - // it to the symbol table. - if (structName.size() > 0) { - TVariable* userTypeDef = new TVariable(&structName, type, true); - if (! parseContext.symbolTable.insert(*userTypeDef)) - parseContext.error(token.loc, "redefinition", structName.c_str(), "struct"); + if (storageQualifier == EvqTemporary) + new(&type) TType(typeList, structName); + else { + postDeclQualifier.storage = storageQualifier; + postDeclQualifier.readonly = readonly; + new(&type) TType(typeList, structName, postDeclQualifier); // sets EbtBlock } + parseContext.declareStruct(token.loc, structName, type); + + // For member functions: now that we know the type of 'this', go back and + // - add their implicit argument with 'this' (not to the mangling, just the argument list) + // - parse the functions, their tokens were saved for deferred parsing (now) + for (int b = 0; b < (int)functionDeclarators.size(); ++b) { + // update signature + if (functionDeclarators[b].function->hasImplicitThis()) + functionDeclarators[b].function->addThisParameter(type, intermediate.implicitThisName); + } + + // All member functions get parsed inside the class/struct namespace and with the + // class/struct members in a symbol-table level. + parseContext.pushNamespace(structName); + parseContext.pushThisScope(type, functionDeclarators); + bool deferredSuccess = true; + for (int b = 0; b < (int)functionDeclarators.size() && deferredSuccess; ++b) { + // parse body + pushTokenStream(functionDeclarators[b].body); + if (! acceptFunctionBody(functionDeclarators[b], nodeList)) + deferredSuccess = false; + popTokenStream(); + } + parseContext.popThisScope(); + parseContext.popNamespace(); + + return deferredSuccess; +} + +// constantbuffer +// : CONSTANTBUFFER LEFT_ANGLE type RIGHT_ANGLE +bool HlslGrammar::acceptConstantBufferType(TType& type) +{ + if (! acceptTokenClass(EHTokConstantBuffer)) + return false; + + if (! acceptTokenClass(EHTokLeftAngle)) { + expected("left angle bracket"); + return false; + } + + TType templateType; + if (! acceptType(templateType)) { + expected("type"); + return false; + } + + if (! acceptTokenClass(EHTokRightAngle)) { + expected("right angle bracket"); + return false; + } + + TQualifier postDeclQualifier; + postDeclQualifier.clear(); + postDeclQualifier.storage = EvqUniform; + + if (templateType.isStruct()) { + // Make a block from the type parsed as the template argument + TTypeList* typeList = templateType.getWritableStruct(); + new(&type) TType(typeList, "", postDeclQualifier); // sets EbtBlock + + type.getQualifier().storage = EvqUniform; + + return true; + } else { + parseContext.error(token.loc, "non-structure type in ConstantBuffer", "", ""); + return false; + } +} + +// texture_buffer +// : TEXTUREBUFFER LEFT_ANGLE type RIGHT_ANGLE +bool HlslGrammar::acceptTextureBufferType(TType& type) +{ + if (! acceptTokenClass(EHTokTextureBuffer)) + return false; + + if (! acceptTokenClass(EHTokLeftAngle)) { + expected("left angle bracket"); + return false; + } + + TType templateType; + if (! acceptType(templateType)) { + expected("type"); + return false; + } + + if (! acceptTokenClass(EHTokRightAngle)) { + expected("right angle bracket"); + return false; + } + + templateType.getQualifier().storage = EvqBuffer; + templateType.getQualifier().readonly = true; + + TType blockType(templateType.getWritableStruct(), "", templateType.getQualifier()); + + blockType.getQualifier().storage = EvqBuffer; + blockType.getQualifier().readonly = true; + + type.shallowCopy(blockType); + + return true; +} + + +// struct_buffer +// : APPENDSTRUCTUREDBUFFER +// | BYTEADDRESSBUFFER +// | CONSUMESTRUCTUREDBUFFER +// | RWBYTEADDRESSBUFFER +// | RWSTRUCTUREDBUFFER +// | STRUCTUREDBUFFER +bool HlslGrammar::acceptStructBufferType(TType& type) +{ + const EHlslTokenClass structBuffType = peek(); + + // TODO: globallycoherent + bool hasTemplateType = true; + bool readonly = false; + + TStorageQualifier storage = EvqBuffer; + TBuiltInVariable builtinType = EbvNone; + + switch (structBuffType) { + case EHTokAppendStructuredBuffer: + builtinType = EbvAppendConsume; + break; + case EHTokByteAddressBuffer: + hasTemplateType = false; + readonly = true; + builtinType = EbvByteAddressBuffer; + break; + case EHTokConsumeStructuredBuffer: + builtinType = EbvAppendConsume; + break; + case EHTokRWByteAddressBuffer: + hasTemplateType = false; + builtinType = EbvRWByteAddressBuffer; + break; + case EHTokRWStructuredBuffer: + builtinType = EbvRWStructuredBuffer; + break; + case EHTokStructuredBuffer: + builtinType = EbvStructuredBuffer; + readonly = true; + break; + default: + return false; // not a structure buffer type + } + + advanceToken(); // consume the structure keyword + + // type on which this StructedBuffer is templatized. E.g, StructedBuffer ==> MyStruct + TType* templateType = new TType; + + if (hasTemplateType) { + if (! acceptTokenClass(EHTokLeftAngle)) { + expected("left angle bracket"); + return false; + } + + if (! acceptType(*templateType)) { + expected("type"); + return false; + } + if (! acceptTokenClass(EHTokRightAngle)) { + expected("right angle bracket"); + return false; + } + } else { + // byte address buffers have no explicit type. + TType uintType(EbtUint, storage); + templateType->shallowCopy(uintType); + } + + // Create an unsized array out of that type. + // TODO: does this work if it's already an array type? + TArraySizes* unsizedArray = new TArraySizes; + unsizedArray->addInnerSize(UnsizedArraySize); + templateType->transferArraySizes(unsizedArray); + templateType->getQualifier().storage = storage; + + // field name is canonical for all structbuffers + templateType->setFieldName("@data"); + + TTypeList* blockStruct = new TTypeList; + TTypeLoc member = { templateType, token.loc }; + blockStruct->push_back(member); + + // This is the type of the buffer block (SSBO) + TType blockType(blockStruct, "", templateType->getQualifier()); + + blockType.getQualifier().storage = storage; + blockType.getQualifier().readonly = readonly; + blockType.getQualifier().builtIn = builtinType; + + // We may have created an equivalent type before, in which case we should use its + // deep structure. + parseContext.shareStructBufferType(blockType); + + type.shallowCopy(blockType); + return true; } @@ -1237,61 +2318,96 @@ bool HlslGrammar::acceptStruct(TType& type) // : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ... // // struct_declaration -// : fully_specified_type struct_declarator COMMA struct_declarator ... +// : attributes fully_specified_type struct_declarator COMMA struct_declarator ... +// | attributes fully_specified_type IDENTIFIER function_parameters post_decls compound_statement // member-function definition // // struct_declarator // : IDENTIFIER post_decls // | IDENTIFIER array_specifier post_decls +// | IDENTIFIER function_parameters post_decls // member-function prototype // -bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList) +bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*& nodeList, + TVector& declarators) { typeList = new TTypeList(); + HlslToken idToken; do { // success on seeing the RIGHT_BRACE coming up if (peekTokenClass(EHTokRightBrace)) - return true; + break; // struct_declaration + // attributes + TAttributes attributes; + acceptAttributes(attributes); + + bool declarator_list = false; + // fully_specified_type TType memberType; - if (! acceptFullySpecifiedType(memberType)) { + if (! acceptFullySpecifiedType(memberType, nodeList, attributes)) { expected("member type"); return false; } + + // merge in the attributes + parseContext.transferTypeAttributes(token.loc, attributes, memberType); // struct_declarator COMMA struct_declarator ... + bool functionDefinitionAccepted = false; do { - // peek IDENTIFIER - if (! peekTokenClass(EHTokIdentifier)) { + if (! acceptIdentifier(idToken)) { expected("member name"); return false; } - // add it to the list of members - TTypeLoc member = { new TType(EbtVoid), token.loc }; - member.type->shallowCopy(memberType); - member.type->setFieldName(*token.string); - typeList->push_back(member); + if (peekTokenClass(EHTokLeftParen)) { + // function_parameters + if (!declarator_list) { + declarators.resize(declarators.size() + 1); + // request a token stream for deferred processing + functionDefinitionAccepted = acceptMemberFunctionDefinition(nodeList, memberType, *idToken.string, + declarators.back()); + if (functionDefinitionAccepted) + break; + } + expected("member-function definition"); + return false; + } else { + // add it to the list of members + TTypeLoc member = { new TType(EbtVoid), token.loc }; + member.type->shallowCopy(memberType); + member.type->setFieldName(*idToken.string); + typeList->push_back(member); - // accept IDENTIFIER - advanceToken(); + // array_specifier + TArraySizes* arraySizes = nullptr; + acceptArraySpecifier(arraySizes); + if (arraySizes) + typeList->back().type->transferArraySizes(arraySizes); - // array_specifier - TArraySizes* arraySizes = nullptr; - acceptArraySpecifier(arraySizes); - if (arraySizes) - typeList->back().type->newArraySizes(*arraySizes); - - acceptPostDecls(*member.type); + acceptPostDecls(member.type->getQualifier()); + // EQUAL assignment_expression + if (acceptTokenClass(EHTokAssign)) { + parseContext.warn(idToken.loc, "struct-member initializers ignored", "typedef", ""); + TIntermTyped* expressionNode = nullptr; + if (! acceptAssignmentExpression(expressionNode)) { + expected("initializer"); + return false; + } + } + } // success on seeing the SEMICOLON coming up if (peekTokenClass(EHTokSemicolon)) break; // COMMA - if (! acceptTokenClass(EHTokComma)) { + if (acceptTokenClass(EHTokComma)) + declarator_list = true; + else { expected(","); return false; } @@ -1299,12 +2415,49 @@ bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList) } while (true); // SEMI_COLON - if (! acceptTokenClass(EHTokSemicolon)) { + if (! functionDefinitionAccepted && ! acceptTokenClass(EHTokSemicolon)) { expected(";"); return false; } } while (true); + + return true; +} + +// member_function_definition +// | function_parameters post_decls compound_statement +// +// Expects type to have EvqGlobal for a static member and +// EvqTemporary for non-static member. +bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TType& type, TString& memberName, + TFunctionDeclarator& declarator) +{ + bool accepted = false; + + TString* functionName = &memberName; + parseContext.getFullNamespaceName(functionName); + declarator.function = new TFunction(functionName, type); + if (type.getQualifier().storage == EvqTemporary) + declarator.function->setImplicitThis(); + else + declarator.function->setIllegalImplicitThis(); + + // function_parameters + if (acceptFunctionParameters(*declarator.function)) { + // post_decls + acceptPostDecls(declarator.function->getWritableType().getQualifier()); + + // compound_statement (function body definition) + if (peekTokenClass(EHTokLeftBrace)) { + declarator.loc = token.loc; + declarator.body = new TVector; + accepted = acceptFunctionDefinition(declarator, nodeList, declarator.body); + } + } else + expected("function parameter list"); + + return accepted; } // function_parameters @@ -1339,17 +2492,75 @@ bool HlslGrammar::acceptFunctionParameters(TFunction& function) return true; } +// default_parameter_declaration +// : EQUAL conditional_expression +// : EQUAL initializer +bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTyped*& node) +{ + node = nullptr; + + // Valid not to have a default_parameter_declaration + if (!acceptTokenClass(EHTokAssign)) + return true; + + if (!acceptConditionalExpression(node)) { + if (!acceptInitializer(node)) + return false; + + // For initializer lists, we have to const-fold into a constructor for the type, so build + // that. + TFunction* constructor = parseContext.makeConstructorCall(token.loc, type); + if (constructor == nullptr) // cannot construct + return false; + + TIntermTyped* arguments = nullptr; + for (int i = 0; i < int(node->getAsAggregate()->getSequence().size()); i++) + parseContext.handleFunctionArgument(constructor, arguments, node->getAsAggregate()->getSequence()[i]->getAsTyped()); + + node = parseContext.handleFunctionCall(token.loc, constructor, node); + } + + if (node == nullptr) + return false; + + // If this is simply a constant, we can use it directly. + if (node->getAsConstantUnion()) + return true; + + // Otherwise, it has to be const-foldable. + TIntermTyped* origNode = node; + + node = intermediate.fold(node->getAsAggregate()); + + if (node != nullptr && origNode != node) + return true; + + parseContext.error(token.loc, "invalid default parameter value", "", ""); + + return false; +} + // parameter_declaration -// : fully_specified_type post_decls -// | fully_specified_type identifier array_specifier post_decls +// : attributes attributed_declaration +// +// attributed_declaration +// : fully_specified_type post_decls [ = default_parameter_declaration ] +// | fully_specified_type identifier array_specifier post_decls [ = default_parameter_declaration ] // bool HlslGrammar::acceptParameterDeclaration(TFunction& function) { + // attributes + TAttributes attributes; + acceptAttributes(attributes); + // fully_specified_type TType* type = new TType; - if (! acceptFullySpecifiedType(*type)) + if (! acceptFullySpecifiedType(*type, attributes)) return false; + // merge in the attributes + parseContext.transferTypeAttributes(token.loc, attributes, *type); + // identifier HlslToken idToken; acceptIdentifier(idToken); @@ -1357,15 +2568,31 @@ bool HlslGrammar::acceptParameterDeclaration(TFunction& function) // array_specifier TArraySizes* arraySizes = nullptr; acceptArraySpecifier(arraySizes); - if (arraySizes) - type->newArraySizes(*arraySizes); + if (arraySizes) { + if (arraySizes->hasUnsized()) { + parseContext.error(token.loc, "function parameter requires array size", "[]", ""); + return false; + } + + type->transferArraySizes(arraySizes); + } // post_decls - acceptPostDecls(*type); + acceptPostDecls(type->getQualifier()); + + TIntermTyped* defaultValue; + if (!acceptDefaultParameterDeclaration(*type, defaultValue)) + return false; parseContext.paramFix(*type); - TParameter param = { idToken.string, type }; + // If any prior parameters have default values, all the parameters after that must as well. + if (defaultValue == nullptr && function.getDefaultParamCount() > 0) { + parseContext.error(idToken.loc, "invalid parameter after default value parameters", idToken.string->c_str(), ""); + return false; + } + + TParameter param = { idToken.string, type, defaultValue }; function.addParameter(param); return true; @@ -1373,25 +2600,43 @@ bool HlslGrammar::acceptParameterDeclaration(TFunction& function) // Do the work to create the function definition in addition to // parsing the body (compound_statement). -bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& node) +// +// If 'deferredTokens' are passed in, just get the token stream, +// don't process. +// +bool HlslGrammar::acceptFunctionDefinition(TFunctionDeclarator& declarator, TIntermNode*& nodeList, + TVector* deferredTokens) { - TFunction* functionDeclarator = parseContext.handleFunctionDeclarator(token.loc, function, false /* not prototype */); + parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, false /* not prototype */); + + if (deferredTokens) + return captureBlockTokens(*deferredTokens); + else + return acceptFunctionBody(declarator, nodeList); +} + +bool HlslGrammar::acceptFunctionBody(TFunctionDeclarator& declarator, TIntermNode*& nodeList) +{ + // we might get back an entry-point + TIntermNode* entryPointNode = nullptr; // This does a pushScope() - node = parseContext.handleFunctionDefinition(token.loc, *functionDeclarator); + TIntermNode* functionNode = parseContext.handleFunctionDefinition(declarator.loc, *declarator.function, + declarator.attributes, entryPointNode); // compound_statement TIntermNode* functionBody = nullptr; - if (acceptCompoundStatement(functionBody)) { - node = intermediate.growAggregate(node, functionBody); - intermediate.setAggregateOperator(node, EOpFunction, functionDeclarator->getType(), token.loc); - node->getAsAggregate()->setName(functionDeclarator->getMangledName().c_str()); - parseContext.popScope(); + if (! acceptCompoundStatement(functionBody)) + return false; - return true; - } + // this does a popScope() + parseContext.handleFunctionBody(declarator.loc, *declarator.function, functionBody, functionNode); - return false; + // Hook up the 1 or 2 function definitions. + nodeList = intermediate.growAggregate(nodeList, functionNode); + nodeList = intermediate.growAggregate(nodeList, entryPointNode); + + return true; } // Accept an expression with parenthesis around it, where @@ -1405,6 +2650,8 @@ bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& no // bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression) { + expression = nullptr; + // LEFT_PAREN if (! acceptTokenClass(EHTokLeftParen)) expected("("); @@ -1469,7 +2716,8 @@ bool HlslGrammar::acceptExpression(TIntermTyped*& node) } // initializer -// : LEFT_BRACE initializer_list RIGHT_BRACE +// : LEFT_BRACE RIGHT_BRACE +// | LEFT_BRACE initializer_list RIGHT_BRACE // // initializer_list // : assignment_expression COMMA assignment_expression COMMA ... @@ -1480,8 +2728,15 @@ bool HlslGrammar::acceptInitializer(TIntermTyped*& node) if (! acceptTokenClass(EHTokLeftBrace)) return false; - // initializer_list + // RIGHT_BRACE TSourceLoc loc = token.loc; + if (acceptTokenClass(EHTokRightBrace)) { + // a zero-length initializer list + node = intermediate.makeAggregate(loc); + return true; + } + + // initializer_list node = nullptr; do { // assignment_expression @@ -1490,11 +2745,25 @@ bool HlslGrammar::acceptInitializer(TIntermTyped*& node) expected("assignment expression in initializer list"); return false; } + + const bool firstNode = (node == nullptr); + node = intermediate.growAggregate(node, expr, loc); + // If every sub-node in the list has qualifier EvqConst, the returned node becomes + // EvqConst. Otherwise, it becomes EvqTemporary. That doesn't happen with e.g. + // EvqIn or EvqPosition, since the collection isn't EvqPosition if all the members are. + if (firstNode && expr->getQualifier().storage == EvqConst) + node->getQualifier().storage = EvqConst; + else if (expr->getQualifier().storage != EvqConst) + node->getQualifier().storage = EvqTemporary; + // COMMA - if (acceptTokenClass(EHTokComma)) + if (acceptTokenClass(EHTokComma)) { + if (acceptTokenClass(EHTokRightBrace)) // allow trailing comma + return true; continue; + } // RIGHT_BRACE if (acceptTokenClass(EHTokRightBrace)) @@ -1511,8 +2780,9 @@ bool HlslGrammar::acceptInitializer(TIntermTyped*& node) // a op (b op (c op d)) // // assigment_expression -// : binary_expression op binary_expression op binary_expression ... -// | initializer +// : initializer +// | conditional_expression +// | conditional_expression assign_op conditional_expression assign_op conditional_expression ... // bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node) { @@ -1525,8 +2795,8 @@ bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node) return false; } - // binary_expression - if (! acceptBinaryExpression(node, PlLogicalOr)) + // conditional_expression + if (! acceptConditionalExpression(node)) return false; // assignment operation? @@ -1534,12 +2804,12 @@ bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node) if (assignOp == EOpNull) return true; - // assignment op + // assign_op TSourceLoc loc = token.loc; advanceToken(); - // binary_expression - // But, done by recursing this function, which automatically + // conditional_expression assign_op conditional_expression ... + // Done by recursing this function, which automatically // gets the right-to-left associativity. TIntermTyped* rightNode = nullptr; if (! acceptAssignmentExpression(rightNode)) { @@ -1547,7 +2817,13 @@ bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node) return false; } - node = intermediate.addAssign(assignOp, node, rightNode, loc); + node = parseContext.handleAssign(loc, assignOp, node, rightNode); + node = parseContext.handleLvalue(loc, "assign", node); + + if (node == nullptr) { + parseContext.error(loc, "could not create assignment", "", ""); + return false; + } if (! peekTokenClass(EHTokComma)) return true; @@ -1555,6 +2831,54 @@ bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node) return true; } +// Accept a conditional expression, which associates right-to-left, +// accomplished by the "true" expression calling down to lower +// precedence levels than this level. +// +// conditional_expression +// : binary_expression +// | binary_expression QUESTION expression COLON assignment_expression +// +bool HlslGrammar::acceptConditionalExpression(TIntermTyped*& node) +{ + // binary_expression + if (! acceptBinaryExpression(node, PlLogicalOr)) + return false; + + if (! acceptTokenClass(EHTokQuestion)) + return true; + + node = parseContext.convertConditionalExpression(token.loc, node, false); + if (node == nullptr) + return false; + + ++parseContext.controlFlowNestingLevel; // this only needs to work right if no errors + + TIntermTyped* trueNode = nullptr; + if (! acceptExpression(trueNode)) { + expected("expression after ?"); + return false; + } + TSourceLoc loc = token.loc; + + if (! acceptTokenClass(EHTokColon)) { + expected(":"); + return false; + } + + TIntermTyped* falseNode = nullptr; + if (! acceptAssignmentExpression(falseNode)) { + expected("expression after :"); + return false; + } + + --parseContext.controlFlowNestingLevel; + + node = intermediate.addSelection(node, trueNode, falseNode, loc); + + return true; +} + // Accept a binary expression, for binary operations that // associate left-to-right. This is, it is implicit, for example // @@ -1574,12 +2898,12 @@ bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel pr if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1))) return false; - TOperator op = HlslOpMap::binary(peek()); - PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op); - if (tokenLevel < precedenceLevel) - return true; - do { + TOperator op = HlslOpMap::binary(peek()); + PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op); + if (tokenLevel < precedenceLevel) + return true; + // ... op TSourceLoc loc = token.loc; advanceToken(); @@ -1592,9 +2916,10 @@ bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel pr } node = intermediate.addBinaryMath(op, node, rightNode, loc); - - if (! peekTokenClass(EHTokComma)) - return true; + if (node == nullptr) { + parseContext.error(loc, "Could not perform requested binary operation", "", ""); + return false; + } } while (true); } @@ -1616,27 +2941,39 @@ bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node) if (acceptTokenClass(EHTokLeftParen)) { TType castType; if (acceptType(castType)) { - if (! acceptTokenClass(EHTokRightParen)) { - expected(")"); - return false; - } - - // We've matched "(type)" now, get the expression to cast + // recognize any array_specifier as part of the type + TArraySizes* arraySizes = nullptr; + acceptArraySpecifier(arraySizes); + if (arraySizes != nullptr) + castType.transferArraySizes(arraySizes); TSourceLoc loc = token.loc; - if (! acceptUnaryExpression(node)) - return false; + if (acceptTokenClass(EHTokRightParen)) { + // We've matched "(type)" now, get the expression to cast + if (! acceptUnaryExpression(node)) + return false; - // Hook it up like a constructor - TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType); - if (constructorFunction == nullptr) { - expected("type that can be constructed"); - return false; + // Hook it up like a constructor + TFunction* constructorFunction = parseContext.makeConstructorCall(loc, castType); + if (constructorFunction == nullptr) { + expected("type that can be constructed"); + return false; + } + TIntermTyped* arguments = nullptr; + parseContext.handleFunctionArgument(constructorFunction, arguments, node); + node = parseContext.handleFunctionCall(loc, constructorFunction, arguments); + + return node != nullptr; + } else { + // This could be a parenthesized constructor, ala (int(3)), and we just accepted + // the '(int' part. We must back up twice. + recedeToken(); + recedeToken(); + + // Note, there are no array constructors like + // (float[2](...)) + if (arraySizes != nullptr) + parseContext.error(loc, "parenthesized array constructor not allowed", "([]())", "", ""); } - TIntermTyped* arguments = nullptr; - parseContext.handleFunctionArgument(constructorFunction, arguments, node); - node = parseContext.handleFunctionCall(loc, constructorFunction, arguments); - - return true; } else { // This isn't a type cast, but it still started "(", so if it is a // unary expression, it can only be a postfix_expression, so try that. @@ -1648,7 +2985,7 @@ bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node) // peek for "op unary_expression" TOperator unaryOp = HlslOpMap::preUnary(peek()); - + // postfix_expression (if no unary operator) if (unaryOp == EOpNull) return acceptPostfixExpression(node); @@ -1665,6 +3002,10 @@ bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node) node = intermediate.addUnaryMath(unaryOp, node, loc); + // These unary ops require lvalues + if (unaryOp == EOpPreIncrement || unaryOp == EOpPreDecrement) + node = parseContext.handleLvalue(loc, "unary operator", node); + return node != nullptr; } @@ -1672,17 +3013,19 @@ bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node) // : LEFT_PAREN expression RIGHT_PAREN // | literal // | constructor -// | identifier +// | IDENTIFIER [ COLONCOLON IDENTIFIER [ COLONCOLON IDENTIFIER ... ] ] // | function_call // | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET // | postfix_expression DOT IDENTIFIER +// | postfix_expression DOT IDENTIFIER arguments +// | postfix_expression arguments // | postfix_expression INC_OP // | postfix_expression DEC_OP // bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node) { // Not implemented as self-recursive: - // The logical "right recursion" is done with an loop at the end + // The logical "right recursion" is done with a loop at the end // idToken will pick up either a variable or a function name in a function call HlslToken idToken; @@ -1700,14 +3043,28 @@ bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node) return false; } } else if (acceptLiteral(node)) { - // literal (nothing else to do yet), go on to the + // literal (nothing else to do yet) } else if (acceptConstructor(node)) { // constructor (nothing else to do yet) } else if (acceptIdentifier(idToken)) { - // identifier or function_call name + // user-type, namespace name, variable, or function name + TString* fullName = idToken.string; + while (acceptTokenClass(EHTokColonColon)) { + // user-type or namespace name + fullName = NewPoolTString(fullName->c_str()); + fullName->append(parseContext.scopeMangler); + if (acceptIdentifier(idToken)) + fullName->append(*idToken.string); + else { + expected("identifier after ::"); + return false; + } + } if (! peekTokenClass(EHTokLeftParen)) { - node = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string); - } else if (acceptFunctionCall(idToken, node)) { + node = parseContext.handleVariable(idToken.loc, fullName); + if (node == nullptr) + return false; + } else if (acceptFunctionCall(idToken.loc, *fullName, node, nullptr)) { // function_call (nothing else to do yet) } else { expected("function call arguments"); @@ -1729,6 +3086,7 @@ bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node) case EOpIndexIndirect: case EOpPostIncrement: case EOpPostDecrement: + case EOpScoping: advanceToken(); break; default: @@ -1737,26 +3095,28 @@ bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node) // We have a valid post-unary operator, process it. switch (postOp) { + case EOpScoping: case EOpIndexDirectStruct: { // DOT IDENTIFIER - // includes swizzles and struct members + // includes swizzles, member variables, and member functions HlslToken field; if (! acceptIdentifier(field)) { expected("swizzle or member"); return false; } - TIntermTyped* base = node; // preserve for method function calls - node = parseContext.handleDotDereference(field.loc, node, *field.string); + if (peekTokenClass(EHTokLeftParen)) { + // member function + TIntermTyped* thisNode = node; - // In the event of a method node, we look for an open paren and accept the function call. - if (node->getAsMethodNode() != nullptr && peekTokenClass(EHTokLeftParen)) { - if (! acceptFunctionCall(field, node, base)) { + // arguments + if (! acceptFunctionCall(field.loc, *field.string, node, thisNode)) { expected("function parameters"); return false; } - } + } else + node = parseContext.handleDotDereference(field.loc, node, *field.string); break; } @@ -1771,6 +3131,8 @@ bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node) } advanceToken(); node = parseContext.handleBracketDereference(indexNode->getLoc(), node, indexNode); + if (node == nullptr) + return false; break; } case EOpPostIncrement: @@ -1779,6 +3141,7 @@ bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node) case EOpPostDecrement: // DEC_OP node = intermediate.addUnaryMath(postOp, node, loc); + node = parseContext.handleLvalue(loc, "unary operator", node); break; default: assert(0); @@ -1795,21 +3158,23 @@ bool HlslGrammar::acceptConstructor(TIntermTyped*& node) // type TType type; if (acceptType(type)) { - TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type); + TFunction* constructorFunction = parseContext.makeConstructorCall(token.loc, type); if (constructorFunction == nullptr) return false; // arguments TIntermTyped* arguments = nullptr; if (! acceptArguments(constructorFunction, arguments)) { - expected("constructor arguments"); + // It's possible this is a type keyword used as an identifier. Put the token back + // for later use. + recedeToken(); return false; } // hook it up node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments); - return true; + return node != nullptr; } return false; @@ -1820,22 +3185,44 @@ bool HlslGrammar::acceptConstructor(TIntermTyped*& node) // function_call // : [idToken] arguments // -bool HlslGrammar::acceptFunctionCall(HlslToken idToken, TIntermTyped*& node, TIntermTyped* base) +bool HlslGrammar::acceptFunctionCall(const TSourceLoc& loc, TString& name, TIntermTyped*& node, TIntermTyped* baseObject) { + // name + TString* functionName = nullptr; + if (baseObject == nullptr) { + functionName = &name; + } else if (parseContext.isBuiltInMethod(loc, baseObject, name)) { + // Built-in methods are not in the symbol table as methods, but as global functions + // taking an explicit 'this' as the first argument. + functionName = NewPoolTString(BUILTIN_PREFIX); + functionName->append(name); + } else { + if (! baseObject->getType().isStruct()) { + expected("structure"); + return false; + } + functionName = NewPoolTString(""); + functionName->append(baseObject->getType().getTypeName()); + parseContext.addScopeMangler(*functionName); + functionName->append(name); + } + + // function + TFunction* function = new TFunction(functionName, TType(EbtVoid)); + // arguments - TFunction* function = new TFunction(idToken.string, TType(EbtVoid)); TIntermTyped* arguments = nullptr; - - // methods have an implicit first argument of the calling object. - if (base != nullptr) - parseContext.handleFunctionArgument(function, arguments, base); - + if (baseObject != nullptr) { + // Non-static member functions have an implicit first argument of the base object. + parseContext.handleFunctionArgument(function, arguments, baseObject); + } if (! acceptArguments(function, arguments)) return false; - node = parseContext.handleFunctionCall(idToken.loc, function, arguments); + // call + node = parseContext.handleFunctionCall(loc, function, arguments); - return true; + return node != nullptr; } // arguments @@ -1850,11 +3237,16 @@ bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments) if (! acceptTokenClass(EHTokLeftParen)) return false; + // RIGHT_PAREN + if (acceptTokenClass(EHTokRightParen)) + return true; + + // must now be at least one expression... do { // expression TIntermTyped* arg; if (! acceptAssignmentExpression(arg)) - break; + return false; // hook it up parseContext.handleFunctionArgument(function, arguments, arg); @@ -1879,6 +3271,12 @@ bool HlslGrammar::acceptLiteral(TIntermTyped*& node) case EHTokIntConstant: node = intermediate.addConstantUnion(token.i, token.loc, true); break; + case EHTokUintConstant: + node = intermediate.addConstantUnion(token.u, token.loc, true); + break; + case EHTokFloat16Constant: + node = intermediate.addConstantUnion(token.d, EbtFloat16, token.loc, true); + break; case EHTokFloatConstant: node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true); break; @@ -1888,6 +3286,9 @@ bool HlslGrammar::acceptLiteral(TIntermTyped*& node) case EHTokBoolConstant: node = intermediate.addConstantUnion(token.b, token.loc, true); break; + case EHTokStringConstant: + node = intermediate.addConstantUnion(token.string, token.loc, true); + break; default: return false; @@ -1898,6 +3299,37 @@ bool HlslGrammar::acceptLiteral(TIntermTyped*& node) return true; } +// simple_statement +// : SEMICOLON +// | declaration_statement +// | expression SEMICOLON +// +bool HlslGrammar::acceptSimpleStatement(TIntermNode*& statement) +{ + // SEMICOLON + if (acceptTokenClass(EHTokSemicolon)) + return true; + + // declaration + if (acceptDeclaration(statement)) + return true; + + // expression + TIntermTyped* node; + if (acceptExpression(node)) + statement = node; + else + return false; + + // SEMICOLON (following an expression) + if (acceptTokenClass(EHTokSemicolon)) + return true; + else { + expected(";"); + return false; + } +} + // compound_statement // : LEFT_CURLY statement statement ... RIGHT_CURLY // @@ -1955,12 +3387,11 @@ bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement) // // attributed_statement // : compound_statement -// | SEMICOLON -// | expression SEMICOLON -// | declaration_statement +// | simple_statement // | selection_statement // | switch_statement // | case_label +// | default_label // | iteration_statement // | jump_statement // @@ -1969,7 +3400,8 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement) statement = nullptr; // attributes - acceptAttributes(); + TAttributes attributes; + acceptAttributes(attributes); // attributed_statement switch (peek()) { @@ -1977,15 +3409,15 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement) return acceptScopedCompoundStatement(statement); case EHTokIf: - return acceptSelectionStatement(statement); + return acceptSelectionStatement(statement, attributes); case EHTokSwitch: - return acceptSwitchStatement(statement); + return acceptSwitchStatement(statement, attributes); case EHTokFor: case EHTokDo: case EHTokWhile: - return acceptIterationStatement(statement); + return acceptIterationStatement(statement, attributes); case EHTokContinue: case EHTokBreak: @@ -1998,40 +3430,28 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement) case EHTokDefault: return acceptDefaultLabel(statement); - case EHTokSemicolon: - return acceptTokenClass(EHTokSemicolon); - case EHTokRightBrace: // Performance: not strictly necessary, but stops a bunch of hunting early, // and is how sequences of statements end. return false; default: - { - // declaration - if (acceptDeclaration(statement)) - return true; - - // expression - TIntermTyped* node; - if (acceptExpression(node)) - statement = node; - else - return false; - - // SEMICOLON (following an expression) - if (! acceptTokenClass(EHTokSemicolon)) { - expected(";"); - return false; - } - } + return acceptSimpleStatement(statement); } return true; } // attributes -// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET +// : [zero or more:] bracketed-attribute +// +// bracketed-attribute: +// : LEFT_BRACKET scoped-attribute RIGHT_BRACKET +// : LEFT_BRACKET LEFT_BRACKET scoped-attribute RIGHT_BRACKET RIGHT_BRACKET +// +// scoped-attribute: +// : attribute +// | namespace COLON COLON attribute // // attribute: // : UNROLL @@ -2042,42 +3462,97 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement) // | FLATTEN // | FORCECASE // | CALL +// | DOMAIN +// | EARLYDEPTHSTENCIL +// | INSTANCE +// | MAXTESSFACTOR +// | OUTPUTCONTROLPOINTS +// | OUTPUTTOPOLOGY +// | PARTITIONING +// | PATCHCONSTANTFUNC +// | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN // -void HlslGrammar::acceptAttributes() +void HlslGrammar::acceptAttributes(TAttributes& attributes) { - // For now, accept the [ XXX(X) ] syntax, but drop. + // For now, accept the [ XXX(X) ] syntax, but drop all but + // numthreads, which is used to set the CS local size. // TODO: subset to correct set? Pass on? do { + HlslToken attributeToken; + // LEFT_BRACKET? if (! acceptTokenClass(EHTokLeftBracket)) return; + // another LEFT_BRACKET? + bool doubleBrackets = false; + if (acceptTokenClass(EHTokLeftBracket)) + doubleBrackets = true; - // attribute - if (peekTokenClass(EHTokIdentifier)) { - // 'token.string' is the attribute - advanceToken(); - } else if (! peekTokenClass(EHTokRightBracket)) { - expected("identifier"); - advanceToken(); + // attribute? (could be namespace; will adjust later) + if (!acceptIdentifier(attributeToken)) { + if (!peekTokenClass(EHTokRightBracket)) { + expected("namespace or attribute identifier"); + advanceToken(); + } } - // (x) + TString nameSpace; + if (acceptTokenClass(EHTokColonColon)) { + // namespace COLON COLON + nameSpace = *attributeToken.string; + // attribute + if (!acceptIdentifier(attributeToken)) { + expected("attribute identifier"); + return; + } + } + + TIntermAggregate* expressions = nullptr; + + // (x, ...) if (acceptTokenClass(EHTokLeftParen)) { + expressions = new TIntermAggregate; + TIntermTyped* node; - if (! acceptLiteral(node)) - expected("literal"); - // 'node' has the literal in it + bool expectingExpression = false; + + while (acceptAssignmentExpression(node)) { + expectingExpression = false; + expressions->getSequence().push_back(node); + if (acceptTokenClass(EHTokComma)) + expectingExpression = true; + } + + // 'expressions' is an aggregate with the expressions in it if (! acceptTokenClass(EHTokRightParen)) expected(")"); + + // Error for partial or missing expression + if (expectingExpression || expressions->getSequence().empty()) + expected("expression"); } // RIGHT_BRACKET - if (acceptTokenClass(EHTokRightBracket)) - continue; - - expected("]"); - return; + if (!acceptTokenClass(EHTokRightBracket)) { + expected("]"); + return; + } + // another RIGHT_BRACKET? + if (doubleBrackets && !acceptTokenClass(EHTokRightBracket)) { + expected("]]"); + return; + } + // Add any values we found into the attribute map. + if (attributeToken.string != nullptr) { + TAttributeType attributeType = parseContext.attributeFromName(nameSpace, *attributeToken.string); + if (attributeType == EatNone) + parseContext.warn(attributeToken.loc, "unrecognized attribute", attributeToken.string->c_str(), ""); + else { + TAttributeArgs attributeArgs = { attributeType, expressions }; + attributes.push_back(attributeArgs); + } + } } while (true); } @@ -2085,7 +3560,7 @@ void HlslGrammar::acceptAttributes() // : IF LEFT_PAREN expression RIGHT_PAREN statement // : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement // -bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement) +bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttributes& attributes) { TSourceLoc loc = token.loc; @@ -2101,10 +3576,15 @@ bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement) TIntermTyped* condition; if (! acceptParenExpression(condition)) return false; + condition = parseContext.convertConditionalExpression(loc, condition); + if (condition == nullptr) + return false; // create the child statements TIntermNodePair thenElse = { nullptr, nullptr }; + ++parseContext.controlFlowNestingLevel; // this only needs to work right if no errors + // then statement if (! acceptScopedStatement(thenElse.node1)) { expected("then statement"); @@ -2122,7 +3602,10 @@ bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement) // Put the pieces together statement = intermediate.addSelection(condition, thenElse, loc); + parseContext.handleSelectionAttributes(loc, statement->getAsSelectionNode(), attributes); + parseContext.popScope(); + --parseContext.controlFlowNestingLevel; return true; } @@ -2130,10 +3613,11 @@ bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement) // switch_statement // : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement // -bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement) +bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttributes& attributes) { // SWITCH TSourceLoc loc = token.loc; + if (! acceptTokenClass(EHTokSwitch)) return false; @@ -2147,9 +3631,14 @@ bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement) // compound_statement parseContext.pushSwitchSequence(new TIntermSequence); + + ++parseContext.controlFlowNestingLevel; bool statementOkay = acceptCompoundStatement(statement); + --parseContext.controlFlowNestingLevel; + if (statementOkay) - statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr); + statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr, + attributes); parseContext.popSwitchSequence(); parseContext.popScope(); @@ -2163,7 +3652,7 @@ bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement) // | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement // // Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen. -bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement) +bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttributes& attributes) { TSourceLoc loc = token.loc; TIntermTyped* condition = nullptr; @@ -2174,16 +3663,21 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement) // WHILE or DO or FOR advanceToken(); + TIntermLoop* loopNode = nullptr; switch (loop) { case EHTokWhile: // so that something declared in the condition is scoped to the lifetime // of the while sub-statement - parseContext.pushScope(); + parseContext.pushScope(); // this only needs to work right if no errors parseContext.nestLooping(); + ++parseContext.controlFlowNestingLevel; // LEFT_PAREN condition RIGHT_PAREN if (! acceptParenExpression(condition)) return false; + condition = parseContext.convertConditionalExpression(loc, condition); + if (condition == nullptr) + return false; // statement if (! acceptScopedStatement(statement)) { @@ -2193,26 +3687,22 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement) parseContext.unnestLooping(); parseContext.popScope(); + --parseContext.controlFlowNestingLevel; - statement = intermediate.addLoop(statement, condition, nullptr, true, loc); - - return true; + loopNode = intermediate.addLoop(statement, condition, nullptr, true, loc); + statement = loopNode; + break; case EHTokDo: - parseContext.nestLooping(); - - if (! acceptTokenClass(EHTokLeftBrace)) - expected("{"); + parseContext.nestLooping(); // this only needs to work right if no errors + ++parseContext.controlFlowNestingLevel; // statement - if (! peekTokenClass(EHTokRightBrace) && ! acceptScopedStatement(statement)) { + if (! acceptScopedStatement(statement)) { expected("do sub-statement"); return false; } - if (! acceptTokenClass(EHTokRightBrace)) - expected("}"); - // WHILE if (! acceptTokenClass(EHTokWhile)) { expected("while"); @@ -2220,18 +3710,21 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement) } // LEFT_PAREN condition RIGHT_PAREN - TIntermTyped* condition; if (! acceptParenExpression(condition)) return false; + condition = parseContext.convertConditionalExpression(loc, condition); + if (condition == nullptr) + return false; if (! acceptTokenClass(EHTokSemicolon)) expected(";"); parseContext.unnestLooping(); + --parseContext.controlFlowNestingLevel; - statement = intermediate.addLoop(statement, condition, 0, false, loc); - - return true; + loopNode = intermediate.addLoop(statement, condition, 0, false, loc); + statement = loopNode; + break; case EHTokFor: { @@ -2245,21 +3738,21 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement) // initializer TIntermNode* initNode = nullptr; - if (! acceptControlDeclaration(initNode)) { - TIntermTyped* initExpr = nullptr; - acceptExpression(initExpr); - initNode = initExpr; - } - // SEMI_COLON - if (! acceptTokenClass(EHTokSemicolon)) - expected(";"); + if (! acceptSimpleStatement(initNode)) + expected("for-loop initializer statement"); - parseContext.nestLooping(); + parseContext.nestLooping(); // this only needs to work right if no errors + ++parseContext.controlFlowNestingLevel; // condition SEMI_COLON acceptExpression(condition); if (! acceptTokenClass(EHTokSemicolon)) expected(";"); + if (condition != nullptr) { + condition = parseContext.convertConditionalExpression(loc, condition); + if (condition == nullptr) + return false; + } // iterator SEMI_COLON TIntermTyped* iterator = nullptr; @@ -2273,17 +3766,21 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement) return false; } - statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc); + statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc, loopNode); parseContext.popScope(); parseContext.unnestLooping(); + --parseContext.controlFlowNestingLevel; - return true; + break; } default: return false; } + + parseContext.handleLoopAttributes(loc, loopNode, attributes); + return true; } // jump_statement @@ -2311,9 +3808,17 @@ bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement) switch (jump) { case EHTokContinue: statement = intermediate.addBranch(EOpContinue, token.loc); + if (parseContext.loopNestingLevel == 0) { + expected("loop"); + return false; + } break; case EHTokBreak: statement = intermediate.addBranch(EOpBreak, token.loc); + if (parseContext.loopNestingLevel == 0 && parseContext.switchSequenceStack.size() == 0) { + expected("loop or switch"); + return false; + } break; case EHTokDiscard: statement = intermediate.addBranch(EOpKill, token.loc); @@ -2325,7 +3830,7 @@ bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement) TIntermTyped* node; if (acceptExpression(node)) { // hook it up - statement = intermediate.addBranch(EOpReturn, node, token.loc); + statement = parseContext.handleReturnValue(token.loc, node); } else statement = intermediate.addBranch(EOpReturn, token.loc); break; @@ -2339,7 +3844,7 @@ bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement) // SEMICOLON if (! acceptTokenClass(EHTokSemicolon)) expected(";"); - + return true; } @@ -2388,95 +3893,228 @@ bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement) } // array_specifier -// : LEFT_BRACKET integer_expression RGHT_BRACKET post_decls // optional +// : LEFT_BRACKET integer_expression RGHT_BRACKET ... // optional +// : LEFT_BRACKET RGHT_BRACKET // optional // void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes) { arraySizes = nullptr; - if (! acceptTokenClass(EHTokLeftBracket)) + // Early-out if there aren't any array dimensions + if (!peekTokenClass(EHTokLeftBracket)) return; - TSourceLoc loc = token.loc; - TIntermTyped* sizeExpr; - if (! acceptAssignmentExpression(sizeExpr)) { - expected("array-sizing expression"); - return; - } - - if (! acceptTokenClass(EHTokRightBracket)) { - expected("]"); - return; - } - - TArraySize arraySize; - parseContext.arraySizeCheck(loc, sizeExpr, arraySize); + // If we get here, we have at least one array dimension. This will track the sizes we find. arraySizes = new TArraySizes; - arraySizes->addInnerSize(arraySize); + + // Collect each array dimension. + while (acceptTokenClass(EHTokLeftBracket)) { + TSourceLoc loc = token.loc; + TIntermTyped* sizeExpr = nullptr; + + // Array sizing expression is optional. If omitted, array will be later sized by initializer list. + const bool hasArraySize = acceptAssignmentExpression(sizeExpr); + + if (! acceptTokenClass(EHTokRightBracket)) { + expected("]"); + return; + } + + if (hasArraySize) { + TArraySize arraySize; + parseContext.arraySizeCheck(loc, sizeExpr, arraySize); + arraySizes->addInnerSize(arraySize); + } else { + arraySizes->addInnerSize(0); // sized by initializers. + } + } } // post_decls -// : COLON semantic // optional -// COLON PACKOFFSET LEFT_PAREN ... RIGHT_PAREN // optional -// COLON REGISTER // optional -// annotations // optional +// : COLON semantic // optional +// COLON PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN // optional +// COLON REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN // optional +// COLON LAYOUT layout_qualifier_list +// annotations // optional // -void HlslGrammar::acceptPostDecls(TType& type) +// Return true if any tokens were accepted. That is, +// false can be returned on successfully recognizing nothing, +// not necessarily meaning bad syntax. +// +bool HlslGrammar::acceptPostDecls(TQualifier& qualifier) { + bool found = false; + do { - // COLON + // COLON if (acceptTokenClass(EHTokColon)) { + found = true; HlslToken idToken; - if (acceptTokenClass(EHTokPackOffset)) { + if (peekTokenClass(EHTokLayout)) + acceptLayoutQualifierList(qualifier); + else if (acceptTokenClass(EHTokPackOffset)) { + // PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN if (! acceptTokenClass(EHTokLeftParen)) { expected("("); - return; + return false; + } + HlslToken locationToken; + if (! acceptIdentifier(locationToken)) { + expected("c[subcomponent][.component]"); + return false; + } + HlslToken componentToken; + if (acceptTokenClass(EHTokDot)) { + if (! acceptIdentifier(componentToken)) { + expected("component"); + return false; + } } - acceptTokenClass(EHTokIdentifier); - acceptTokenClass(EHTokDot); - acceptTokenClass(EHTokIdentifier); if (! acceptTokenClass(EHTokRightParen)) { expected(")"); break; } - // TODO: process the packoffset information + parseContext.handlePackOffset(locationToken.loc, qualifier, *locationToken.string, componentToken.string); } else if (! acceptIdentifier(idToken)) { - expected("semantic or packoffset or register"); - return; + expected("layout, semantic, packoffset, or register"); + return false; } else if (*idToken.string == "register") { + // REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN + // LEFT_PAREN if (! acceptTokenClass(EHTokLeftParen)) { expected("("); - return; + return false; } - acceptTokenClass(EHTokIdentifier); - acceptTokenClass(EHTokComma); - acceptTokenClass(EHTokIdentifier); - acceptTokenClass(EHTokLeftBracket); - if (peekTokenClass(EHTokIntConstant)) + HlslToken registerDesc; // for Type# + HlslToken profile; + if (! acceptIdentifier(registerDesc)) { + expected("register number description"); + return false; + } + if (registerDesc.string->size() > 1 && !isdigit((*registerDesc.string)[1]) && + acceptTokenClass(EHTokComma)) { + // Then we didn't really see the registerDesc yet, it was + // actually the profile. Adjust... + profile = registerDesc; + if (! acceptIdentifier(registerDesc)) { + expected("register number description"); + return false; + } + } + int subComponent = 0; + if (acceptTokenClass(EHTokLeftBracket)) { + // LEFT_BRACKET subcomponent RIGHT_BRACKET + if (! peekTokenClass(EHTokIntConstant)) { + expected("literal integer"); + return false; + } + subComponent = token.i; advanceToken(); - acceptTokenClass(EHTokRightBracket); + if (! acceptTokenClass(EHTokRightBracket)) { + expected("]"); + break; + } + } + // (COMMA SPACEN)opt + HlslToken spaceDesc; + if (acceptTokenClass(EHTokComma)) { + if (! acceptIdentifier(spaceDesc)) { + expected ("space identifier"); + return false; + } + } + // RIGHT_PAREN if (! acceptTokenClass(EHTokRightParen)) { expected(")"); break; } - // TODO: process the register information + parseContext.handleRegister(registerDesc.loc, qualifier, profile.string, *registerDesc.string, subComponent, spaceDesc.string); } else { // semantic, in idToken.string - parseContext.handleSemantic(type, *idToken.string); + TString semanticUpperCase = *idToken.string; + std::transform(semanticUpperCase.begin(), semanticUpperCase.end(), semanticUpperCase.begin(), ::toupper); + parseContext.handleSemantic(idToken.loc, qualifier, mapSemantic(semanticUpperCase.c_str()), semanticUpperCase); } - } else if (acceptTokenClass(EHTokLeftAngle)) { - // TODO: process annotations, just accepting them for now - do { - if (peekTokenClass(EHTokNone)) - return; - if (acceptTokenClass(EHTokRightAngle)) - break; - advanceToken(); - } while (true); + } else if (peekTokenClass(EHTokLeftAngle)) { + found = true; + acceptAnnotations(qualifier); } else break; } while (true); + + return found; +} + +// +// Get the stream of tokens from the scanner, but skip all syntactic/semantic +// processing. +// +bool HlslGrammar::captureBlockTokens(TVector& tokens) +{ + if (! peekTokenClass(EHTokLeftBrace)) + return false; + + int braceCount = 0; + + do { + switch (peek()) { + case EHTokLeftBrace: + ++braceCount; + break; + case EHTokRightBrace: + --braceCount; + break; + case EHTokNone: + // End of input before balance { } is bad... + return false; + default: + break; + } + + tokens.push_back(token); + advanceToken(); + } while (braceCount > 0); + + return true; +} + +// Return a string for just the types that can also be declared as an identifier. +const char* HlslGrammar::getTypeString(EHlslTokenClass tokenClass) const +{ + switch (tokenClass) { + case EHTokSample: return "sample"; + case EHTokHalf: return "half"; + case EHTokHalf1x1: return "half1x1"; + case EHTokHalf1x2: return "half1x2"; + case EHTokHalf1x3: return "half1x3"; + case EHTokHalf1x4: return "half1x4"; + case EHTokHalf2x1: return "half2x1"; + case EHTokHalf2x2: return "half2x2"; + case EHTokHalf2x3: return "half2x3"; + case EHTokHalf2x4: return "half2x4"; + case EHTokHalf3x1: return "half3x1"; + case EHTokHalf3x2: return "half3x2"; + case EHTokHalf3x3: return "half3x3"; + case EHTokHalf3x4: return "half3x4"; + case EHTokHalf4x1: return "half4x1"; + case EHTokHalf4x2: return "half4x2"; + case EHTokHalf4x3: return "half4x3"; + case EHTokHalf4x4: return "half4x4"; + case EHTokBool: return "bool"; + case EHTokFloat: return "float"; + case EHTokDouble: return "double"; + case EHTokInt: return "int"; + case EHTokUint: return "uint"; + case EHTokMin16float: return "min16float"; + case EHTokMin10float: return "min10float"; + case EHTokMin16int: return "min16int"; + case EHTokMin12int: return "min12int"; + case EHTokConstantBuffer: return "ConstantBuffer"; + case EHTokLayout: return "layout"; + default: + return nullptr; + } } } // end namespace glslang diff --git a/Externals/glslang/hlsl/hlslGrammar.h b/Externals/glslang/hlsl/hlslGrammar.h index 9f224fef56..046f7957e5 100755 --- a/Externals/glslang/hlsl/hlslGrammar.h +++ b/Externals/glslang/hlsl/hlslGrammar.h @@ -1,12 +1,12 @@ // -//Copyright (C) 2016 Google, Inc. -//Copyright (C) 2016 LunarG, Inc. +// Copyright (C) 2016 Google, Inc. +// Copyright (C) 2016 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,18 +20,18 @@ // 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. +// 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 HLSLGRAMMAR_H_ @@ -43,13 +43,16 @@ namespace glslang { + class TFunctionDeclarator; + // Should just be the grammar aspect of HLSL. // Described in more detail in hlslGrammar.cpp. class HlslGrammar : public HlslTokenStream { public: HlslGrammar(HlslScanContext& scanner, HlslParseContext& parseContext) - : HlslTokenStream(scanner), parseContext(parseContext), intermediate(parseContext.intermediate) { } + : HlslTokenStream(scanner), parseContext(parseContext), intermediate(parseContext.intermediate), + typeIdentifiers(false) { } virtual ~HlslGrammar() { } bool parse(); @@ -62,51 +65,74 @@ namespace glslang { void unimplemented(const char*); bool acceptIdentifier(HlslToken&); bool acceptCompilationUnit(); - bool acceptDeclaration(TIntermNode*& node); + bool acceptDeclarationList(TIntermNode*&); + bool acceptDeclaration(TIntermNode*&); bool acceptControlDeclaration(TIntermNode*& node); bool acceptSamplerDeclarationDX9(TType&); bool acceptSamplerState(); - bool acceptFullySpecifiedType(TType&); - void acceptQualifier(TQualifier&); + bool acceptFullySpecifiedType(TType&, const TAttributes&); + bool acceptFullySpecifiedType(TType&, TIntermNode*& nodeList, const TAttributes&, bool forbidDeclarators = false); + bool acceptQualifier(TQualifier&); + bool acceptLayoutQualifierList(TQualifier&); bool acceptType(TType&); - bool acceptTemplateType(TBasicType&); + bool acceptType(TType&, TIntermNode*& nodeList); + bool acceptTemplateVecMatBasicType(TBasicType&); bool acceptVectorTemplateType(TType&); bool acceptMatrixTemplateType(TType&); + bool acceptTessellationDeclType(TBuiltInVariable&); + bool acceptTessellationPatchTemplateType(TType&); + bool acceptStreamOutTemplateType(TType&, TLayoutGeometry&); + bool acceptOutputPrimitiveGeometry(TLayoutGeometry&); + bool acceptAnnotations(TQualifier&); bool acceptSamplerType(TType&); bool acceptTextureType(TType&); - bool acceptStruct(TType&); - bool acceptStructDeclarationList(TTypeList*&); + bool acceptSubpassInputType(TType&); + bool acceptStructBufferType(TType&); + bool acceptTextureBufferType(TType&); + bool acceptConstantBufferType(TType&); + bool acceptStruct(TType&, TIntermNode*& nodeList); + bool acceptStructDeclarationList(TTypeList*&, TIntermNode*& nodeList, TVector&); + bool acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TType&, TString& memberName, + TFunctionDeclarator&); bool acceptFunctionParameters(TFunction&); bool acceptParameterDeclaration(TFunction&); - bool acceptFunctionDefinition(TFunction&, TIntermNode*&); + bool acceptFunctionDefinition(TFunctionDeclarator&, TIntermNode*& nodeList, TVector* deferredTokens); + bool acceptFunctionBody(TFunctionDeclarator& declarator, TIntermNode*& nodeList); bool acceptParenExpression(TIntermTyped*&); bool acceptExpression(TIntermTyped*&); bool acceptInitializer(TIntermTyped*&); bool acceptAssignmentExpression(TIntermTyped*&); + bool acceptConditionalExpression(TIntermTyped*&); bool acceptBinaryExpression(TIntermTyped*&, PrecedenceLevel); bool acceptUnaryExpression(TIntermTyped*&); bool acceptPostfixExpression(TIntermTyped*&); bool acceptConstructor(TIntermTyped*&); - bool acceptFunctionCall(HlslToken, TIntermTyped*&, TIntermTyped* base = nullptr); + bool acceptFunctionCall(const TSourceLoc&, TString& name, TIntermTyped*&, TIntermTyped* objectBase); bool acceptArguments(TFunction*, TIntermTyped*&); bool acceptLiteral(TIntermTyped*&); + bool acceptSimpleStatement(TIntermNode*&); bool acceptCompoundStatement(TIntermNode*&); - bool acceptStatement(TIntermNode*&); bool acceptScopedStatement(TIntermNode*&); bool acceptScopedCompoundStatement(TIntermNode*&); + bool acceptStatement(TIntermNode*&); bool acceptNestedStatement(TIntermNode*&); - void acceptAttributes(); - bool acceptSelectionStatement(TIntermNode*&); - bool acceptSwitchStatement(TIntermNode*&); - bool acceptIterationStatement(TIntermNode*&); + void acceptAttributes(TAttributes&); + bool acceptSelectionStatement(TIntermNode*&, const TAttributes&); + bool acceptSwitchStatement(TIntermNode*&, const TAttributes&); + bool acceptIterationStatement(TIntermNode*&, const TAttributes&); bool acceptJumpStatement(TIntermNode*&); bool acceptCaseLabel(TIntermNode*&); bool acceptDefaultLabel(TIntermNode*&); void acceptArraySpecifier(TArraySizes*&); - void acceptPostDecls(TType&); + bool acceptPostDecls(TQualifier&); + bool acceptDefaultParameterDeclaration(const TType&, TIntermTyped*&); + + bool captureBlockTokens(TVector& tokens); + const char* getTypeString(EHlslTokenClass tokenClass) const; HlslParseContext& parseContext; // state of parsing and helper functions for building the intermediate TIntermediate& intermediate; // the final product, the intermediate representation, includes the AST + bool typeIdentifiers; // shader uses some types as identifiers }; } // end namespace glslang diff --git a/Externals/glslang/hlsl/hlslOpMap.cpp b/Externals/glslang/hlsl/hlslOpMap.cpp index 524e66a2a2..ebe6fbd96c 100755 --- a/Externals/glslang/hlsl/hlslOpMap.cpp +++ b/Externals/glslang/hlsl/hlslOpMap.cpp @@ -1,11 +1,11 @@ // -//Copyright (C) 2016 Google, Inc. +// Copyright (C) 2016 Google, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,18 +19,18 @@ // 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. +// 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. // // Map from physical token form (e.g. '-') to logical operator @@ -99,7 +99,7 @@ TOperator HlslOpMap::preUnary(EHlslTokenClass op) case EHTokDash: return EOpNegative; case EHTokBang: return EOpLogicalNot; case EHTokTilde: return EOpBitwiseNot; - + case EHTokIncOp: return EOpPreIncrement; case EHTokDecOp: return EOpPreDecrement; @@ -114,10 +114,12 @@ TOperator HlslOpMap::postUnary(EHlslTokenClass op) switch (op) { case EHTokDot: return EOpIndexDirectStruct; case EHTokLeftBracket: return EOpIndexIndirect; - + case EHTokIncOp: return EOpPostIncrement; case EHTokDecOp: return EOpPostDecrement; + case EHTokColonColon: return EOpScoping; + default: return EOpNull; // means not a post-unary op } } diff --git a/Externals/glslang/hlsl/hlslOpMap.h b/Externals/glslang/hlsl/hlslOpMap.h index 924637878c..4e783f3f0c 100755 --- a/Externals/glslang/hlsl/hlslOpMap.h +++ b/Externals/glslang/hlsl/hlslOpMap.h @@ -1,11 +1,11 @@ // -//Copyright (C) 2016 Google, Inc. +// Copyright (C) 2016 Google, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,18 +19,18 @@ // 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. +// 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 HLSLOPMAP_H_ diff --git a/Externals/glslang/hlsl/hlslParseHelper.cpp b/Externals/glslang/hlsl/hlslParseHelper.cpp index b7b70007d8..d80f356b55 100755 --- a/Externals/glslang/hlsl/hlslParseHelper.cpp +++ b/Externals/glslang/hlsl/hlslParseHelper.cpp @@ -1,12 +1,12 @@ // -//Copyright (C) 2016 Google, Inc. -//Copyright (C) 2016 LunarG, Inc. +// Copyright (C) 2017 Google, Inc. +// Copyright (C) 2017 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,58 +20,73 @@ // 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. +// 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. // #include "hlslParseHelper.h" #include "hlslScanContext.h" #include "hlslGrammar.h" +#include "hlslAttributes.h" #include "../glslang/MachineIndependent/Scan.h" #include "../glslang/MachineIndependent/preprocessor/PpContext.h" #include "../glslang/OSDependent/osinclude.h" -#include #include +#include +#include +#include +#include namespace glslang { -HlslParseContext::HlslParseContext(TSymbolTable& symbolTable, TIntermediate& interm, bool /*parsingBuiltins*/, - int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TInfoSink& infoSink, +HlslParseContext::HlslParseContext(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins, + int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, + TInfoSink& infoSink, + const TString sourceEntryPointName, bool forwardCompatible, EShMessages messages) : - TParseContextBase(symbolTable, interm, version, profile, spvVersion, language, infoSink, forwardCompatible, messages), - contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), - postMainReturn(false), - limits(resources.limits), - afterEOF(false) + TParseContextBase(symbolTable, interm, parsingBuiltins, version, profile, spvVersion, language, infoSink, + forwardCompatible, messages, &sourceEntryPointName), + annotationNestingLevel(0), + inputPatch(nullptr), + nextInLocation(0), nextOutLocation(0), + entryPointFunction(nullptr), + entryPointFunctionBody(nullptr), + gsStreamOutput(nullptr), + clipDistanceOutput(nullptr), + cullDistanceOutput(nullptr), + clipDistanceInput(nullptr), + cullDistanceInput(nullptr) { - // ensure we always have a linkage node, even if empty, to simplify tree topology algorithms - linkage = new TIntermAggregate; - globalUniformDefaults.clear(); - globalUniformDefaults.layoutMatrix = ElmColumnMajor; + globalUniformDefaults.layoutMatrix = ElmRowMajor; globalUniformDefaults.layoutPacking = ElpStd140; globalBufferDefaults.clear(); - globalBufferDefaults.layoutMatrix = ElmColumnMajor; + globalBufferDefaults.layoutMatrix = ElmRowMajor; globalBufferDefaults.layoutPacking = ElpStd430; globalInputDefaults.clear(); globalOutputDefaults.clear(); - // "Shaders in the transform + clipSemanticNSizeIn.fill(0); + cullSemanticNSizeIn.fill(0); + clipSemanticNSizeOut.fill(0); + cullSemanticNSizeOut.fill(0); + + // "Shaders in the transform // feedback capturing mode have an initial global default of // layout(xfb_buffer = 0) out;" if (language == EShLangVertex || @@ -82,12 +97,23 @@ HlslParseContext::HlslParseContext(TSymbolTable& symbolTable, TIntermediate& int if (language == EShLangGeometry) globalOutputDefaults.layoutStream = 0; + + if (spvVersion.spv == 0 || spvVersion.vulkan == 0) + infoSink.info << "ERROR: HLSL currently only supported when requesting SPIR-V for Vulkan.\n"; } HlslParseContext::~HlslParseContext() { } +void HlslParseContext::initializeExtensionBehavior() +{ + TParseContextBase::initializeExtensionBehavior(); + + // HLSL allows #line by default. + extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive] = EBhEnable; +} + void HlslParseContext::setLimits(const TBuiltInResource& r) { resources = r; @@ -104,16 +130,398 @@ bool HlslParseContext::parseShaderStrings(TPpContext& ppContext, TInputScanner& currentScanner = &input; ppContext.setInput(input, versionWillBeError); - HlslScanContext::fillInKeywordMap(); // TODO: right place, and include the delete too - HlslScanContext scanContext(*this, ppContext); HlslGrammar grammar(scanContext, *this); - if (! grammar.parse()) - printf("HLSL translation failed.\n"); + if (!grammar.parse()) { + // Print a message formated such that if you click on the message it will take you right to + // the line through most UIs. + const glslang::TSourceLoc& sourceLoc = input.getSourceLoc(); + infoSink.info << sourceLoc.name << "(" << sourceLoc.line << "): error at column " << sourceLoc.column + << ", HLSL parsing failed.\n"; + ++numErrors; + return false; + } + + finish(); return numErrors == 0; } +// +// Return true if this l-value node should be converted in some manner. +// For instance: turning a load aggregate into a store in an l-value. +// +bool HlslParseContext::shouldConvertLValue(const TIntermNode* node) const +{ + if (node == nullptr || node->getAsTyped() == nullptr) + return false; + + const TIntermAggregate* lhsAsAggregate = node->getAsAggregate(); + const TIntermBinary* lhsAsBinary = node->getAsBinaryNode(); + + // If it's a swizzled/indexed aggregate, look at the left node instead. + if (lhsAsBinary != nullptr && + (lhsAsBinary->getOp() == EOpVectorSwizzle || lhsAsBinary->getOp() == EOpIndexDirect)) + lhsAsAggregate = lhsAsBinary->getLeft()->getAsAggregate(); + if (lhsAsAggregate != nullptr && lhsAsAggregate->getOp() == EOpImageLoad) + return true; + + return false; +} + +void HlslParseContext::growGlobalUniformBlock(const TSourceLoc& loc, TType& memberType, const TString& memberName, + TTypeList* newTypeList) +{ + newTypeList = nullptr; + correctUniform(memberType.getQualifier()); + if (memberType.isStruct()) { + auto it = ioTypeMap.find(memberType.getStruct()); + if (it != ioTypeMap.end() && it->second.uniform) + newTypeList = it->second.uniform; + } + TParseContextBase::growGlobalUniformBlock(loc, memberType, memberName, newTypeList); +} + +// +// Return a TLayoutFormat corresponding to the given texture type. +// +TLayoutFormat HlslParseContext::getLayoutFromTxType(const TSourceLoc& loc, const TType& txType) +{ + if (txType.isStruct()) { + // TODO: implement. + error(loc, "unimplemented: structure type in image or buffer", "", ""); + return ElfNone; + } + + const int components = txType.getVectorSize(); + const TBasicType txBasicType = txType.getBasicType(); + + const auto selectFormat = [this,&components](TLayoutFormat v1, TLayoutFormat v2, TLayoutFormat v4) -> TLayoutFormat { + if (intermediate.getNoStorageFormat()) + return ElfNone; + + return components == 1 ? v1 : + components == 2 ? v2 : v4; + }; + + switch (txBasicType) { + case EbtFloat: return selectFormat(ElfR32f, ElfRg32f, ElfRgba32f); + case EbtInt: return selectFormat(ElfR32i, ElfRg32i, ElfRgba32i); + case EbtUint: return selectFormat(ElfR32ui, ElfRg32ui, ElfRgba32ui); + default: + error(loc, "unknown basic type in image format", "", ""); + return ElfNone; + } +} + +// +// Both test and if necessary, spit out an error, to see if the node is really +// an l-value that can be operated on this way. +// +// Returns true if there was an error. +// +bool HlslParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node) +{ + if (shouldConvertLValue(node)) { + // if we're writing to a texture, it must be an RW form. + + TIntermAggregate* lhsAsAggregate = node->getAsAggregate(); + TIntermTyped* object = lhsAsAggregate->getSequence()[0]->getAsTyped(); + + if (!object->getType().getSampler().isImage()) { + error(loc, "operator[] on a non-RW texture must be an r-value", "", ""); + return true; + } + } + + // We tolerate samplers as l-values, even though they are nominally + // illegal, because we expect a later optimization to eliminate them. + if (node->getType().getBasicType() == EbtSampler) { + intermediate.setNeedsLegalization(); + return false; + } + + // Let the base class check errors + return TParseContextBase::lValueErrorCheck(loc, op, node); +} + +// +// This function handles l-value conversions and verifications. It uses, but is not synonymous +// with lValueErrorCheck. That function accepts an l-value directly, while this one must be +// given the surrounding tree - e.g, with an assignment, so we can convert the assign into a +// series of other image operations. +// +// Most things are passed through unmodified, except for error checking. +// +TIntermTyped* HlslParseContext::handleLvalue(const TSourceLoc& loc, const char* op, TIntermTyped*& node) +{ + if (node == nullptr) + return nullptr; + + TIntermBinary* nodeAsBinary = node->getAsBinaryNode(); + TIntermUnary* nodeAsUnary = node->getAsUnaryNode(); + TIntermAggregate* sequence = nullptr; + + TIntermTyped* lhs = nodeAsUnary ? nodeAsUnary->getOperand() : + nodeAsBinary ? nodeAsBinary->getLeft() : + nullptr; + + // Early bail out if there is no conversion to apply + if (!shouldConvertLValue(lhs)) { + if (lhs != nullptr) + if (lValueErrorCheck(loc, op, lhs)) + return nullptr; + return node; + } + + // *** If we get here, we're going to apply some conversion to an l-value. + + // Helper to create a load. + const auto makeLoad = [&](TIntermSymbol* rhsTmp, TIntermTyped* object, TIntermTyped* coord, const TType& derefType) { + TIntermAggregate* loadOp = new TIntermAggregate(EOpImageLoad); + loadOp->setLoc(loc); + loadOp->getSequence().push_back(object); + loadOp->getSequence().push_back(intermediate.addSymbol(*coord->getAsSymbolNode())); + loadOp->setType(derefType); + + sequence = intermediate.growAggregate(sequence, + intermediate.addAssign(EOpAssign, rhsTmp, loadOp, loc), + loc); + }; + + // Helper to create a store. + const auto makeStore = [&](TIntermTyped* object, TIntermTyped* coord, TIntermSymbol* rhsTmp) { + TIntermAggregate* storeOp = new TIntermAggregate(EOpImageStore); + storeOp->getSequence().push_back(object); + storeOp->getSequence().push_back(coord); + storeOp->getSequence().push_back(intermediate.addSymbol(*rhsTmp)); + storeOp->setLoc(loc); + storeOp->setType(TType(EbtVoid)); + + sequence = intermediate.growAggregate(sequence, storeOp); + }; + + // Helper to create an assign. + const auto makeBinary = [&](TOperator op, TIntermTyped* lhs, TIntermTyped* rhs) { + sequence = intermediate.growAggregate(sequence, + intermediate.addBinaryNode(op, lhs, rhs, loc, lhs->getType()), + loc); + }; + + // Helper to complete sequence by adding trailing variable, so we evaluate to the right value. + const auto finishSequence = [&](TIntermSymbol* rhsTmp, const TType& derefType) -> TIntermAggregate* { + // Add a trailing use of the temp, so the sequence returns the proper value. + sequence = intermediate.growAggregate(sequence, intermediate.addSymbol(*rhsTmp)); + sequence->setOperator(EOpSequence); + sequence->setLoc(loc); + sequence->setType(derefType); + + return sequence; + }; + + // Helper to add unary op + const auto makeUnary = [&](TOperator op, TIntermSymbol* rhsTmp) { + sequence = intermediate.growAggregate(sequence, + intermediate.addUnaryNode(op, intermediate.addSymbol(*rhsTmp), loc, + rhsTmp->getType()), + loc); + }; + + // Return true if swizzle or index writes all components of the given variable. + const auto writesAllComponents = [&](TIntermSymbol* var, TIntermBinary* swizzle) -> bool { + if (swizzle == nullptr) // not a swizzle or index + return true; + + // Track which components are being set. + std::array compIsSet; + compIsSet.fill(false); + + const TIntermConstantUnion* asConst = swizzle->getRight()->getAsConstantUnion(); + const TIntermAggregate* asAggregate = swizzle->getRight()->getAsAggregate(); + + // This could be either a direct index, or a swizzle. + if (asConst) { + compIsSet[asConst->getConstArray()[0].getIConst()] = true; + } else if (asAggregate) { + const TIntermSequence& seq = asAggregate->getSequence(); + for (int comp=0; compgetAsConstantUnion()->getConstArray()[0].getIConst()] = true; + } else { + assert(0); + } + + // Return true if all components are being set by the index or swizzle + return std::all_of(compIsSet.begin(), compIsSet.begin() + var->getType().getVectorSize(), + [](bool isSet) { return isSet; } ); + }; + + // Create swizzle matching input swizzle + const auto addSwizzle = [&](TIntermSymbol* var, TIntermBinary* swizzle) -> TIntermTyped* { + if (swizzle) + return intermediate.addBinaryNode(swizzle->getOp(), var, swizzle->getRight(), loc, swizzle->getType()); + else + return var; + }; + + TIntermBinary* lhsAsBinary = lhs->getAsBinaryNode(); + TIntermAggregate* lhsAsAggregate = lhs->getAsAggregate(); + bool lhsIsSwizzle = false; + + // If it's a swizzled L-value, remember the swizzle, and use the LHS. + if (lhsAsBinary != nullptr && (lhsAsBinary->getOp() == EOpVectorSwizzle || lhsAsBinary->getOp() == EOpIndexDirect)) { + lhsAsAggregate = lhsAsBinary->getLeft()->getAsAggregate(); + lhsIsSwizzle = true; + } + + TIntermTyped* object = lhsAsAggregate->getSequence()[0]->getAsTyped(); + TIntermTyped* coord = lhsAsAggregate->getSequence()[1]->getAsTyped(); + + const TSampler& texSampler = object->getType().getSampler(); + + TType objDerefType; + getTextureReturnType(texSampler, objDerefType); + + if (nodeAsBinary) { + TIntermTyped* rhs = nodeAsBinary->getRight(); + const TOperator assignOp = nodeAsBinary->getOp(); + + bool isModifyOp = false; + + switch (assignOp) { + case EOpAddAssign: + case EOpSubAssign: + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + case EOpDivAssign: + case EOpModAssign: + case EOpAndAssign: + case EOpInclusiveOrAssign: + case EOpExclusiveOrAssign: + case EOpLeftShiftAssign: + case EOpRightShiftAssign: + isModifyOp = true; + // fall through... + case EOpAssign: + { + // Since this is an lvalue, we'll convert an image load to a sequence like this + // (to still provide the value): + // OpSequence + // OpImageStore(object, lhs, rhs) + // rhs + // But if it's not a simple symbol RHS (say, a fn call), we don't want to duplicate the RHS, + // so we'll convert instead to this: + // OpSequence + // rhsTmp = rhs + // OpImageStore(object, coord, rhsTmp) + // rhsTmp + // If this is a read-modify-write op, like +=, we issue: + // OpSequence + // coordtmp = load's param1 + // rhsTmp = OpImageLoad(object, coordTmp) + // rhsTmp op= rhs + // OpImageStore(object, coordTmp, rhsTmp) + // rhsTmp + // + // If the lvalue is swizzled, we apply that when writing the temp variable, like so: + // ... + // rhsTmp.some_swizzle = ... + // For partial writes, an error is generated. + + TIntermSymbol* rhsTmp = rhs->getAsSymbolNode(); + TIntermTyped* coordTmp = coord; + + if (rhsTmp == nullptr || isModifyOp || lhsIsSwizzle) { + rhsTmp = makeInternalVariableNode(loc, "storeTemp", objDerefType); + + // Partial updates not yet supported + if (!writesAllComponents(rhsTmp, lhsAsBinary)) { + error(loc, "unimplemented: partial image updates", "", ""); + } + + // Assign storeTemp = rhs + if (isModifyOp) { + // We have to make a temp var for the coordinate, to avoid evaluating it twice. + coordTmp = makeInternalVariableNode(loc, "coordTemp", coord->getType()); + makeBinary(EOpAssign, coordTmp, coord); // coordtmp = load[param1] + makeLoad(rhsTmp, object, coordTmp, objDerefType); // rhsTmp = OpImageLoad(object, coordTmp) + } + + // rhsTmp op= rhs. + makeBinary(assignOp, addSwizzle(intermediate.addSymbol(*rhsTmp), lhsAsBinary), rhs); + } + + makeStore(object, coordTmp, rhsTmp); // add a store + return finishSequence(rhsTmp, objDerefType); // return rhsTmp from sequence + } + + default: + break; + } + } + + if (nodeAsUnary) { + const TOperator assignOp = nodeAsUnary->getOp(); + + switch (assignOp) { + case EOpPreIncrement: + case EOpPreDecrement: + { + // We turn this into: + // OpSequence + // coordtmp = load's param1 + // rhsTmp = OpImageLoad(object, coordTmp) + // rhsTmp op + // OpImageStore(object, coordTmp, rhsTmp) + // rhsTmp + + TIntermSymbol* rhsTmp = makeInternalVariableNode(loc, "storeTemp", objDerefType); + TIntermTyped* coordTmp = makeInternalVariableNode(loc, "coordTemp", coord->getType()); + + makeBinary(EOpAssign, coordTmp, coord); // coordtmp = load[param1] + makeLoad(rhsTmp, object, coordTmp, objDerefType); // rhsTmp = OpImageLoad(object, coordTmp) + makeUnary(assignOp, rhsTmp); // op rhsTmp + makeStore(object, coordTmp, rhsTmp); // OpImageStore(object, coordTmp, rhsTmp) + return finishSequence(rhsTmp, objDerefType); // return rhsTmp from sequence + } + + case EOpPostIncrement: + case EOpPostDecrement: + { + // We turn this into: + // OpSequence + // coordtmp = load's param1 + // rhsTmp1 = OpImageLoad(object, coordTmp) + // rhsTmp2 = rhsTmp1 + // rhsTmp2 op + // OpImageStore(object, coordTmp, rhsTmp2) + // rhsTmp1 (pre-op value) + TIntermSymbol* rhsTmp1 = makeInternalVariableNode(loc, "storeTempPre", objDerefType); + TIntermSymbol* rhsTmp2 = makeInternalVariableNode(loc, "storeTempPost", objDerefType); + TIntermTyped* coordTmp = makeInternalVariableNode(loc, "coordTemp", coord->getType()); + + makeBinary(EOpAssign, coordTmp, coord); // coordtmp = load[param1] + makeLoad(rhsTmp1, object, coordTmp, objDerefType); // rhsTmp1 = OpImageLoad(object, coordTmp) + makeBinary(EOpAssign, rhsTmp2, rhsTmp1); // rhsTmp2 = rhsTmp1 + makeUnary(assignOp, rhsTmp2); // rhsTmp op + makeStore(object, coordTmp, rhsTmp2); // OpImageStore(object, coordTmp, rhsTmp2) + return finishSequence(rhsTmp1, objDerefType); // return rhsTmp from sequence + } + + default: + break; + } + } + + if (lhs) + if (lValueErrorCheck(loc, op, lhs)) + return nullptr; + + return node; +} + void HlslParseContext::handlePragma(const TSourceLoc& loc, const TVector& tokens) { if (pragmaCallback) @@ -121,172 +529,128 @@ void HlslParseContext::handlePragma(const TSourceLoc& loc, const TVector lowerTokens = tokens; + + for (auto it = lowerTokens.begin(); it != lowerTokens.end(); ++it) + std::transform(it->begin(), it->end(), it->begin(), ::tolower); + + // Handle pack_matrix + if (tokens.size() == 4 && lowerTokens[0] == "pack_matrix" && tokens[1] == "(" && tokens[3] == ")") { + // Note that HLSL semantic order is Mrc, not Mcr like SPIR-V, so we reverse the sense. + // Row major becomes column major and vice versa. + + if (lowerTokens[2] == "row_major") { + globalUniformDefaults.layoutMatrix = globalBufferDefaults.layoutMatrix = ElmColumnMajor; + } else if (lowerTokens[2] == "column_major") { + globalUniformDefaults.layoutMatrix = globalBufferDefaults.layoutMatrix = ElmRowMajor; + } else { + // unknown majorness strings are treated as (HLSL column major)==(SPIR-V row major) + warn(loc, "unknown pack_matrix pragma value", tokens[2].c_str(), ""); + globalUniformDefaults.layoutMatrix = globalBufferDefaults.layoutMatrix = ElmRowMajor; + } + return; + } + + // Handle once + if (lowerTokens[0] == "once") { + warn(loc, "not implemented", "#pragma once", ""); + return; + } } // -// Look at a '.' field selector string and change it into offsets -// for a vector or scalar +// Look at a '.' matrix selector string and change it into components +// for a matrix. There are two types: +// +// _21 second row, first column (one based) +// _m21 third row, second column (zero based) // // Returns true if there is no error. // -bool HlslParseContext::parseVectorFields(const TSourceLoc& loc, const TString& compString, int vecSize, TVectorFields& fields) +bool HlslParseContext::parseMatrixSwizzleSelector(const TSourceLoc& loc, const TString& fields, int cols, int rows, + TSwizzleSelectors& components) { - fields.num = (int)compString.size(); - if (fields.num > 4) { - error(loc, "illegal vector field selection", compString.c_str(), ""); - return false; - } + int startPos[MaxSwizzleSelectors]; + int numComps = 0; + TString compString = fields; - enum { - exyzw, - ergba, - estpq, - } fieldSet[4]; - - for (int i = 0; i < fields.num; ++i) { - switch (compString[i]) { - case 'x': - fields.offsets[i] = 0; - fieldSet[i] = exyzw; - break; - case 'r': - fields.offsets[i] = 0; - fieldSet[i] = ergba; - break; - case 's': - fields.offsets[i] = 0; - fieldSet[i] = estpq; - break; - case 'y': - fields.offsets[i] = 1; - fieldSet[i] = exyzw; - break; - case 'g': - fields.offsets[i] = 1; - fieldSet[i] = ergba; - break; - case 't': - fields.offsets[i] = 1; - fieldSet[i] = estpq; - break; - case 'z': - fields.offsets[i] = 2; - fieldSet[i] = exyzw; - break; - case 'b': - fields.offsets[i] = 2; - fieldSet[i] = ergba; - break; - case 'p': - fields.offsets[i] = 2; - fieldSet[i] = estpq; - break; - - case 'w': - fields.offsets[i] = 3; - fieldSet[i] = exyzw; - break; - case 'a': - fields.offsets[i] = 3; - fieldSet[i] = ergba; - break; - case 'q': - fields.offsets[i] = 3; - fieldSet[i] = estpq; - break; - default: - error(loc, "illegal vector field selection", compString.c_str(), ""); + // Find where each component starts, + // recording the first character position after the '_'. + for (size_t c = 0; c < compString.size(); ++c) { + if (compString[c] == '_') { + if (numComps >= MaxSwizzleSelectors) { + error(loc, "matrix component swizzle has too many components", compString.c_str(), ""); return false; } - } - - for (int i = 0; i < fields.num; ++i) { - if (fields.offsets[i] >= vecSize) { - error(loc, "vector field selection out of range", compString.c_str(), ""); + if (c > compString.size() - 3 || + ((compString[c+1] == 'm' || compString[c+1] == 'M') && c > compString.size() - 4)) { + error(loc, "matrix component swizzle missing", compString.c_str(), ""); return false; } - - if (i > 0) { - if (fieldSet[i] != fieldSet[i - 1]) { - error(loc, "illegal - vector component fields not from the same set", compString.c_str(), ""); - return false; - } - } + startPos[numComps++] = (int)c + 1; } - - return true; -} - -// -// Used to output syntax, parsing, and semantic errors. -// - -void HlslParseContext::outputMessage(const TSourceLoc& loc, const char* szReason, - const char* szToken, - const char* szExtraInfoFormat, - TPrefixType prefix, va_list args) -{ - const int maxSize = MaxTokenLength + 200; - char szExtraInfo[maxSize]; - - safe_vsprintf(szExtraInfo, maxSize, szExtraInfoFormat, args); - - infoSink.info.prefix(prefix); - infoSink.info.location(loc); - infoSink.info << "'" << szToken << "' : " << szReason << " " << szExtraInfo << "\n"; - - if (prefix == EPrefixError) { - ++numErrors; } + + // Process each component + for (int i = 0; i < numComps; ++i) { + int pos = startPos[i]; + int bias = -1; + if (compString[pos] == 'm' || compString[pos] == 'M') { + bias = 0; + ++pos; + } + TMatrixSelector comp; + comp.coord1 = compString[pos+0] - '0' + bias; + comp.coord2 = compString[pos+1] - '0' + bias; + if (comp.coord1 < 0 || comp.coord1 >= cols) { + error(loc, "matrix row component out of range", compString.c_str(), ""); + return false; + } + if (comp.coord2 < 0 || comp.coord2 >= rows) { + error(loc, "matrix column component out of range", compString.c_str(), ""); + return false; + } + components.push_back(comp); + } + + return true; } -void C_DECL HlslParseContext::error(const TSourceLoc& loc, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...) +// If the 'comps' express a column of a matrix, +// return the column. Column means the first coords all match. +// +// Otherwise, return -1. +// +int HlslParseContext::getMatrixComponentsColumn(int rows, const TSwizzleSelectors& selector) { - if (messages & EShMsgOnlyPreprocessor) - return; - va_list args; - va_start(args, szExtraInfoFormat); - outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args); - va_end(args); -} + int col = -1; -void C_DECL HlslParseContext::warn(const TSourceLoc& loc, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...) -{ - if (suppressWarnings()) - return; - va_list args; - va_start(args, szExtraInfoFormat); - outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args); - va_end(args); -} + // right number of comps? + if (selector.size() != rows) + return -1; -void C_DECL HlslParseContext::ppError(const TSourceLoc& loc, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...) -{ - va_list args; - va_start(args, szExtraInfoFormat); - outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args); - va_end(args); -} + // all comps in the same column? + // rows in order? + col = selector[0].coord1; + for (int i = 0; i < rows; ++i) { + if (col != selector[i].coord1) + return -1; + if (i != selector[i].coord2) + return -1; + } -void C_DECL HlslParseContext::ppWarn(const TSourceLoc& loc, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...) -{ - va_list args; - va_start(args, szExtraInfoFormat); - outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args); - va_end(args); + return col; } // // Handle seeing a variable identifier in the grammar. // -TIntermTyped* HlslParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symbol, const TString* string) +TIntermTyped* HlslParseContext::handleVariable(const TSourceLoc& loc, const TString* string) { - if (symbol == nullptr) - symbol = symbolTable.find(*string); + int thisDepth; + TSymbol* symbol = symbolTable.find(*string, thisDepth); if (symbol && symbol->getAsVariable() && symbol->getAsVariable()->isUserType()) { error(loc, "expected symbol, not user-defined type", string->c_str(), ""); return nullptr; @@ -296,27 +660,21 @@ TIntermTyped* HlslParseContext::handleVariable(const TSourceLoc& loc, TSymbol* s if (symbol && symbol->getNumExtensions()) requireExtensions(loc, symbol->getNumExtensions(), symbol->getExtensions(), symbol->getName().c_str()); - if (symbol && symbol->isReadOnly()) { - // All shared things containing an implicitly sized array must be copied up - // on first use, so that all future references will share its array structure, - // so that editing the implicit size will effect all nodes consuming it, - // and so that editing the implicit size won't change the shared one. - // - // If this is a variable or a block, check it and all it contains, but if this - // is a member of an anonymous block, check the whole block, as the whole block - // will need to be copied up if it contains an implicitly-sized array. - if (symbol->getType().containsImplicitlySizedArray() || (symbol->getAsAnonMember() && symbol->getAsAnonMember()->getAnonContainer().getType().containsImplicitlySizedArray())) - makeEditable(symbol); - } - - const TVariable* variable; + const TVariable* variable = nullptr; const TAnonMember* anon = symbol ? symbol->getAsAnonMember() : nullptr; TIntermTyped* node = nullptr; if (anon) { - // It was a member of an anonymous container. + // It was a member of an anonymous container, which could be a 'this' structure. // Create a subtree for its dereference. - variable = anon->getAnonContainer().getAsVariable(); + if (thisDepth > 0) { + variable = getImplicitThis(thisDepth); + if (variable == nullptr) + error(loc, "cannot access member variables (static member function?)", "this", ""); + } + if (variable == nullptr) + variable = anon->getAnonContainer().getAsVariable(); + TIntermTyped* container = intermediate.addSymbol(*variable, loc); TIntermTyped* constNode = intermediate.addConstantUnion(anon->getMemberNumber(), loc); node = intermediate.addIndex(EOpIndexDirectStruct, container, constNode, loc); @@ -342,8 +700,10 @@ TIntermTyped* HlslParseContext::handleVariable(const TSourceLoc& loc, TSymbol* s } // Recovery, if it wasn't found or was not a variable. - if (! variable) + if (variable == nullptr) { + error(loc, "unknown variable", string->c_str(), ""); variable = new TVariable(string, TType(EbtVoid)); + } if (variable->getType().getQualifier().isFrontEndConstant()) node = intermediate.addConstantUnion(variable->getConstArray(), variable->getType(), loc); @@ -357,39 +717,138 @@ TIntermTyped* HlslParseContext::handleVariable(const TSourceLoc& loc, TSymbol* s return node; } +// +// Handle operator[] on any objects it applies to. Currently: +// Textures +// Buffers +// +TIntermTyped* HlslParseContext::handleBracketOperator(const TSourceLoc& loc, TIntermTyped* base, TIntermTyped* index) +{ + // handle r-value operator[] on textures and images. l-values will be processed later. + if (base->getType().getBasicType() == EbtSampler && !base->isArray()) { + const TSampler& sampler = base->getType().getSampler(); + if (sampler.isImage() || sampler.isTexture()) { + if (! mipsOperatorMipArg.empty() && mipsOperatorMipArg.back().mipLevel == nullptr) { + // The first operator[] to a .mips[] sequence is the mip level. We'll remember it. + mipsOperatorMipArg.back().mipLevel = index; + return base; // next [] index is to the same base. + } else { + TIntermAggregate* load = new TIntermAggregate(sampler.isImage() ? EOpImageLoad : EOpTextureFetch); + + TType sampReturnType; + getTextureReturnType(sampler, sampReturnType); + + load->setType(sampReturnType); + load->setLoc(loc); + load->getSequence().push_back(base); + load->getSequence().push_back(index); + + // Textures need a MIP. If we saw one go by, use it. Otherwise, use zero. + if (sampler.isTexture()) { + if (! mipsOperatorMipArg.empty()) { + load->getSequence().push_back(mipsOperatorMipArg.back().mipLevel); + mipsOperatorMipArg.pop_back(); + } else { + load->getSequence().push_back(intermediate.addConstantUnion(0, loc, true)); + } + } + + return load; + } + } + } + + // Handle operator[] on structured buffers: this indexes into the array element of the buffer. + // indexStructBufferContent returns nullptr if it isn't a structuredbuffer (SSBO). + TIntermTyped* sbArray = indexStructBufferContent(loc, base); + if (sbArray != nullptr) { + if (sbArray == nullptr) + return nullptr; + + // Now we'll apply the [] index to that array + const TOperator idxOp = (index->getQualifier().storage == EvqConst) ? EOpIndexDirect : EOpIndexIndirect; + + TIntermTyped* element = intermediate.addIndex(idxOp, sbArray, index, loc); + const TType derefType(sbArray->getType(), 0); + element->setType(derefType); + return element; + } + + return nullptr; +} + +// +// Cast index value to a uint if it isn't already (for operator[], load indexes, etc) +TIntermTyped* HlslParseContext::makeIntegerIndex(TIntermTyped* index) +{ + const TBasicType indexBasicType = index->getType().getBasicType(); + const int vecSize = index->getType().getVectorSize(); + + // We can use int types directly as the index + if (indexBasicType == EbtInt || indexBasicType == EbtUint || + indexBasicType == EbtInt64 || indexBasicType == EbtUint64) + return index; + + // Cast index to unsigned integer if it isn't one. + return intermediate.addConversion(EOpConstructUint, TType(EbtUint, EvqTemporary, vecSize), index); +} + // // Handle seeing a base[index] dereference in the grammar. // TIntermTyped* HlslParseContext::handleBracketDereference(const TSourceLoc& loc, TIntermTyped* base, TIntermTyped* index) { - TIntermTyped* result = nullptr; + index = makeIntegerIndex(index); - int indexValue = 0; - if (index->getQualifier().storage == EvqConst) { - indexValue = index->getAsConstantUnion()->getConstArray()[0].getIConst(); - checkIndex(loc, base->getType(), indexValue); + if (index == nullptr) { + error(loc, " unknown index type ", "", ""); + return nullptr; } + TIntermTyped* result = handleBracketOperator(loc, base, index); + + if (result != nullptr) + return result; // it was handled as an operator[] + + bool flattened = false; + int indexValue = 0; + if (index->getQualifier().isFrontEndConstant()) + indexValue = index->getAsConstantUnion()->getConstArray()[0].getIConst(); + variableCheck(base); if (! base->isArray() && ! base->isMatrix() && ! base->isVector()) { if (base->getAsSymbolNode()) - error(loc, " left of '[' is not of type array, matrix, or vector ", base->getAsSymbolNode()->getName().c_str(), ""); + error(loc, " left of '[' is not of type array, matrix, or vector ", + base->getAsSymbolNode()->getName().c_str(), ""); else error(loc, " left of '[' is not of type array, matrix, or vector ", "expression", ""); - } else if (base->getType().getQualifier().storage == EvqConst && index->getQualifier().storage == EvqConst) + } else if (base->getType().getQualifier().storage == EvqConst && index->getQualifier().storage == EvqConst) { + // both base and index are front-end constants + checkIndex(loc, base->getType(), indexValue); return intermediate.foldDereference(base, indexValue, loc); - else { + } else { // at least one of base and index is variable... - if (base->getAsSymbolNode() && isIoResizeArray(base->getType())) - handleIoResizeArrayAccess(loc, base); + if (index->getQualifier().isFrontEndConstant()) + checkIndex(loc, base->getType(), indexValue); - if (index->getQualifier().storage == EvqConst) { - if (base->getType().isImplicitlySizedArray()) - updateImplicitArraySize(loc, base, indexValue); - result = intermediate.addIndex(EOpIndexDirect, base, index, loc); + if (base->getType().isScalarOrVec1()) + result = base; + else if (base->getAsSymbolNode() && wasFlattened(base)) { + if (index->getQualifier().storage != EvqConst) + error(loc, "Invalid variable index to flattened array", base->getAsSymbolNode()->getName().c_str(), ""); + + result = flattenAccess(base, indexValue); + flattened = (result != base); } else { - result = intermediate.addIndex(EOpIndexIndirect, base, index, loc); + if (index->getQualifier().isFrontEndConstant()) { + if (base->getType().isUnsizedArray()) + base->getWritableType().updateImplicitArraySize(indexValue + 1); + else + checkIndex(loc, base->getType(), indexValue); + result = intermediate.addIndex(EOpIndexDirect, base, index, loc); + } else + result = intermediate.addIndex(EOpIndexIndirect, base, index, loc); } } @@ -397,154 +856,37 @@ TIntermTyped* HlslParseContext::handleBracketDereference(const TSourceLoc& loc, // Insert dummy error-recovery result result = intermediate.addConstantUnion(0.0, EbtFloat, loc); } else { - // Insert valid dereferenced result - TType newType(base->getType(), 0); // dereferenced type - if (base->getType().getQualifier().storage == EvqConst && index->getQualifier().storage == EvqConst) - newType.getQualifier().storage = EvqConst; - else - newType.getQualifier().storage = EvqTemporary; - result->setType(newType); + // If the array reference was flattened, it has the correct type. E.g, if it was + // a uniform array, it was flattened INTO a set of scalar uniforms, not scalar temps. + // In that case, we preserve the qualifiers. + if (!flattened) { + // Insert valid dereferenced result + TType newType(base->getType(), 0); // dereferenced type + if (base->getType().getQualifier().storage == EvqConst && index->getQualifier().storage == EvqConst) + newType.getQualifier().storage = EvqConst; + else + newType.getQualifier().storage = EvqTemporary; + result->setType(newType); + } } return result; } -void HlslParseContext::checkIndex(const TSourceLoc& /*loc*/, const TType& /*type*/, int& /*index*/) -{ - // HLSL todo: any rules for index fixups? -} - -// Make a shared symbol have a non-shared version that can be edited by the current -// compile, such that editing its type will not change the shared version and will -// effect all nodes sharing it. -void HlslParseContext::makeEditable(TSymbol*& symbol) -{ - // copyUp() does a deep copy of the type. - symbol = symbolTable.copyUp(symbol); - - // Also, see if it's tied to IO resizing - if (isIoResizeArray(symbol->getType())) - ioArraySymbolResizeList.push_back(symbol); - - // Also, save it in the AST for linker use. - intermediate.addSymbolLinkageNode(linkage, *symbol); -} - -TVariable* HlslParseContext::getEditableVariable(const char* name) -{ - bool builtIn; - TSymbol* symbol = symbolTable.find(name, &builtIn); - if (builtIn) - makeEditable(symbol); - - return symbol->getAsVariable(); -} - -// Return true if this is a geometry shader input array or tessellation control output array. -bool HlslParseContext::isIoResizeArray(const TType& type) const -{ - return type.isArray() && - ((language == EShLangGeometry && type.getQualifier().storage == EvqVaryingIn) || - (language == EShLangTessControl && type.getQualifier().storage == EvqVaryingOut && ! type.getQualifier().patch)); -} - -// If an array is not isIoResizeArray() but is an io array, make sure it has the right size -void HlslParseContext::fixIoArraySize(const TSourceLoc& loc, TType& type) -{ - if (! type.isArray() || type.getQualifier().patch || symbolTable.atBuiltInLevel()) - return; - - assert(! isIoResizeArray(type)); - - if (type.getQualifier().storage != EvqVaryingIn || type.getQualifier().patch) - return; - - if (language == EShLangTessControl || language == EShLangTessEvaluation) { - if (type.getOuterArraySize() != resources.maxPatchVertices) { - if (type.isExplicitlySizedArray()) - error(loc, "tessellation input array size must be gl_MaxPatchVertices or implicitly sized", "[]", ""); - type.changeOuterArraySize(resources.maxPatchVertices); - } - } -} - -// Handle a dereference of a geometry shader input array or tessellation control output array. -// See ioArraySymbolResizeList comment in ParseHelper.h. -// -void HlslParseContext::handleIoResizeArrayAccess(const TSourceLoc& /*loc*/, TIntermTyped* base) -{ - TIntermSymbol* symbolNode = base->getAsSymbolNode(); - assert(symbolNode); - if (! symbolNode) - return; - - // fix array size, if it can be fixed and needs to be fixed (will allow variable indexing) - if (symbolNode->getType().isImplicitlySizedArray()) { - int newSize = getIoArrayImplicitSize(); - if (newSize > 0) - symbolNode->getWritableType().changeOuterArraySize(newSize); - } -} - -// If there has been an input primitive declaration (geometry shader) or an output -// number of vertices declaration(tessellation shader), make sure all input array types -// match it in size. Types come either from nodes in the AST or symbols in the -// symbol table. -// -// Types without an array size will be given one. -// Types already having a size that is wrong will get an error. -// -void HlslParseContext::checkIoArraysConsistency(const TSourceLoc& loc, bool tailOnly) -{ - int requiredSize = getIoArrayImplicitSize(); - if (requiredSize == 0) - return; - - const char* feature; - if (language == EShLangGeometry) - feature = TQualifier::getGeometryString(intermediate.getInputPrimitive()); - else if (language == EShLangTessControl) - feature = "vertices"; - else - feature = "unknown"; - - if (tailOnly) { - checkIoArrayConsistency(loc, requiredSize, feature, ioArraySymbolResizeList.back()->getWritableType(), ioArraySymbolResizeList.back()->getName()); - return; - } - - for (size_t i = 0; i < ioArraySymbolResizeList.size(); ++i) - checkIoArrayConsistency(loc, requiredSize, feature, ioArraySymbolResizeList[i]->getWritableType(), ioArraySymbolResizeList[i]->getName()); -} - -int HlslParseContext::getIoArrayImplicitSize() const -{ - if (language == EShLangGeometry) - return TQualifier::mapGeometryToSize(intermediate.getInputPrimitive()); - else if (language == EShLangTessControl) - return intermediate.getVertices() != TQualifier::layoutNotSet ? intermediate.getVertices() : 0; - else - return 0; -} - -void HlslParseContext::checkIoArrayConsistency(const TSourceLoc& /*loc*/, int requiredSize, const char* /*feature*/, TType& type, const TString& /*name*/) -{ - if (type.isImplicitlySizedArray()) - type.changeOuterArraySize(requiredSize); -} - // Handle seeing a binary node with a math operation. -TIntermTyped* HlslParseContext::handleBinaryMath(const TSourceLoc& loc, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right) +TIntermTyped* HlslParseContext::handleBinaryMath(const TSourceLoc& loc, const char* str, TOperator op, + TIntermTyped* left, TIntermTyped* right) { TIntermTyped* result = intermediate.addBinaryMath(op, left, right, loc); - if (! result) + if (result == nullptr) binaryOpError(loc, str, left->getCompleteString(), right->getCompleteString()); return result; } // Handle seeing a unary node with a math operation. -TIntermTyped* HlslParseContext::handleUnaryMath(const TSourceLoc& loc, const char* str, TOperator op, TIntermTyped* childNode) +TIntermTyped* HlslParseContext::handleUnaryMath(const TSourceLoc& loc, const char* str, TOperator op, + TIntermTyped* childNode) { TIntermTyped* result = intermediate.addUnaryMath(op, childNode, loc); @@ -555,85 +897,144 @@ TIntermTyped* HlslParseContext::handleUnaryMath(const TSourceLoc& loc, const cha return childNode; } +// +// Return true if the name is a struct buffer method +// +bool HlslParseContext::isStructBufferMethod(const TString& name) const +{ + return + name == "GetDimensions" || + name == "Load" || + name == "Load2" || + name == "Load3" || + name == "Load4" || + name == "Store" || + name == "Store2" || + name == "Store3" || + name == "Store4" || + name == "InterlockedAdd" || + name == "InterlockedAnd" || + name == "InterlockedCompareExchange" || + name == "InterlockedCompareStore" || + name == "InterlockedExchange" || + name == "InterlockedMax" || + name == "InterlockedMin" || + name == "InterlockedOr" || + name == "InterlockedXor" || + name == "IncrementCounter" || + name == "DecrementCounter" || + name == "Append" || + name == "Consume"; +} // -// Handle seeing a base.field dereference in the grammar. +// Handle seeing a base.field dereference in the grammar, where 'field' is a +// swizzle or member variable. // TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TIntermTyped* base, const TString& field) { variableCheck(base); - // - // methods can't be resolved until we later see the function-calling syntax. - // Save away the name in the AST for now. Processing is completed in - // handleLengthMethod(), etc. - // - if (field == "length") { - return intermediate.addMethod(base, TType(EbtInt), &field, loc); - } else if (field == "CalculateLevelOfDetail" || - field == "CalculateLevelOfDetailUnclamped" || - field == "Gather" || - field == "GetDimensions" || - field == "GetSamplePosition" || - field == "Load" || - field == "Sample" || - field == "SampleBias" || - field == "SampleCmp" || - field == "SampleCmpLevelZero" || - field == "SampleGrad" || - field == "SampleLevel") { - // If it's not a method on a sampler object, we fall through in case it is a struct member. - if (base->getType().getBasicType() == EbtSampler) { - const TSampler& texType = base->getType().getSampler(); - if (! texType.isPureSampler()) { - const int vecSize = texType.isShadow() ? 1 : 4; - return intermediate.addMethod(base, TType(texType.type, EvqTemporary, vecSize), &field, loc); - } - } - } - - // It's not .length() if we get to here. - if (base->isArray()) { error(loc, "cannot apply to an array:", ".", field.c_str()); - return base; } - // It's neither an array nor .length() if we get here, - // leaving swizzles and struct/block dereferences. - TIntermTyped* result = base; - if (base->isVector() || base->isScalar()) { - TVectorFields fields; - if (! parseVectorFields(loc, field, base->getVectorSize(), fields)) { - fields.num = 1; - fields.offsets[0] = 0; + + if (base->getType().getBasicType() == EbtSampler) { + // Handle .mips[mipid][pos] operation on textures + const TSampler& sampler = base->getType().getSampler(); + if (sampler.isTexture() && field == "mips") { + // Push a null to signify that we expect a mip level under operator[] next. + mipsOperatorMipArg.push_back(tMipsOperatorData(loc, nullptr)); + // Keep 'result' pointing to 'base', since we expect an operator[] to go by next. + } else { + if (field == "mips") + error(loc, "unexpected texture type for .mips[][] operator:", + base->getType().getCompleteString().c_str(), ""); + else + error(loc, "unexpected operator on texture type:", field.c_str(), + base->getType().getCompleteString().c_str()); } + } else if (base->isVector() || base->isScalar()) { + TSwizzleSelectors selectors; + parseSwizzleSelector(loc, field, base->getVectorSize(), selectors); if (base->isScalar()) { - if (fields.num == 1) + if (selectors.size() == 1) return result; else { - TType type(base->getBasicType(), EvqTemporary, fields.num); - return addConstructor(loc, base, type, mapTypeToConstructorOp(type)); + TType type(base->getBasicType(), EvqTemporary, selectors.size()); + return addConstructor(loc, base, type); + } + } + if (base->getVectorSize() == 1) { + TType scalarType(base->getBasicType(), EvqTemporary, 1); + if (selectors.size() == 1) + return addConstructor(loc, base, scalarType); + else { + TType vectorType(base->getBasicType(), EvqTemporary, selectors.size()); + return addConstructor(loc, addConstructor(loc, base, scalarType), vectorType); } } if (base->getType().getQualifier().isFrontEndConstant()) - result = intermediate.foldSwizzle(base, fields, loc); + result = intermediate.foldSwizzle(base, selectors, loc); else { - if (fields.num == 1) { - TIntermTyped* index = intermediate.addConstantUnion(fields.offsets[0], loc); + if (selectors.size() == 1) { + TIntermTyped* index = intermediate.addConstantUnion(selectors[0], loc); result = intermediate.addIndex(EOpIndexDirect, base, index, loc); - result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision)); + result->setType(TType(base->getBasicType(), EvqTemporary)); } else { - TString vectorString = field; - TIntermTyped* index = intermediate.addSwizzle(fields, loc); + TIntermTyped* index = intermediate.addSwizzle(selectors, loc); result = intermediate.addIndex(EOpVectorSwizzle, base, index, loc); - result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision, (int)vectorString.size())); + result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision, + selectors.size())); } } + } else if (base->isMatrix()) { + TSwizzleSelectors selectors; + if (! parseMatrixSwizzleSelector(loc, field, base->getMatrixCols(), base->getMatrixRows(), selectors)) + return result; + + if (selectors.size() == 1) { + // Representable by m[c][r] + if (base->getType().getQualifier().isFrontEndConstant()) { + result = intermediate.foldDereference(base, selectors[0].coord1, loc); + result = intermediate.foldDereference(result, selectors[0].coord2, loc); + } else { + result = intermediate.addIndex(EOpIndexDirect, base, + intermediate.addConstantUnion(selectors[0].coord1, loc), + loc); + TType dereferencedCol(base->getType(), 0); + result->setType(dereferencedCol); + result = intermediate.addIndex(EOpIndexDirect, result, + intermediate.addConstantUnion(selectors[0].coord2, loc), + loc); + TType dereferenced(dereferencedCol, 0); + result->setType(dereferenced); + } + } else { + int column = getMatrixComponentsColumn(base->getMatrixRows(), selectors); + if (column >= 0) { + // Representable by m[c] + if (base->getType().getQualifier().isFrontEndConstant()) + result = intermediate.foldDereference(base, column, loc); + else { + result = intermediate.addIndex(EOpIndexDirect, base, intermediate.addConstantUnion(column, loc), + loc); + TType dereferenced(base->getType(), 0); + result->setType(dereferenced); + } + } else { + // general case, not a column, not a single component + TIntermTyped* index = intermediate.addSwizzle(selectors, loc); + result = intermediate.addIndex(EOpMatrixSwizzle, base, index, loc); + result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision, + selectors.size())); + } + } } else if (base->getBasicType() == EbtStruct || base->getBasicType() == EbtBlock) { const TTypeList* fields = base->getType().getStruct(); bool fieldFound = false; @@ -645,12 +1046,16 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt } } if (fieldFound) { - if (base->getType().getQualifier().storage == EvqConst) - result = intermediate.foldDereference(base, member, loc); - else { - TIntermTyped* index = intermediate.addConstantUnion(member, loc); - result = intermediate.addIndex(EOpIndexDirectStruct, base, index, loc); - result->setType(*(*fields)[member].type); + if (base->getAsSymbolNode() && wasFlattened(base)) { + result = flattenAccess(base, member); + } else { + if (base->getType().getQualifier().storage == EvqConst) + result = intermediate.foldDereference(base, member, loc); + else { + TIntermTyped* index = intermediate.addConstantUnion(member, loc); + result = intermediate.addIndex(EOpIndexDirectStruct, base, index, loc); + result->setType(*(*fields)[member].type); + } } } else error(loc, "no such field in structure", field.c_str(), ""); @@ -660,11 +1065,524 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt return result; } +// +// Return true if the field should be treated as a built-in method. +// Return false otherwise. +// +bool HlslParseContext::isBuiltInMethod(const TSourceLoc&, TIntermTyped* base, const TString& field) +{ + if (base == nullptr) + return false; + + variableCheck(base); + + if (base->getType().getBasicType() == EbtSampler) { + return true; + } else if (isStructBufferType(base->getType()) && isStructBufferMethod(field)) { + return true; + } else if (field == "Append" || + field == "RestartStrip") { + // We cannot check the type here: it may be sanitized if we're not compiling a geometry shader, but + // the code is around in the shader source. + return true; + } else + return false; +} + +// Independently establish a built-in that is a member of a structure. +// 'arraySizes' are what's desired for the independent built-in, whatever +// the higher-level source/expression of them was. +void HlslParseContext::splitBuiltIn(const TString& baseName, const TType& memberType, const TArraySizes* arraySizes, + const TQualifier& outerQualifier) +{ + // Because of arrays of structs, we might be asked more than once, + // but the arraySizes passed in should have captured the whole thing + // the first time. + // However, clip/cull rely on multiple updates. + if (!isClipOrCullDistance(memberType)) + if (splitBuiltIns.find(tInterstageIoData(memberType.getQualifier().builtIn, outerQualifier.storage)) != + splitBuiltIns.end()) + return; + + TVariable* ioVar = makeInternalVariable(baseName + "." + memberType.getFieldName(), memberType); + + if (arraySizes != nullptr && !memberType.isArray()) + ioVar->getWritableType().copyArraySizes(*arraySizes); + + splitBuiltIns[tInterstageIoData(memberType.getQualifier().builtIn, outerQualifier.storage)] = ioVar; + if (!isClipOrCullDistance(ioVar->getType())) + trackLinkage(*ioVar); + + // Merge qualifier from the user structure + mergeQualifiers(ioVar->getWritableType().getQualifier(), outerQualifier); + + // Fix the builtin type if needed (e.g, some types require fixed array sizes, no matter how the + // shader declared them). This is done after mergeQualifiers(), in case fixBuiltInIoType looks + // at the qualifier to determine e.g, in or out qualifications. + fixBuiltInIoType(ioVar->getWritableType()); + + // But, not location, we're losing that + ioVar->getWritableType().getQualifier().layoutLocation = TQualifier::layoutLocationEnd; +} + +// Split a type into +// 1. a struct of non-I/O members +// 2. a collection of independent I/O variables +void HlslParseContext::split(const TVariable& variable) +{ + // Create a new variable: + const TType& clonedType = *variable.getType().clone(); + const TType& splitType = split(clonedType, variable.getName(), clonedType.getQualifier()); + splitNonIoVars[variable.getUniqueId()] = makeInternalVariable(variable.getName(), splitType); +} + +// Recursive implementation of split(). +// Returns reference to the modified type. +const TType& HlslParseContext::split(const TType& type, const TString& name, const TQualifier& outerQualifier) +{ + if (type.isStruct()) { + TTypeList* userStructure = type.getWritableStruct(); + for (auto ioType = userStructure->begin(); ioType != userStructure->end(); ) { + if (ioType->type->isBuiltIn()) { + // move out the built-in + splitBuiltIn(name, *ioType->type, type.getArraySizes(), outerQualifier); + ioType = userStructure->erase(ioType); + } else { + split(*ioType->type, name + "." + ioType->type->getFieldName(), outerQualifier); + ++ioType; + } + } + } + + return type; +} + +// Is this an aggregate that should be flattened? +// Can be applied to intermediate levels of type in a hierarchy. +// Some things like flattening uniform arrays are only about the top level +// of the aggregate, triggered on 'topLevel'. +bool HlslParseContext::shouldFlatten(const TType& type, TStorageQualifier qualifier, bool topLevel) const +{ + switch (qualifier) { + case EvqVaryingIn: + case EvqVaryingOut: + return type.isStruct() || type.isArray(); + case EvqUniform: + return (type.isArray() && intermediate.getFlattenUniformArrays() && topLevel) || + (type.isStruct() && type.containsOpaque()); + default: + return false; + }; +} + +// Top level variable flattening: construct data +void HlslParseContext::flatten(const TVariable& variable, bool linkage) +{ + const TType& type = variable.getType(); + + // If it's a standalone built-in, there is nothing to flatten + if (type.isBuiltIn() && !type.isStruct()) + return; + + auto entry = flattenMap.insert(std::make_pair(variable.getUniqueId(), + TFlattenData(type.getQualifier().layoutBinding, + type.getQualifier().layoutLocation))); + + // the item is a map pair, so first->second is the TFlattenData itself. + flatten(variable, type, entry.first->second, variable.getName(), linkage, type.getQualifier(), nullptr); +} + +// Recursively flatten the given variable at the provided type, building the flattenData as we go. +// +// This is mutually recursive with flattenStruct and flattenArray. +// We are going to flatten an arbitrarily nested composite structure into a linear sequence of +// members, and later on, we want to turn a path through the tree structure into a final +// location in this linear sequence. +// +// If the tree was N-ary, that can be directly calculated. However, we are dealing with +// arbitrary numbers - perhaps a struct of 7 members containing an array of 3. Thus, we must +// build a data structure to allow the sequence of bracket and dot operators on arrays and +// structs to arrive at the proper member. +// +// To avoid storing a tree with pointers, we are going to flatten the tree into a vector of integers. +// The leaves are the indexes into the flattened member array. +// Each level will have the next location for the Nth item stored sequentially, so for instance: +// +// struct { float2 a[2]; int b; float4 c[3] }; +// +// This will produce the following flattened tree: +// Pos: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 +// (3, 7, 8, 5, 6, 0, 1, 2, 11, 12, 13, 3, 4, 5} +// +// Given a reference to mystruct.c[1], the access chain is (2,1), so we traverse: +// (0+2) = 8 --> (8+1) = 12 --> 12 = 4 +// +// so the 4th flattened member in traversal order is ours. +// +int HlslParseContext::flatten(const TVariable& variable, const TType& type, + TFlattenData& flattenData, TString name, bool linkage, + const TQualifier& outerQualifier, + const TArraySizes* builtInArraySizes) +{ + // If something is an arrayed struct, the array flattener will recursively call flatten() + // to then flatten the struct, so this is an "if else": we don't do both. + if (type.isArray()) + return flattenArray(variable, type, flattenData, name, linkage, outerQualifier); + else if (type.isStruct()) + return flattenStruct(variable, type, flattenData, name, linkage, outerQualifier, builtInArraySizes); + else { + assert(0); // should never happen + return -1; + } +} + +// Add a single flattened member to the flattened data being tracked for the composite +// Returns true for the final flattening level. +int HlslParseContext::addFlattenedMember(const TVariable& variable, const TType& type, TFlattenData& flattenData, + const TString& memberName, bool linkage, + const TQualifier& outerQualifier, + const TArraySizes* builtInArraySizes) +{ + if (!shouldFlatten(type, outerQualifier.storage, false)) { + // This is as far as we flatten. Insert the variable. + TVariable* memberVariable = makeInternalVariable(memberName, type); + mergeQualifiers(memberVariable->getWritableType().getQualifier(), variable.getType().getQualifier()); + + if (flattenData.nextBinding != TQualifier::layoutBindingEnd) + memberVariable->getWritableType().getQualifier().layoutBinding = flattenData.nextBinding++; + + if (memberVariable->getType().isBuiltIn()) { + // inherited locations are nonsensical for built-ins (TODO: what if semantic had a number) + memberVariable->getWritableType().getQualifier().layoutLocation = TQualifier::layoutLocationEnd; + } else { + // inherited locations must be auto bumped, not replicated + if (flattenData.nextLocation != TQualifier::layoutLocationEnd) { + memberVariable->getWritableType().getQualifier().layoutLocation = flattenData.nextLocation; + flattenData.nextLocation += intermediate.computeTypeLocationSize(memberVariable->getType(), language); + nextOutLocation = std::max(nextOutLocation, flattenData.nextLocation); + } + } + + flattenData.offsets.push_back(static_cast(flattenData.members.size())); + flattenData.members.push_back(memberVariable); + + if (linkage) + trackLinkage(*memberVariable); + + return static_cast(flattenData.offsets.size()) - 1; // location of the member reference + } else { + // Further recursion required + return flatten(variable, type, flattenData, memberName, linkage, outerQualifier, builtInArraySizes); + } +} + +// Figure out the mapping between an aggregate's top members and an +// equivalent set of individual variables. +// +// Assumes shouldFlatten() or equivalent was called first. +int HlslParseContext::flattenStruct(const TVariable& variable, const TType& type, + TFlattenData& flattenData, TString name, bool linkage, + const TQualifier& outerQualifier, + const TArraySizes* builtInArraySizes) +{ + assert(type.isStruct()); + + auto members = *type.getStruct(); + + // Reserve space for this tree level. + int start = static_cast(flattenData.offsets.size()); + int pos = start; + flattenData.offsets.resize(int(pos + members.size()), -1); + + for (int member = 0; member < (int)members.size(); ++member) { + TType& dereferencedType = *members[member].type; + if (dereferencedType.isBuiltIn()) + splitBuiltIn(variable.getName(), dereferencedType, builtInArraySizes, outerQualifier); + else { + const int mpos = addFlattenedMember(variable, dereferencedType, flattenData, + name + "." + dereferencedType.getFieldName(), + linkage, outerQualifier, + builtInArraySizes == nullptr && dereferencedType.isArray() + ? dereferencedType.getArraySizes() + : builtInArraySizes); + flattenData.offsets[pos++] = mpos; + } + } + + return start; +} + +// Figure out mapping between an array's members and an +// equivalent set of individual variables. +// +// Assumes shouldFlatten() or equivalent was called first. +int HlslParseContext::flattenArray(const TVariable& variable, const TType& type, + TFlattenData& flattenData, TString name, bool linkage, + const TQualifier& outerQualifier) +{ + assert(type.isSizedArray()); + + const int size = type.getOuterArraySize(); + const TType dereferencedType(type, 0); + + if (name.empty()) + name = variable.getName(); + + // Reserve space for this tree level. + int start = static_cast(flattenData.offsets.size()); + int pos = start; + flattenData.offsets.resize(int(pos + size), -1); + + for (int element=0; element < size; ++element) { + char elementNumBuf[20]; // sufficient for MAXINT + snprintf(elementNumBuf, sizeof(elementNumBuf)-1, "[%d]", element); + const int mpos = addFlattenedMember(variable, dereferencedType, flattenData, + name + elementNumBuf, linkage, outerQualifier, + type.getArraySizes()); + + flattenData.offsets[pos++] = mpos; + } + + return start; +} + +// Return true if we have flattened this node. +bool HlslParseContext::wasFlattened(const TIntermTyped* node) const +{ + return node != nullptr && node->getAsSymbolNode() != nullptr && + wasFlattened(node->getAsSymbolNode()->getId()); +} + +// Return true if we have split this structure +bool HlslParseContext::wasSplit(const TIntermTyped* node) const +{ + return node != nullptr && node->getAsSymbolNode() != nullptr && + wasSplit(node->getAsSymbolNode()->getId()); +} + +// Turn an access into an aggregate that was flattened to instead be +// an access to the individual variable the member was flattened to. +// Assumes wasFlattened() or equivalent was called first. +TIntermTyped* HlslParseContext::flattenAccess(TIntermTyped* base, int member) +{ + const TType dereferencedType(base->getType(), member); // dereferenced type + const TIntermSymbol& symbolNode = *base->getAsSymbolNode(); + TIntermTyped* flattened = flattenAccess(symbolNode.getId(), member, base->getQualifier().storage, + dereferencedType, symbolNode.getFlattenSubset()); + + return flattened ? flattened : base; +} +TIntermTyped* HlslParseContext::flattenAccess(int uniqueId, int member, TStorageQualifier outerStorage, + const TType& dereferencedType, int subset) +{ + const auto flattenData = flattenMap.find(uniqueId); + + if (flattenData == flattenMap.end()) + return nullptr; + + // Calculate new cumulative offset from the packed tree + int newSubset = flattenData->second.offsets[subset >= 0 ? subset + member : member]; + + TIntermSymbol* subsetSymbol; + if (!shouldFlatten(dereferencedType, outerStorage, false)) { + // Finished flattening: create symbol for variable + member = flattenData->second.offsets[newSubset]; + const TVariable* memberVariable = flattenData->second.members[member]; + subsetSymbol = intermediate.addSymbol(*memberVariable); + subsetSymbol->setFlattenSubset(-1); + } else { + + // If this is not the final flattening, accumulate the position and return + // an object of the partially dereferenced type. + subsetSymbol = new TIntermSymbol(uniqueId, "flattenShadow", dereferencedType); + subsetSymbol->setFlattenSubset(newSubset); + } + + return subsetSymbol; +} + +// For finding where the first leaf is in a subtree of a multi-level aggregate +// that is just getting a subset assigned. Follows the same logic as flattenAccess, +// but logically going down the "left-most" tree branch each step of the way. +// +// Returns the offset into the first leaf of the subset. +int HlslParseContext::findSubtreeOffset(const TIntermNode& node) const +{ + const TIntermSymbol* sym = node.getAsSymbolNode(); + if (sym == nullptr) + return 0; + if (!sym->isArray() && !sym->isStruct()) + return 0; + int subset = sym->getFlattenSubset(); + if (subset == -1) + return 0; + + // Getting this far means a partial aggregate is identified by the flatten subset. + // Find the first leaf of the subset. + + const auto flattenData = flattenMap.find(sym->getId()); + if (flattenData == flattenMap.end()) + return 0; + + return findSubtreeOffset(sym->getType(), subset, flattenData->second.offsets); + + do { + subset = flattenData->second.offsets[subset]; + } while (true); +} +// Recursively do the desent +int HlslParseContext::findSubtreeOffset(const TType& type, int subset, const TVector& offsets) const +{ + if (!type.isArray() && !type.isStruct()) + return offsets[subset]; + TType derefType(type, 0); + return findSubtreeOffset(derefType, offsets[subset], offsets); +}; + +// Find and return the split IO TVariable for id, or nullptr if none. +TVariable* HlslParseContext::getSplitNonIoVar(int id) const +{ + const auto splitNonIoVar = splitNonIoVars.find(id); + if (splitNonIoVar == splitNonIoVars.end()) + return nullptr; + + return splitNonIoVar->second; +} + +// Pass through to base class after remembering built-in mappings. +void HlslParseContext::trackLinkage(TSymbol& symbol) +{ + TBuiltInVariable biType = symbol.getType().getQualifier().builtIn; + + if (biType != EbvNone) + builtInTessLinkageSymbols[biType] = symbol.clone(); + + TParseContextBase::trackLinkage(symbol); +} + + +// Returns true if the built-in is a clip or cull distance variable. +bool HlslParseContext::isClipOrCullDistance(TBuiltInVariable builtIn) +{ + return builtIn == EbvClipDistance || builtIn == EbvCullDistance; +} + +// Some types require fixed array sizes in SPIR-V, but can be scalars or +// arrays of sizes SPIR-V doesn't allow. For example, tessellation factors. +// This creates the right size. A conversion is performed when the internal +// type is copied to or from the external type. This corrects the externally +// facing input or output type to abide downstream semantics. +void HlslParseContext::fixBuiltInIoType(TType& type) +{ + int requiredArraySize = 0; + int requiredVectorSize = 0; + + switch (type.getQualifier().builtIn) { + case EbvTessLevelOuter: requiredArraySize = 4; break; + case EbvTessLevelInner: requiredArraySize = 2; break; + + case EbvSampleMask: + { + // Promote scalar to array of size 1. Leave existing arrays alone. + if (!type.isArray()) + requiredArraySize = 1; + break; + } + + case EbvWorkGroupId: requiredVectorSize = 3; break; + case EbvGlobalInvocationId: requiredVectorSize = 3; break; + case EbvLocalInvocationId: requiredVectorSize = 3; break; + case EbvTessCoord: requiredVectorSize = 3; break; + + default: + if (isClipOrCullDistance(type)) { + const int loc = type.getQualifier().layoutLocation; + + if (type.getQualifier().builtIn == EbvClipDistance) { + if (type.getQualifier().storage == EvqVaryingIn) + clipSemanticNSizeIn[loc] = type.getVectorSize(); + else + clipSemanticNSizeOut[loc] = type.getVectorSize(); + } else { + if (type.getQualifier().storage == EvqVaryingIn) + cullSemanticNSizeIn[loc] = type.getVectorSize(); + else + cullSemanticNSizeOut[loc] = type.getVectorSize(); + } + } + + return; + } + + // Alter or set vector size as needed. + if (requiredVectorSize > 0) { + TType newType(type.getBasicType(), type.getQualifier().storage, requiredVectorSize); + newType.getQualifier() = type.getQualifier(); + + type.shallowCopy(newType); + } + + // Alter or set array size as needed. + if (requiredArraySize > 0) { + if (!type.isArray() || type.getOuterArraySize() != requiredArraySize) { + TArraySizes* arraySizes = new TArraySizes; + arraySizes->addInnerSize(requiredArraySize); + type.transferArraySizes(arraySizes); + } + } +} + +// Variables that correspond to the user-interface in and out of a stage +// (not the built-in interface) are +// - assigned locations +// - registered as a linkage node (part of the stage's external interface). +// Assumes it is called in the order in which locations should be assigned. +void HlslParseContext::assignToInterface(TVariable& variable) +{ + const auto assignLocation = [&](TVariable& variable) { + TType& type = variable.getWritableType(); + if (!type.isStruct() || type.getStruct()->size() > 0) { + TQualifier& qualifier = type.getQualifier(); + if (qualifier.storage == EvqVaryingIn || qualifier.storage == EvqVaryingOut) { + if (qualifier.builtIn == EbvNone && !qualifier.hasLocation()) { + // Strip off the outer array dimension for those having an extra one. + int size; + if (type.isArray() && qualifier.isArrayedIo(language)) { + TType elementType(type, 0); + size = intermediate.computeTypeLocationSize(elementType, language); + } else + size = intermediate.computeTypeLocationSize(type, language); + + if (qualifier.storage == EvqVaryingIn) { + variable.getWritableType().getQualifier().layoutLocation = nextInLocation; + nextInLocation += size; + } else { + variable.getWritableType().getQualifier().layoutLocation = nextOutLocation; + nextOutLocation += size; + } + } + trackLinkage(variable); + } + } + }; + + if (wasFlattened(variable.getUniqueId())) { + auto& memberList = flattenMap[variable.getUniqueId()].members; + for (auto member = memberList.begin(); member != memberList.end(); ++member) + assignLocation(**member); + } else if (wasSplit(variable.getUniqueId())) { + TVariable* splitIoVar = getSplitNonIoVar(variable.getUniqueId()); + assignLocation(*splitIoVar); + } else { + assignLocation(variable); + } +} + // // Handle seeing a function declarator in the grammar. This is the precursor // to recognizing a function prototype or function definition. // -TFunction* HlslParseContext::handleFunctionDeclarator(const TSourceLoc& loc, TFunction& function, bool prototype) +void HlslParseContext::handleFunctionDeclarator(const TSourceLoc& loc, TFunction& function, bool prototype) { // // Multiple declarations of the same function name are allowed. @@ -692,26 +1610,46 @@ TFunction* HlslParseContext::handleFunctionDeclarator(const TSourceLoc& loc, TFu // other forms of name collisions. if (! symbolTable.insert(function)) error(loc, "function name is redeclaration of existing name", function.getName().c_str(), ""); +} - // - // If this is a redeclaration, it could also be a definition, - // in which case, we need to use the parameter names from this one, and not the one that's - // being redeclared. So, pass back this declaration, not the one in the symbol table. - // - return &function; +// For struct buffers with counters, we must pass the counter buffer as hidden parameter. +// This adds the hidden parameter to the parameter list in 'paramNodes' if needed. +// Otherwise, it's a no-op +void HlslParseContext::addStructBufferHiddenCounterParam(const TSourceLoc& loc, TParameter& param, + TIntermAggregate*& paramNodes) +{ + if (! hasStructBuffCounter(*param.type)) + return; + + const TString counterBlockName(intermediate.addCounterBufferName(*param.name)); + + TType counterType; + counterBufferType(loc, counterType); + TVariable *variable = makeInternalVariable(counterBlockName, counterType); + + if (! symbolTable.insert(*variable)) + error(loc, "redefinition", variable->getName().c_str(), ""); + + paramNodes = intermediate.growAggregate(paramNodes, + intermediate.addSymbol(*variable, loc), + loc); } // -// Handle seeing the function prototype in front of a function definition in the grammar. +// Handle seeing the function prototype in front of a function definition in the grammar. // The body is handled after this function returns. // -TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& loc, TFunction& function) +// Returns an aggregate of parameter-symbol nodes. +// +TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& loc, TFunction& function, + const TAttributes& attributes, + TIntermNode*& entryPointTree) { currentCaller = function.getMangledName(); TSymbol* symbol = symbolTable.find(function.getMangledName()); TFunction* prevDec = symbol ? symbol->getAsFunction() : nullptr; - if (! prevDec) + if (prevDec == nullptr) error(loc, "can't find function", function.getName().c_str(), ""); // Note: 'prevDec' could be 'function' if this is the first time we've seen function // as it would have just been put in the symbol table. Otherwise, we're looking up @@ -730,12 +1668,9 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l currentFunctionType = new TType(EbtVoid); functionReturnsValue = false; - inEntrypoint = (function.getName() == intermediate.getEntryPoint().c_str()); - if (inEntrypoint) { - // parameters are actually shader-level inputs - for (int i = 0; i < function.getParamCount(); i++) - function[i].type->getQualifier().storage = EvqVaryingIn; - } + // Entry points need different I/O and other handling, transform it so the + // rest of this function doesn't care. + entryPointTree = transformEntryPoint(loc, function, attributes); // // New symbol table scope for body of function plus its arguments @@ -747,7 +1682,7 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l // If the parameter has no name, it's not an error, just don't insert it // (could be used for unused args). // - // Also, accumulate the list of parameters into the HIL, so lower level code + // Also, accumulate the list of parameters into the AST, so lower level code // knows where to find parameters. // TIntermAggregate* paramNodes = new TIntermAggregate; @@ -756,33 +1691,670 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l if (param.name != nullptr) { TVariable *variable = new TVariable(param.name, *param.type); + if (i == 0 && function.hasImplicitThis()) { + // Anonymous 'this' members are already in a symbol-table level, + // and we need to know what function parameter to map them to. + symbolTable.makeInternalVariable(*variable); + pushImplicitThis(variable); + } + // Insert the parameters with name in the symbol table. if (! symbolTable.insert(*variable)) error(loc, "redefinition", variable->getName().c_str(), ""); - else { - // Transfer ownership of name pointer to symbol table. - param.name = nullptr; - // Add the parameter to the HIL + // Add parameters to the AST list. + if (shouldFlatten(variable->getType(), variable->getType().getQualifier().storage, true)) { + // Expand the AST parameter nodes (but not the name mangling or symbol table view) + // for structures that need to be flattened. + flatten(*variable, false); + const TTypeList* structure = variable->getType().getStruct(); + for (int mem = 0; mem < (int)structure->size(); ++mem) { + paramNodes = intermediate.growAggregate(paramNodes, + flattenAccess(variable->getUniqueId(), mem, + variable->getType().getQualifier().storage, + *(*structure)[mem].type), + loc); + } + } else { + // Add the parameter to the AST paramNodes = intermediate.growAggregate(paramNodes, - intermediate.addSymbol(*variable, loc), - loc); + intermediate.addSymbol(*variable, loc), + loc); } + + // Add hidden AST parameter for struct buffer counters, if needed. + addStructBufferHiddenCounterParam(loc, param, paramNodes); } else paramNodes = intermediate.growAggregate(paramNodes, intermediate.addSymbol(*param.type, loc), loc); } + if (function.hasIllegalImplicitThis()) + pushImplicitThis(nullptr); + intermediate.setAggregateOperator(paramNodes, EOpParameters, TType(EbtVoid), loc); loopNestingLevel = 0; controlFlowNestingLevel = 0; - postMainReturn = false; + postEntryPointReturn = false; return paramNodes; } -void HlslParseContext::handleFunctionArgument(TFunction* function, TIntermTyped*& arguments, TIntermTyped* newArg) +// Handle all [attrib] attribute for the shader entry point +void HlslParseContext::handleEntryPointAttributes(const TSourceLoc& loc, const TAttributes& attributes) { - TParameter param = { 0, new TType }; + for (auto it = attributes.begin(); it != attributes.end(); ++it) { + switch (it->name) { + case EatNumThreads: + { + const TIntermSequence& sequence = it->args->getSequence(); + for (int lid = 0; lid < int(sequence.size()); ++lid) + intermediate.setLocalSize(lid, sequence[lid]->getAsConstantUnion()->getConstArray()[0].getIConst()); + break; + } + case EatMaxVertexCount: + { + int maxVertexCount; + + if (! it->getInt(maxVertexCount)) { + error(loc, "invalid maxvertexcount", "", ""); + } else { + if (! intermediate.setVertices(maxVertexCount)) + error(loc, "cannot change previously set maxvertexcount attribute", "", ""); + } + break; + } + case EatPatchConstantFunc: + { + TString pcfName; + if (! it->getString(pcfName, 0, false)) { + error(loc, "invalid patch constant function", "", ""); + } else { + patchConstantFunctionName = pcfName; + } + break; + } + case EatDomain: + { + // Handle [domain("...")] + TString domainStr; + if (! it->getString(domainStr)) { + error(loc, "invalid domain", "", ""); + } else { + TLayoutGeometry domain = ElgNone; + + if (domainStr == "tri") { + domain = ElgTriangles; + } else if (domainStr == "quad") { + domain = ElgQuads; + } else if (domainStr == "isoline") { + domain = ElgIsolines; + } else { + error(loc, "unsupported domain type", domainStr.c_str(), ""); + } + + if (language == EShLangTessEvaluation) { + if (! intermediate.setInputPrimitive(domain)) + error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), ""); + } else { + if (! intermediate.setOutputPrimitive(domain)) + error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), ""); + } + } + break; + } + case EatOutputTopology: + { + // Handle [outputtopology("...")] + TString topologyStr; + if (! it->getString(topologyStr)) { + error(loc, "invalid outputtopology", "", ""); + } else { + TVertexOrder vertexOrder = EvoNone; + TLayoutGeometry primitive = ElgNone; + + if (topologyStr == "point") { + intermediate.setPointMode(); + } else if (topologyStr == "line") { + primitive = ElgIsolines; + } else if (topologyStr == "triangle_cw") { + vertexOrder = EvoCw; + primitive = ElgTriangles; + } else if (topologyStr == "triangle_ccw") { + vertexOrder = EvoCcw; + primitive = ElgTriangles; + } else { + error(loc, "unsupported outputtopology type", topologyStr.c_str(), ""); + } + + if (vertexOrder != EvoNone) { + if (! intermediate.setVertexOrder(vertexOrder)) { + error(loc, "cannot change previously set outputtopology", + TQualifier::getVertexOrderString(vertexOrder), ""); + } + } + if (primitive != ElgNone) + intermediate.setOutputPrimitive(primitive); + } + break; + } + case EatPartitioning: + { + // Handle [partitioning("...")] + TString partitionStr; + if (! it->getString(partitionStr)) { + error(loc, "invalid partitioning", "", ""); + } else { + TVertexSpacing partitioning = EvsNone; + + if (partitionStr == "integer") { + partitioning = EvsEqual; + } else if (partitionStr == "fractional_even") { + partitioning = EvsFractionalEven; + } else if (partitionStr == "fractional_odd") { + partitioning = EvsFractionalOdd; + //} else if (partition == "pow2") { // TODO: currently nothing to map this to. + } else { + error(loc, "unsupported partitioning type", partitionStr.c_str(), ""); + } + + if (! intermediate.setVertexSpacing(partitioning)) + error(loc, "cannot change previously set partitioning", + TQualifier::getVertexSpacingString(partitioning), ""); + } + break; + } + case EatOutputControlPoints: + { + // Handle [outputcontrolpoints("...")] + int ctrlPoints; + if (! it->getInt(ctrlPoints)) { + error(loc, "invalid outputcontrolpoints", "", ""); + } else { + if (! intermediate.setVertices(ctrlPoints)) { + error(loc, "cannot change previously set outputcontrolpoints attribute", "", ""); + } + } + break; + } + case EatBuiltIn: + case EatLocation: + // tolerate these because of dual use of entrypoint and type attributes + break; + default: + warn(loc, "attribute does not apply to entry point", "", ""); + break; + } + } +} + +// Update the given type with any type-like attribute information in the +// attributes. +void HlslParseContext::transferTypeAttributes(const TSourceLoc& loc, const TAttributes& attributes, TType& type, + bool allowEntry) +{ + if (attributes.size() == 0) + return; + + int value; + TString builtInString; + for (auto it = attributes.begin(); it != attributes.end(); ++it) { + switch (it->name) { + case EatLocation: + // location + if (it->getInt(value)) + type.getQualifier().layoutLocation = value; + break; + case EatBinding: + // binding + if (it->getInt(value)) { + type.getQualifier().layoutBinding = value; + type.getQualifier().layoutSet = 0; + } + // set + if (it->getInt(value, 1)) + type.getQualifier().layoutSet = value; + break; + case EatGlobalBinding: + // global cbuffer binding + if (it->getInt(value)) + globalUniformBinding = value; + // global cbuffer binding + if (it->getInt(value, 1)) + globalUniformSet = value; + break; + case EatInputAttachment: + // input attachment + if (it->getInt(value)) + type.getQualifier().layoutAttachment = value; + break; + case EatBuiltIn: + // PointSize built-in + if (it->getString(builtInString, 0, false)) { + if (builtInString == "PointSize") + type.getQualifier().builtIn = EbvPointSize; + } + break; + case EatPushConstant: + // push_constant + type.getQualifier().layoutPushConstant = true; + break; + case EatConstantId: + // specialization constant + if (it->getInt(value)) { + TSourceLoc loc; + loc.init(); + setSpecConstantId(loc, type.getQualifier(), value); + } + break; + default: + if (! allowEntry) + warn(loc, "attribute does not apply to a type", "", ""); + break; + } + } +} + +// +// Do all special handling for the entry point, including wrapping +// the shader's entry point with the official entry point that will call it. +// +// The following: +// +// retType shaderEntryPoint(args...) // shader declared entry point +// { body } +// +// Becomes +// +// out retType ret; +// in iargs...; +// out oargs ...; +// +// void shaderEntryPoint() // synthesized, but official, entry point +// { +// args = iargs...; +// ret = @shaderEntryPoint(args...); +// oargs = args...; +// } +// retType @shaderEntryPoint(args...) +// { body } +// +// The symbol table will still map the original entry point name to the +// the modified function and its new name: +// +// symbol table: shaderEntryPoint -> @shaderEntryPoint +// +// Returns nullptr if no entry-point tree was built, otherwise, returns +// a subtree that creates the entry point. +// +TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunction& userFunction, + const TAttributes& attributes) +{ + // Return true if this is a tessellation patch constant function input to a domain shader. + const auto isDsPcfInput = [this](const TType& type) { + return language == EShLangTessEvaluation && + type.contains([](const TType* t) { + return t->getQualifier().builtIn == EbvTessLevelOuter || + t->getQualifier().builtIn == EbvTessLevelInner; + }); + }; + + // if we aren't in the entry point, fix the IO as such and exit + if (userFunction.getName().compare(intermediate.getEntryPointName().c_str()) != 0) { + remapNonEntryPointIO(userFunction); + return nullptr; + } + + entryPointFunction = &userFunction; // needed in finish() + + // Handle entry point attributes + handleEntryPointAttributes(loc, attributes); + + // entry point logic... + + // Move parameters and return value to shader in/out + TVariable* entryPointOutput; // gets created in remapEntryPointIO + TVector inputs; + TVector outputs; + remapEntryPointIO(userFunction, entryPointOutput, inputs, outputs); + + // Further this return/in/out transform by flattening, splitting, and assigning locations + const auto makeVariableInOut = [&](TVariable& variable) { + if (variable.getType().isStruct()) { + if (variable.getType().getQualifier().isArrayedIo(language)) { + if (variable.getType().containsBuiltIn()) + split(variable); + } else if (shouldFlatten(variable.getType(), EvqVaryingIn /* not assigned yet, but close enough */, true)) + flatten(variable, false /* don't track linkage here, it will be tracked in assignToInterface() */); + } + // TODO: flatten arrays too + // TODO: flatten everything in I/O + // TODO: replace all split with flatten, make all paths can create flattened I/O, then split code can be removed + + // For clip and cull distance, multiple output variables potentially get merged + // into one in assignClipCullDistance. That code in assignClipCullDistance + // handles the interface logic, so we avoid it here in that case. + if (!isClipOrCullDistance(variable.getType())) + assignToInterface(variable); + }; + if (entryPointOutput != nullptr) + makeVariableInOut(*entryPointOutput); + for (auto it = inputs.begin(); it != inputs.end(); ++it) + if (!isDsPcfInput((*it)->getType())) // wait until the end for PCF input (see comment below) + makeVariableInOut(*(*it)); + for (auto it = outputs.begin(); it != outputs.end(); ++it) + makeVariableInOut(*(*it)); + + // In the domain shader, PCF input must be at the end of the linkage. That's because in the + // hull shader there is no ordering: the output comes from the separate PCF, which does not + // participate in the argument list. That is always put at the end of the HS linkage, so the + // input side of the DS must match. The argument may be in any position in the DS argument list + // however, so this ensures the linkage is built in the correct order regardless of argument order. + if (language == EShLangTessEvaluation) { + for (auto it = inputs.begin(); it != inputs.end(); ++it) + if (isDsPcfInput((*it)->getType())) + makeVariableInOut(*(*it)); + } + + // Synthesize the call + + pushScope(); // matches the one in handleFunctionBody() + + // new signature + TType voidType(EbtVoid); + TFunction synthEntryPoint(&userFunction.getName(), voidType); + TIntermAggregate* synthParams = new TIntermAggregate(); + intermediate.setAggregateOperator(synthParams, EOpParameters, voidType, loc); + intermediate.setEntryPointMangledName(synthEntryPoint.getMangledName().c_str()); + intermediate.incrementEntryPointCount(); + TFunction callee(&userFunction.getName(), voidType); // call based on old name, which is still in the symbol table + + // change original name + userFunction.addPrefix("@"); // change the name in the function, but not in the symbol table + + // Copy inputs (shader-in -> calling arg), while building up the call node + TVector argVars; + TIntermAggregate* synthBody = new TIntermAggregate(); + auto inputIt = inputs.begin(); + TIntermTyped* callingArgs = nullptr; + + for (int i = 0; i < userFunction.getParamCount(); i++) { + TParameter& param = userFunction[i]; + argVars.push_back(makeInternalVariable(*param.name, *param.type)); + argVars.back()->getWritableType().getQualifier().makeTemporary(); + + // Track the input patch, which is the only non-builtin supported by hull shader PCF. + if (param.getDeclaredBuiltIn() == EbvInputPatch) + inputPatch = argVars.back(); + + TIntermSymbol* arg = intermediate.addSymbol(*argVars.back()); + handleFunctionArgument(&callee, callingArgs, arg); + if (param.type->getQualifier().isParamInput()) { + intermediate.growAggregate(synthBody, handleAssign(loc, EOpAssign, arg, + intermediate.addSymbol(**inputIt))); + inputIt++; + } + } + + // Call + currentCaller = synthEntryPoint.getMangledName(); + TIntermTyped* callReturn = handleFunctionCall(loc, &callee, callingArgs); + currentCaller = userFunction.getMangledName(); + + // Return value + if (entryPointOutput) { + TIntermTyped* returnAssign; + + // For hull shaders, the wrapped entry point return value is written to + // an array element as indexed by invocation ID, which we might have to make up. + // This is required to match SPIR-V semantics. + if (language == EShLangTessControl) { + TIntermSymbol* invocationIdSym = findTessLinkageSymbol(EbvInvocationId); + + // If there is no user declared invocation ID, we must make one. + if (invocationIdSym == nullptr) { + TType invocationIdType(EbtUint, EvqIn, 1); + TString* invocationIdName = NewPoolTString("InvocationId"); + invocationIdType.getQualifier().builtIn = EbvInvocationId; + + TVariable* variable = makeInternalVariable(*invocationIdName, invocationIdType); + + globalQualifierFix(loc, variable->getWritableType().getQualifier()); + trackLinkage(*variable); + + invocationIdSym = intermediate.addSymbol(*variable); + } + + TIntermTyped* element = intermediate.addIndex(EOpIndexIndirect, intermediate.addSymbol(*entryPointOutput), + invocationIdSym, loc); + + // Set the type of the array element being dereferenced + const TType derefElementType(entryPointOutput->getType(), 0); + element->setType(derefElementType); + + returnAssign = handleAssign(loc, EOpAssign, element, callReturn); + } else { + returnAssign = handleAssign(loc, EOpAssign, intermediate.addSymbol(*entryPointOutput), callReturn); + } + intermediate.growAggregate(synthBody, returnAssign); + } else + intermediate.growAggregate(synthBody, callReturn); + + // Output copies + auto outputIt = outputs.begin(); + for (int i = 0; i < userFunction.getParamCount(); i++) { + TParameter& param = userFunction[i]; + + // GS outputs are via emit, so we do not copy them here. + if (param.type->getQualifier().isParamOutput()) { + if (param.getDeclaredBuiltIn() == EbvGsOutputStream) { + // GS output stream does not assign outputs here: it's the Append() method + // which writes to the output, probably multiple times separated by Emit. + // We merely remember the output to use, here. + gsStreamOutput = *outputIt; + } else { + intermediate.growAggregate(synthBody, handleAssign(loc, EOpAssign, + intermediate.addSymbol(**outputIt), + intermediate.addSymbol(*argVars[i]))); + } + + outputIt++; + } + } + + // Put the pieces together to form a full function subtree + // for the synthesized entry point. + synthBody->setOperator(EOpSequence); + TIntermNode* synthFunctionDef = synthParams; + handleFunctionBody(loc, synthEntryPoint, synthBody, synthFunctionDef); + + entryPointFunctionBody = synthBody; + + return synthFunctionDef; +} + +void HlslParseContext::handleFunctionBody(const TSourceLoc& loc, TFunction& function, TIntermNode* functionBody, + TIntermNode*& node) +{ + node = intermediate.growAggregate(node, functionBody); + intermediate.setAggregateOperator(node, EOpFunction, function.getType(), loc); + node->getAsAggregate()->setName(function.getMangledName().c_str()); + + popScope(); + if (function.hasImplicitThis()) + popImplicitThis(); + + if (function.getType().getBasicType() != EbtVoid && ! functionReturnsValue) + error(loc, "function does not return a value:", "", function.getName().c_str()); +} + +// AST I/O is done through shader globals declared in the 'in' or 'out' +// storage class. An HLSL entry point has a return value, input parameters +// and output parameters. These need to get remapped to the AST I/O. +void HlslParseContext::remapEntryPointIO(TFunction& function, TVariable*& returnValue, + TVector& inputs, TVector& outputs) +{ + // We might have in input structure type with no decorations that caused it + // to look like an input type, yet it has (e.g.) interpolation types that + // must be modified that turn it into an input type. + // Hence, a missing ioTypeMap for 'input' might need to be synthesized. + const auto synthesizeEditedInput = [this](TType& type) { + // True if a type needs to be 'flat' + const auto needsFlat = [](const TType& type) { + return type.containsBasicType(EbtInt) || + type.containsBasicType(EbtUint) || + type.containsBasicType(EbtInt64) || + type.containsBasicType(EbtUint64) || + type.containsBasicType(EbtBool) || + type.containsBasicType(EbtDouble); + }; + + if (language == EShLangFragment && needsFlat(type)) { + if (type.isStruct()) { + TTypeList* finalList = nullptr; + auto it = ioTypeMap.find(type.getStruct()); + if (it == ioTypeMap.end() || it->second.input == nullptr) { + // Getting here means we have no input struct, but we need one. + auto list = new TTypeList; + for (auto member = type.getStruct()->begin(); member != type.getStruct()->end(); ++member) { + TType* newType = new TType; + newType->shallowCopy(*member->type); + TTypeLoc typeLoc = { newType, member->loc }; + list->push_back(typeLoc); + } + // install the new input type + if (it == ioTypeMap.end()) { + tIoKinds newLists = { list, nullptr, nullptr }; + ioTypeMap[type.getStruct()] = newLists; + } else + it->second.input = list; + finalList = list; + } else + finalList = it->second.input; + // edit for 'flat' + for (auto member = finalList->begin(); member != finalList->end(); ++member) { + if (needsFlat(*member->type)) { + member->type->getQualifier().clearInterpolation(); + member->type->getQualifier().flat = true; + } + } + } else { + type.getQualifier().clearInterpolation(); + type.getQualifier().flat = true; + } + } + }; + + // Do the actual work to make a type be a shader input or output variable, + // and clear the original to be non-IO (for use as a normal function parameter/return). + const auto makeIoVariable = [this](const char* name, TType& type, TStorageQualifier storage) -> TVariable* { + TVariable* ioVariable = makeInternalVariable(name, type); + clearUniformInputOutput(type.getQualifier()); + if (type.isStruct()) { + auto newLists = ioTypeMap.find(ioVariable->getType().getStruct()); + if (newLists != ioTypeMap.end()) { + if (storage == EvqVaryingIn && newLists->second.input) + ioVariable->getWritableType().setStruct(newLists->second.input); + else if (storage == EvqVaryingOut && newLists->second.output) + ioVariable->getWritableType().setStruct(newLists->second.output); + } + } + if (storage == EvqVaryingIn) { + correctInput(ioVariable->getWritableType().getQualifier()); + if (language == EShLangTessEvaluation) + if (!ioVariable->getType().isArray()) + ioVariable->getWritableType().getQualifier().patch = true; + } else { + correctOutput(ioVariable->getWritableType().getQualifier()); + } + ioVariable->getWritableType().getQualifier().storage = storage; + + fixBuiltInIoType(ioVariable->getWritableType()); + + return ioVariable; + }; + + // return value is actually a shader-scoped output (out) + if (function.getType().getBasicType() == EbtVoid) { + returnValue = nullptr; + } else { + if (language == EShLangTessControl) { + // tessellation evaluation in HLSL writes a per-ctrl-pt value, but it needs to be an + // array in SPIR-V semantics. We'll write to it indexed by invocation ID. + + returnValue = makeIoVariable("@entryPointOutput", function.getWritableType(), EvqVaryingOut); + + TType outputType; + outputType.shallowCopy(function.getType()); + + // vertices has necessarily already been set when handling entry point attributes. + TArraySizes* arraySizes = new TArraySizes; + arraySizes->addInnerSize(intermediate.getVertices()); + outputType.transferArraySizes(arraySizes); + + clearUniformInputOutput(function.getWritableType().getQualifier()); + returnValue = makeIoVariable("@entryPointOutput", outputType, EvqVaryingOut); + } else { + returnValue = makeIoVariable("@entryPointOutput", function.getWritableType(), EvqVaryingOut); + } + } + + // parameters are actually shader-scoped inputs and outputs (in or out) + for (int i = 0; i < function.getParamCount(); i++) { + TType& paramType = *function[i].type; + if (paramType.getQualifier().isParamInput()) { + synthesizeEditedInput(paramType); + TVariable* argAsGlobal = makeIoVariable(function[i].name->c_str(), paramType, EvqVaryingIn); + inputs.push_back(argAsGlobal); + } + if (paramType.getQualifier().isParamOutput()) { + TVariable* argAsGlobal = makeIoVariable(function[i].name->c_str(), paramType, EvqVaryingOut); + outputs.push_back(argAsGlobal); + } + } +} + +// An HLSL function that looks like an entry point, but is not, +// declares entry point IO built-ins, but these have to be undone. +void HlslParseContext::remapNonEntryPointIO(TFunction& function) +{ + // return value + if (function.getType().getBasicType() != EbtVoid) + clearUniformInputOutput(function.getWritableType().getQualifier()); + + // parameters. + // References to structuredbuffer types are left unmodified + for (int i = 0; i < function.getParamCount(); i++) + if (!isReference(*function[i].type)) + clearUniformInputOutput(function[i].type->getQualifier()); +} + +// Handle function returns, including type conversions to the function return type +// if necessary. +TIntermNode* HlslParseContext::handleReturnValue(const TSourceLoc& loc, TIntermTyped* value) +{ + functionReturnsValue = true; + + if (currentFunctionType->getBasicType() == EbtVoid) { + error(loc, "void function cannot return a value", "return", ""); + return intermediate.addBranch(EOpReturn, loc); + } else if (*currentFunctionType != value->getType()) { + value = intermediate.addConversion(EOpReturn, *currentFunctionType, value); + if (value && *currentFunctionType != value->getType()) + value = intermediate.addUniShapeConversion(EOpReturn, *currentFunctionType, value); + if (value == nullptr || *currentFunctionType != value->getType()) { + error(loc, "type does not match, or is not convertible to, the function's return type", "return", ""); + return value; + } + } + + return intermediate.addBranch(EOpReturn, value, loc); +} + +void HlslParseContext::handleFunctionArgument(TFunction* function, + TIntermTyped*& arguments, TIntermTyped* newArg) +{ + TParameter param = { 0, new TType, nullptr }; param.type->shallowCopy(newArg->getType()); + function->addParameter(param); if (arguments) arguments = intermediate.growAggregate(arguments, newArg); @@ -790,6 +2362,710 @@ void HlslParseContext::handleFunctionArgument(TFunction* function, TIntermTyped* arguments = newArg; } +// Position may require special handling: we can optionally invert Y. +// See: https://github.com/KhronosGroup/glslang/issues/1173 +// https://github.com/KhronosGroup/glslang/issues/494 +TIntermTyped* HlslParseContext::assignPosition(const TSourceLoc& loc, TOperator op, + TIntermTyped* left, TIntermTyped* right) +{ + // If we are not asked for Y inversion, use a plain old assign. + if (!intermediate.getInvertY()) + return intermediate.addAssign(op, left, right, loc); + + // If we get here, we should invert Y. + TIntermAggregate* assignList = nullptr; + + // If this is a complex rvalue, we don't want to dereference it many times. Create a temporary. + TVariable* rhsTempVar = nullptr; + rhsTempVar = makeInternalVariable("@position", right->getType()); + rhsTempVar->getWritableType().getQualifier().makeTemporary(); + + { + TIntermTyped* rhsTempSym = intermediate.addSymbol(*rhsTempVar, loc); + assignList = intermediate.growAggregate(assignList, + intermediate.addAssign(EOpAssign, rhsTempSym, right, loc), loc); + } + + // pos.y = -pos.y + { + const int Y = 1; + + TIntermTyped* tempSymL = intermediate.addSymbol(*rhsTempVar, loc); + TIntermTyped* tempSymR = intermediate.addSymbol(*rhsTempVar, loc); + TIntermTyped* index = intermediate.addConstantUnion(Y, loc); + + TIntermTyped* lhsElement = intermediate.addIndex(EOpIndexDirect, tempSymL, index, loc); + TIntermTyped* rhsElement = intermediate.addIndex(EOpIndexDirect, tempSymR, index, loc); + + const TType derefType(right->getType(), 0); + + lhsElement->setType(derefType); + rhsElement->setType(derefType); + + TIntermTyped* yNeg = intermediate.addUnaryMath(EOpNegative, rhsElement, loc); + + assignList = intermediate.growAggregate(assignList, intermediate.addAssign(EOpAssign, lhsElement, yNeg, loc)); + } + + // Assign the rhs temp (now with Y inversion) to the final output + { + TIntermTyped* rhsTempSym = intermediate.addSymbol(*rhsTempVar, loc); + assignList = intermediate.growAggregate(assignList, intermediate.addAssign(op, left, rhsTempSym, loc)); + } + + assert(assignList != nullptr); + assignList->setOperator(EOpSequence); + + return assignList; +} + +// Clip and cull distance require special handling due to a semantic mismatch. In HLSL, +// these can be float scalar, float vector, or arrays of float scalar or float vector. +// In SPIR-V, they are arrays of scalar floats in all cases. We must copy individual components +// (e.g, both x and y components of a float2) out into the destination float array. +// +// The values are assigned to sequential members of the output array. The inner dimension +// is vector components. The outer dimension is array elements. +TIntermAggregate* HlslParseContext::assignClipCullDistance(const TSourceLoc& loc, TOperator op, int semanticId, + TIntermTyped* left, TIntermTyped* right) +{ + switch (language) { + case EShLangFragment: + case EShLangVertex: + case EShLangGeometry: + break; + default: + error(loc, "unimplemented: clip/cull not currently implemented for this stage", "", ""); + return nullptr; + } + + TVariable** clipCullVar = nullptr; + + // Figure out if we are assigning to, or from, clip or cull distance. + const bool isOutput = isClipOrCullDistance(left->getType()); + + // This is the rvalue or lvalue holding the clip or cull distance. + TIntermTyped* clipCullNode = isOutput ? left : right; + // This is the value going into or out of the clip or cull distance. + TIntermTyped* internalNode = isOutput ? right : left; + + const TBuiltInVariable builtInType = clipCullNode->getQualifier().builtIn; + + decltype(clipSemanticNSizeIn)* semanticNSize = nullptr; + + // Refer to either the clip or the cull distance, depending on semantic. + switch (builtInType) { + case EbvClipDistance: + clipCullVar = isOutput ? &clipDistanceOutput : &clipDistanceInput; + semanticNSize = isOutput ? &clipSemanticNSizeOut : &clipSemanticNSizeIn; + break; + case EbvCullDistance: + clipCullVar = isOutput ? &cullDistanceOutput : &cullDistanceInput; + semanticNSize = isOutput ? &cullSemanticNSizeOut : &cullSemanticNSizeIn; + break; + + // called invalidly: we expected a clip or a cull distance. + // static compile time problem: should not happen. + default: assert(0); return nullptr; + } + + // This is the offset in the destination array of a given semantic's data + std::array semanticOffset; + + // Calculate offset of variable of semantic N in destination array + int arrayLoc = 0; + int vecItems = 0; + + for (int x = 0; x < maxClipCullRegs; ++x) { + // See if we overflowed the vec4 packing + if ((vecItems + (*semanticNSize)[x]) > 4) { + arrayLoc = (arrayLoc + 3) & (~0x3); // round up to next multiple of 4 + vecItems = 0; + } + + semanticOffset[x] = arrayLoc; + vecItems += (*semanticNSize)[x]; + arrayLoc += (*semanticNSize)[x]; + } + + + // It can have up to 2 array dimensions (in the case of geometry shader inputs) + const TArraySizes* const internalArraySizes = internalNode->getType().getArraySizes(); + const int internalArrayDims = internalNode->getType().isArray() ? internalArraySizes->getNumDims() : 0; + // vector sizes: + const int internalVectorSize = internalNode->getType().getVectorSize(); + // array sizes, or 1 if it's not an array: + const int internalInnerArraySize = (internalArrayDims > 0 ? internalArraySizes->getDimSize(internalArrayDims-1) : 1); + const int internalOuterArraySize = (internalArrayDims > 1 ? internalArraySizes->getDimSize(0) : 1); + + // The created type may be an array of arrays, e.g, for geometry shader inputs. + const bool isImplicitlyArrayed = (language == EShLangGeometry && !isOutput); + + // If we haven't created the output already, create it now. + if (*clipCullVar == nullptr) { + // ClipDistance and CullDistance are handled specially in the entry point input/output copy + // algorithm, because they may need to be unpacked from components of vectors (or a scalar) + // into a float array, or vice versa. Here, we make the array the right size and type, + // which depends on the incoming data, which has several potential dimensions: + // * Semantic ID + // * vector size + // * array size + // Of those, semantic ID and array size cannot appear simultaneously. + // + // Also to note: for implicitly arrayed forms (e.g, geometry shader inputs), we need to create two + // array dimensions. The shader's declaration may have one or two array dimensions. One is always + // the geometry's dimension. + + const bool useInnerSize = internalArrayDims > 1 || !isImplicitlyArrayed; + + const int requiredInnerArraySize = arrayLoc * (useInnerSize ? internalInnerArraySize : 1); + const int requiredOuterArraySize = (internalArrayDims > 0) ? internalArraySizes->getDimSize(0) : 1; + + TType clipCullType(EbtFloat, clipCullNode->getType().getQualifier().storage, 1); + clipCullType.getQualifier() = clipCullNode->getType().getQualifier(); + + // Create required array dimension + TArraySizes* arraySizes = new TArraySizes; + if (isImplicitlyArrayed) + arraySizes->addInnerSize(requiredOuterArraySize); + arraySizes->addInnerSize(requiredInnerArraySize); + clipCullType.transferArraySizes(arraySizes); + + // Obtain symbol name: we'll use that for the symbol we introduce. + TIntermSymbol* sym = clipCullNode->getAsSymbolNode(); + assert(sym != nullptr); + + // We are moving the semantic ID from the layout location, so it is no longer needed or + // desired there. + clipCullType.getQualifier().layoutLocation = TQualifier::layoutLocationEnd; + + // Create variable and track its linkage + *clipCullVar = makeInternalVariable(sym->getName().c_str(), clipCullType); + + trackLinkage(**clipCullVar); + } + + // Create symbol for the clip or cull variable. + TIntermSymbol* clipCullSym = intermediate.addSymbol(**clipCullVar); + + // vector sizes: + const int clipCullVectorSize = clipCullSym->getType().getVectorSize(); + + // array sizes, or 1 if it's not an array: + const TArraySizes* const clipCullArraySizes = clipCullSym->getType().getArraySizes(); + const int clipCullOuterArraySize = isImplicitlyArrayed ? clipCullArraySizes->getDimSize(0) : 1; + const int clipCullInnerArraySize = clipCullArraySizes->getDimSize(isImplicitlyArrayed ? 1 : 0); + + // clipCullSym has got to be an array of scalar floats, per SPIR-V semantics. + // fixBuiltInIoType() should have handled that upstream. + assert(clipCullSym->getType().isArray()); + assert(clipCullSym->getType().getVectorSize() == 1); + assert(clipCullSym->getType().getBasicType() == EbtFloat); + + // We may be creating multiple sub-assignments. This is an aggregate to hold them. + // TODO: it would be possible to be clever sometimes and avoid the sequence node if not needed. + TIntermAggregate* assignList = nullptr; + + // Holds individual component assignments as we make them. + TIntermTyped* clipCullAssign = nullptr; + + // If the types are homomorphic, use a simple assign. No need to mess about with + // individual components. + if (clipCullSym->getType().isArray() == internalNode->getType().isArray() && + clipCullInnerArraySize == internalInnerArraySize && + clipCullOuterArraySize == internalOuterArraySize && + clipCullVectorSize == internalVectorSize) { + + if (isOutput) + clipCullAssign = intermediate.addAssign(op, clipCullSym, internalNode, loc); + else + clipCullAssign = intermediate.addAssign(op, internalNode, clipCullSym, loc); + + assignList = intermediate.growAggregate(assignList, clipCullAssign); + assignList->setOperator(EOpSequence); + + return assignList; + } + + // We are going to copy each component of the internal (per array element if indicated) to sequential + // array elements of the clipCullSym. This tracks the lhs element we're writing to as we go along. + // We may be starting in the middle - e.g, for a non-zero semantic ID calculated above. + int clipCullInnerArrayPos = semanticOffset[semanticId]; + int clipCullOuterArrayPos = 0; + + // Lambda to add an index to a node, set the type of the result, and return the new node. + const auto addIndex = [this, &loc](TIntermTyped* node, int pos) -> TIntermTyped* { + const TType derefType(node->getType(), 0); + node = intermediate.addIndex(EOpIndexDirect, node, intermediate.addConstantUnion(pos, loc), loc); + node->setType(derefType); + return node; + }; + + // Loop through every component of every element of the internal, and copy to or from the matching external. + for (int internalOuterArrayPos = 0; internalOuterArrayPos < internalOuterArraySize; ++internalOuterArrayPos) { + for (int internalInnerArrayPos = 0; internalInnerArrayPos < internalInnerArraySize; ++internalInnerArrayPos) { + for (int internalComponent = 0; internalComponent < internalVectorSize; ++internalComponent) { + // clip/cull array member to read from / write to: + TIntermTyped* clipCullMember = clipCullSym; + + // If implicitly arrayed, there is an outer array dimension involved + if (isImplicitlyArrayed) + clipCullMember = addIndex(clipCullMember, clipCullOuterArrayPos); + + // Index into proper array position for clip cull member + clipCullMember = addIndex(clipCullMember, clipCullInnerArrayPos++); + + // if needed, start over with next outer array slice. + if (isImplicitlyArrayed && clipCullInnerArrayPos >= clipCullInnerArraySize) { + clipCullInnerArrayPos = semanticOffset[semanticId]; + ++clipCullOuterArrayPos; + } + + // internal member to read from / write to: + TIntermTyped* internalMember = internalNode; + + // If internal node has outer array dimension, index appropriately. + if (internalArrayDims > 1) + internalMember = addIndex(internalMember, internalOuterArrayPos); + + // If internal node has inner array dimension, index appropriately. + if (internalArrayDims > 0) + internalMember = addIndex(internalMember, internalInnerArrayPos); + + // If internal node is a vector, extract the component of interest. + if (internalNode->getType().isVector()) + internalMember = addIndex(internalMember, internalComponent); + + // Create an assignment: output from internal to clip cull, or input from clip cull to internal. + if (isOutput) + clipCullAssign = intermediate.addAssign(op, clipCullMember, internalMember, loc); + else + clipCullAssign = intermediate.addAssign(op, internalMember, clipCullMember, loc); + + // Track assignment in the sequence. + assignList = intermediate.growAggregate(assignList, clipCullAssign); + } + } + } + + assert(assignList != nullptr); + assignList->setOperator(EOpSequence); + + return assignList; +} + +// Some simple source assignments need to be flattened to a sequence +// of AST assignments. Catch these and flatten, otherwise, pass through +// to intermediate.addAssign(). +// +// Also, assignment to matrix swizzles requires multiple component assignments, +// intercept those as well. +TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op, TIntermTyped* left, + TIntermTyped* right) +{ + if (left == nullptr || right == nullptr) + return nullptr; + + // writing to opaques will require fixing transforms + if (left->getType().containsOpaque()) + intermediate.setNeedsLegalization(); + + if (left->getAsOperator() && left->getAsOperator()->getOp() == EOpMatrixSwizzle) + return handleAssignToMatrixSwizzle(loc, op, left, right); + + // Return true if the given node is an index operation into a split variable. + const auto indexesSplit = [this](const TIntermTyped* node) -> bool { + const TIntermBinary* binaryNode = node->getAsBinaryNode(); + + if (binaryNode == nullptr) + return false; + + return (binaryNode->getOp() == EOpIndexDirect || binaryNode->getOp() == EOpIndexIndirect) && + wasSplit(binaryNode->getLeft()); + }; + + // Return true if this stage assigns clip position with potentially inverted Y + const auto assignsClipPos = [this](const TIntermTyped* node) -> bool { + return node->getType().getQualifier().builtIn == EbvPosition && + (language == EShLangVertex || language == EShLangGeometry || language == EShLangTessEvaluation); + }; + + const bool isSplitLeft = wasSplit(left) || indexesSplit(left); + const bool isSplitRight = wasSplit(right) || indexesSplit(right); + + const bool isFlattenLeft = wasFlattened(left); + const bool isFlattenRight = wasFlattened(right); + + // OK to do a single assign if neither side is split or flattened. Otherwise, + // fall through to a member-wise copy. + if (!isFlattenLeft && !isFlattenRight && !isSplitLeft && !isSplitRight) { + // Clip and cull distance requires more processing. See comment above assignClipCullDistance. + if (isClipOrCullDistance(left->getType()) || isClipOrCullDistance(right->getType())) { + const bool isOutput = isClipOrCullDistance(left->getType()); + + const int semanticId = (isOutput ? left : right)->getType().getQualifier().layoutLocation; + return assignClipCullDistance(loc, op, semanticId, left, right); + } else if (assignsClipPos(left)) { + // Position can require special handling: see comment above assignPosition + return assignPosition(loc, op, left, right); + } else if (left->getQualifier().builtIn == EbvSampleMask) { + // Certain builtins are required to be arrayed outputs in SPIR-V, but may internally be scalars + // in the shader. Copy the scalar RHS into the LHS array element zero, if that happens. + if (left->isArray() && !right->isArray()) { + const TType derefType(left->getType(), 0); + left = intermediate.addIndex(EOpIndexDirect, left, intermediate.addConstantUnion(0, loc), loc); + left->setType(derefType); + // Fall through to add assign. + } + } + + return intermediate.addAssign(op, left, right, loc); + } + + TIntermAggregate* assignList = nullptr; + const TVector* leftVariables = nullptr; + const TVector* rightVariables = nullptr; + + // A temporary to store the right node's value, so we don't keep indirecting into it + // if it's not a simple symbol. + TVariable* rhsTempVar = nullptr; + + // If the RHS is a simple symbol node, we'll copy it for each member. + TIntermSymbol* cloneSymNode = nullptr; + + int memberCount = 0; + + // Track how many items there are to copy. + if (left->getType().isStruct()) + memberCount = (int)left->getType().getStruct()->size(); + if (left->getType().isArray()) + memberCount = left->getType().getCumulativeArraySize(); + + if (isFlattenLeft) + leftVariables = &flattenMap.find(left->getAsSymbolNode()->getId())->second.members; + + if (isFlattenRight) { + rightVariables = &flattenMap.find(right->getAsSymbolNode()->getId())->second.members; + } else { + // The RHS is not flattened. There are several cases: + // 1. 1 item to copy: Use the RHS directly. + // 2. >1 item, simple symbol RHS: we'll create a new TIntermSymbol node for each, but no assign to temp. + // 3. >1 item, complex RHS: assign it to a new temp variable, and create a TIntermSymbol for each member. + + if (memberCount <= 1) { + // case 1: we'll use the symbol directly below. Nothing to do. + } else { + if (right->getAsSymbolNode() != nullptr) { + // case 2: we'll copy the symbol per iteration below. + cloneSymNode = right->getAsSymbolNode(); + } else { + // case 3: assign to a temp, and indirect into that. + rhsTempVar = makeInternalVariable("flattenTemp", right->getType()); + rhsTempVar->getWritableType().getQualifier().makeTemporary(); + TIntermTyped* noFlattenRHS = intermediate.addSymbol(*rhsTempVar, loc); + + // Add this to the aggregate being built. + assignList = intermediate.growAggregate(assignList, + intermediate.addAssign(op, noFlattenRHS, right, loc), loc); + } + } + } + + // When dealing with split arrayed structures of built-ins, the arrayness is moved to the extracted built-in + // variables, which is awkward when copying between split and unsplit structures. This variable tracks + // array indirections so they can be percolated from outer structs to inner variables. + std::vector arrayElement; + + TStorageQualifier leftStorage = left->getType().getQualifier().storage; + TStorageQualifier rightStorage = right->getType().getQualifier().storage; + + int leftOffset = findSubtreeOffset(*left); + int rightOffset = findSubtreeOffset(*right); + + const auto getMember = [&](bool isLeft, const TType& type, int member, TIntermTyped* splitNode, int splitMember, + bool flattened) + -> TIntermTyped * { + const bool split = isLeft ? isSplitLeft : isSplitRight; + + TIntermTyped* subTree; + const TType derefType(type, member); + const TVariable* builtInVar = nullptr; + if ((flattened || split) && derefType.isBuiltIn()) { + auto splitPair = splitBuiltIns.find(HlslParseContext::tInterstageIoData( + derefType.getQualifier().builtIn, + isLeft ? leftStorage : rightStorage)); + if (splitPair != splitBuiltIns.end()) + builtInVar = splitPair->second; + } + if (builtInVar != nullptr) { + // copy from interstage IO built-in if needed + subTree = intermediate.addSymbol(*builtInVar); + + if (subTree->getType().isArray()) { + // Arrayness of builtIn symbols isn't handled by the normal recursion: + // it's been extracted and moved to the built-in. + if (!arrayElement.empty()) { + const TType splitDerefType(subTree->getType(), arrayElement.back()); + subTree = intermediate.addIndex(EOpIndexDirect, subTree, + intermediate.addConstantUnion(arrayElement.back(), loc), loc); + subTree->setType(splitDerefType); + } else if (splitNode->getAsOperator() != nullptr && (splitNode->getAsOperator()->getOp() == EOpIndexIndirect)) { + // This might also be a stage with arrayed outputs, in which case there's an index + // operation we should transfer to the output builtin. + + const TType splitDerefType(subTree->getType(), 0); + subTree = intermediate.addIndex(splitNode->getAsOperator()->getOp(), subTree, + splitNode->getAsBinaryNode()->getRight(), loc); + subTree->setType(splitDerefType); + } + } + } else if (flattened && !shouldFlatten(derefType, isLeft ? leftStorage : rightStorage, false)) { + if (isLeft) + subTree = intermediate.addSymbol(*(*leftVariables)[leftOffset++]); + else + subTree = intermediate.addSymbol(*(*rightVariables)[rightOffset++]); + } else { + // Index operator if it's an aggregate, else EOpNull + const TOperator accessOp = type.isArray() ? EOpIndexDirect + : type.isStruct() ? EOpIndexDirectStruct + : EOpNull; + if (accessOp == EOpNull) { + subTree = splitNode; + } else { + subTree = intermediate.addIndex(accessOp, splitNode, intermediate.addConstantUnion(splitMember, loc), + loc); + const TType splitDerefType(splitNode->getType(), splitMember); + subTree->setType(splitDerefType); + } + } + + return subTree; + }; + + // Use the proper RHS node: a new symbol from a TVariable, copy + // of an TIntermSymbol node, or sometimes the right node directly. + right = rhsTempVar != nullptr ? intermediate.addSymbol(*rhsTempVar, loc) : + cloneSymNode != nullptr ? intermediate.addSymbol(*cloneSymNode) : + right; + + // Cannot use auto here, because this is recursive, and auto can't work out the type without seeing the + // whole thing. So, we'll resort to an explicit type via std::function. + const std::function + traverse = [&](TIntermTyped* left, TIntermTyped* right, TIntermTyped* splitLeft, TIntermTyped* splitRight, + bool topLevel) -> void { + // If we get here, we are assigning to or from a whole array or struct that must be + // flattened, so have to do member-by-member assignment: + + bool shouldFlattenSubsetLeft = isFlattenLeft && shouldFlatten(left->getType(), leftStorage, topLevel); + bool shouldFlattenSubsetRight = isFlattenRight && shouldFlatten(right->getType(), rightStorage, topLevel); + + if ((left->getType().isArray() || right->getType().isArray()) && + (shouldFlattenSubsetLeft || isSplitLeft || + shouldFlattenSubsetRight || isSplitRight)) { + const int elementsL = left->getType().isArray() ? left->getType().getOuterArraySize() : 1; + const int elementsR = right->getType().isArray() ? right->getType().getOuterArraySize() : 1; + + // The arrays might not be the same size, + // e.g., if the size has been forced for EbvTessLevelInner/Outer. + const int elementsToCopy = std::min(elementsL, elementsR); + + // array case + for (int element = 0; element < elementsToCopy; ++element) { + arrayElement.push_back(element); + + // Add a new AST symbol node if we have a temp variable holding a complex RHS. + TIntermTyped* subLeft = getMember(true, left->getType(), element, left, element, + shouldFlattenSubsetLeft); + TIntermTyped* subRight = getMember(false, right->getType(), element, right, element, + shouldFlattenSubsetRight); + + TIntermTyped* subSplitLeft = isSplitLeft ? getMember(true, left->getType(), element, splitLeft, + element, shouldFlattenSubsetLeft) + : subLeft; + TIntermTyped* subSplitRight = isSplitRight ? getMember(false, right->getType(), element, splitRight, + element, shouldFlattenSubsetRight) + : subRight; + + traverse(subLeft, subRight, subSplitLeft, subSplitRight, false); + + arrayElement.pop_back(); + } + } else if (left->getType().isStruct() && (shouldFlattenSubsetLeft || isSplitLeft || + shouldFlattenSubsetRight || isSplitRight)) { + // struct case + const auto& membersL = *left->getType().getStruct(); + const auto& membersR = *right->getType().getStruct(); + + // These track the members in the split structures corresponding to the same in the unsplit structures, + // which we traverse in parallel. + int memberL = 0; + int memberR = 0; + + // Handle empty structure assignment + if (int(membersL.size()) == 0 && int(membersR.size()) == 0) + assignList = intermediate.growAggregate(assignList, intermediate.addAssign(op, left, right, loc), loc); + + for (int member = 0; member < int(membersL.size()); ++member) { + const TType& typeL = *membersL[member].type; + const TType& typeR = *membersR[member].type; + + TIntermTyped* subLeft = getMember(true, left->getType(), member, left, member, + shouldFlattenSubsetLeft); + TIntermTyped* subRight = getMember(false, right->getType(), member, right, member, + shouldFlattenSubsetRight); + + // If there is no splitting, use the same values to avoid inefficiency. + TIntermTyped* subSplitLeft = isSplitLeft ? getMember(true, left->getType(), member, splitLeft, + memberL, shouldFlattenSubsetLeft) + : subLeft; + TIntermTyped* subSplitRight = isSplitRight ? getMember(false, right->getType(), member, splitRight, + memberR, shouldFlattenSubsetRight) + : subRight; + + if (isClipOrCullDistance(subSplitLeft->getType()) || isClipOrCullDistance(subSplitRight->getType())) { + // Clip and cull distance built-in assignment is complex in its own right, and is handled in + // a separate function dedicated to that task. See comment above assignClipCullDistance; + + const bool isOutput = isClipOrCullDistance(subSplitLeft->getType()); + + // Since all clip/cull semantics boil down to the same built-in type, we need to get the + // semantic ID from the dereferenced type's layout location, to avoid an N-1 mapping. + const TType derefType((isOutput ? left : right)->getType(), member); + const int semanticId = derefType.getQualifier().layoutLocation; + + TIntermAggregate* clipCullAssign = assignClipCullDistance(loc, op, semanticId, + subSplitLeft, subSplitRight); + + assignList = intermediate.growAggregate(assignList, clipCullAssign, loc); + } else if (assignsClipPos(subSplitLeft)) { + // Position can require special handling: see comment above assignPosition + TIntermTyped* positionAssign = assignPosition(loc, op, subSplitLeft, subSplitRight); + assignList = intermediate.growAggregate(assignList, positionAssign, loc); + } else if (!shouldFlattenSubsetLeft && !shouldFlattenSubsetRight && + !typeL.containsBuiltIn() && !typeR.containsBuiltIn()) { + // If this is the final flattening (no nested types below to flatten) + // we'll copy the member, else recurse into the type hierarchy. + // However, if splitting the struct, that means we can copy a whole + // subtree here IFF it does not itself contain any interstage built-in + // IO variables, so we only have to recurse into it if there's something + // for splitting to do. That can save a lot of AST verbosity for + // a bunch of memberwise copies. + + assignList = intermediate.growAggregate(assignList, + intermediate.addAssign(op, subSplitLeft, subSplitRight, loc), + loc); + } else { + traverse(subLeft, subRight, subSplitLeft, subSplitRight, false); + } + + memberL += (typeL.isBuiltIn() ? 0 : 1); + memberR += (typeR.isBuiltIn() ? 0 : 1); + } + } else { + // Member copy + assignList = intermediate.growAggregate(assignList, intermediate.addAssign(op, left, right, loc), loc); + } + + }; + + TIntermTyped* splitLeft = left; + TIntermTyped* splitRight = right; + + // If either left or right was a split structure, we must read or write it, but still have to + // parallel-recurse through the unsplit structure to identify the built-in IO vars. + // The left can be either a symbol, or an index into a symbol (e.g, array reference) + if (isSplitLeft) { + if (indexesSplit(left)) { + // Index case: Refer to the indexed symbol, if the left is an index operator. + const TIntermSymbol* symNode = left->getAsBinaryNode()->getLeft()->getAsSymbolNode(); + + TIntermTyped* splitLeftNonIo = intermediate.addSymbol(*getSplitNonIoVar(symNode->getId()), loc); + + splitLeft = intermediate.addIndex(left->getAsBinaryNode()->getOp(), splitLeftNonIo, + left->getAsBinaryNode()->getRight(), loc); + + const TType derefType(splitLeftNonIo->getType(), 0); + splitLeft->setType(derefType); + } else { + // Symbol case: otherwise, if not indexed, we have the symbol directly. + const TIntermSymbol* symNode = left->getAsSymbolNode(); + splitLeft = intermediate.addSymbol(*getSplitNonIoVar(symNode->getId()), loc); + } + } + + if (isSplitRight) + splitRight = intermediate.addSymbol(*getSplitNonIoVar(right->getAsSymbolNode()->getId()), loc); + + // This makes the whole assignment, recursing through subtypes as needed. + traverse(left, right, splitLeft, splitRight, true); + + assert(assignList != nullptr); + assignList->setOperator(EOpSequence); + + return assignList; +} + +// An assignment to matrix swizzle must be decomposed into individual assignments. +// These must be selected component-wise from the RHS and stored component-wise +// into the LHS. +TIntermTyped* HlslParseContext::handleAssignToMatrixSwizzle(const TSourceLoc& loc, TOperator op, TIntermTyped* left, + TIntermTyped* right) +{ + assert(left->getAsOperator() && left->getAsOperator()->getOp() == EOpMatrixSwizzle); + + if (op != EOpAssign) + error(loc, "only simple assignment to non-simple matrix swizzle is supported", "assign", ""); + + // isolate the matrix and swizzle nodes + TIntermTyped* matrix = left->getAsBinaryNode()->getLeft()->getAsTyped(); + const TIntermSequence& swizzle = left->getAsBinaryNode()->getRight()->getAsAggregate()->getSequence(); + + // if the RHS isn't already a simple vector, let's store into one + TIntermSymbol* vector = right->getAsSymbolNode(); + TIntermTyped* vectorAssign = nullptr; + if (vector == nullptr) { + // create a new intermediate vector variable to assign to + TType vectorType(matrix->getBasicType(), EvqTemporary, matrix->getQualifier().precision, (int)swizzle.size()/2); + vector = intermediate.addSymbol(*makeInternalVariable("intermVec", vectorType), loc); + + // assign the right to the new vector + vectorAssign = handleAssign(loc, op, vector, right); + } + + // Assign the vector components to the matrix components. + // Store this as a sequence, so a single aggregate node represents this + // entire operation. + TIntermAggregate* result = intermediate.makeAggregate(vectorAssign); + TType columnType(matrix->getType(), 0); + TType componentType(columnType, 0); + TType indexType(EbtInt); + for (int i = 0; i < (int)swizzle.size(); i += 2) { + // the right component, single index into the RHS vector + TIntermTyped* rightComp = intermediate.addIndex(EOpIndexDirect, vector, + intermediate.addConstantUnion(i/2, loc), loc); + + // the left component, double index into the LHS matrix + TIntermTyped* leftComp = intermediate.addIndex(EOpIndexDirect, matrix, + intermediate.addConstantUnion(swizzle[i]->getAsConstantUnion()->getConstArray(), + indexType, loc), + loc); + leftComp->setType(columnType); + leftComp = intermediate.addIndex(EOpIndexDirect, leftComp, + intermediate.addConstantUnion(swizzle[i+1]->getAsConstantUnion()->getConstArray(), + indexType, loc), + loc); + leftComp->setType(componentType); + + // Add the assignment to the aggregate + result = intermediate.growAggregate(result, intermediate.addAssign(op, leftComp, rightComp, loc)); + } + + result->setOp(EOpSequence); + + return result; +} + // // HLSL atomic operations have slightly different arguments than // GLSL/AST/SPIRV. The semantics are converted below in decomposeIntrinsic. @@ -798,15 +3074,15 @@ void HlslParseContext::handleFunctionArgument(TFunction* function, TIntermTyped* TOperator HlslParseContext::mapAtomicOp(const TSourceLoc& loc, TOperator op, bool isImage) { switch (op) { - case EOpInterlockedAdd: return isImage ? EOpImageAtomicAdd : EOpAtomicAdd; - case EOpInterlockedAnd: return isImage ? EOpImageAtomicAnd : EOpAtomicAnd; + case EOpInterlockedAdd: return isImage ? EOpImageAtomicAdd : EOpAtomicAdd; + case EOpInterlockedAnd: return isImage ? EOpImageAtomicAnd : EOpAtomicAnd; case EOpInterlockedCompareExchange: return isImage ? EOpImageAtomicCompSwap : EOpAtomicCompSwap; - case EOpInterlockedMax: return isImage ? EOpImageAtomicMax : EOpAtomicMax; - case EOpInterlockedMin: return isImage ? EOpImageAtomicMin : EOpAtomicMin; - case EOpInterlockedOr: return isImage ? EOpImageAtomicOr : EOpAtomicOr; - case EOpInterlockedXor: return isImage ? EOpImageAtomicXor : EOpAtomicXor; + case EOpInterlockedMax: return isImage ? EOpImageAtomicMax : EOpAtomicMax; + case EOpInterlockedMin: return isImage ? EOpImageAtomicMin : EOpAtomicMin; + case EOpInterlockedOr: return isImage ? EOpImageAtomicOr : EOpAtomicOr; + case EOpInterlockedXor: return isImage ? EOpImageAtomicXor : EOpAtomicXor; case EOpInterlockedExchange: return isImage ? EOpImageAtomicExchange : EOpAtomicExchange; - case EOpInterlockedCompareStore: // TODO: ... + case EOpInterlockedCompareStore: // TODO: ... default: error(loc, "unknown atomic operation", "unknown op", ""); return EOpNull; @@ -816,7 +3092,8 @@ TOperator HlslParseContext::mapAtomicOp(const TSourceLoc& loc, TOperator op, boo // // Create a combined sampler/texture from separate sampler and texture. // -TIntermAggregate* HlslParseContext::handleSamplerTextureCombine(const TSourceLoc& loc, TIntermTyped* argTex, TIntermTyped* argSampler) +TIntermAggregate* HlslParseContext::handleSamplerTextureCombine(const TSourceLoc& loc, TIntermTyped* argTex, + TIntermTyped* argSampler) { TIntermAggregate* txcombine = new TIntermAggregate(EOpConstructTextureSampler); @@ -826,32 +3103,673 @@ TIntermAggregate* HlslParseContext::handleSamplerTextureCombine(const TSourceLoc TSampler samplerType = argTex->getType().getSampler(); samplerType.combined = true; + // TODO: + // This block exists until the spec no longer requires shadow modes on texture objects. + // It can be deleted after that, along with the shadowTextureVariant member. + { + const bool shadowMode = argSampler->getType().getSampler().shadow; + + TIntermSymbol* texSymbol = argTex->getAsSymbolNode(); + + if (texSymbol == nullptr) + texSymbol = argTex->getAsBinaryNode()->getLeft()->getAsSymbolNode(); + + if (texSymbol == nullptr) { + error(loc, "unable to find texture symbol", "", ""); + return nullptr; + } + + // This forces the texture's shadow state to be the sampler's + // shadow state. This depends on downstream optimization to + // DCE one variant in [shadow, nonshadow] if both are present, + // or the SPIR-V module would be invalid. + int newId = texSymbol->getId(); + + // Check to see if this texture has been given a shadow mode already. + // If so, look up the one we already have. + const auto textureShadowEntry = textureShadowVariant.find(texSymbol->getId()); + + if (textureShadowEntry != textureShadowVariant.end()) + newId = textureShadowEntry->second->get(shadowMode); + else + textureShadowVariant[texSymbol->getId()] = new tShadowTextureSymbols; + + // Sometimes we have to create another symbol (if this texture has been seen before, + // and we haven't created the form for this shadow mode). + if (newId == -1) { + TType texType; + texType.shallowCopy(argTex->getType()); + texType.getSampler().shadow = shadowMode; // set appropriate shadow mode. + globalQualifierFix(loc, texType.getQualifier()); + + TVariable* newTexture = makeInternalVariable(texSymbol->getName(), texType); + + trackLinkage(*newTexture); + + newId = newTexture->getUniqueId(); + } + + assert(newId != -1); + + if (textureShadowVariant.find(newId) == textureShadowVariant.end()) + textureShadowVariant[newId] = textureShadowVariant[texSymbol->getId()]; + + textureShadowVariant[newId]->set(shadowMode, newId); + + // Remember this shadow mode in the texture and the merged type. + argTex->getWritableType().getSampler().shadow = shadowMode; + samplerType.shadow = shadowMode; + + texSymbol->switchId(newId); + } + txcombine->setType(TType(samplerType, EvqTemporary)); txcombine->setLoc(loc); return txcombine; } +// Return true if this a buffer type that has an associated counter buffer. +bool HlslParseContext::hasStructBuffCounter(const TType& type) const +{ + switch (type.getQualifier().declaredBuiltIn) { + case EbvAppendConsume: // fall through... + case EbvRWStructuredBuffer: // ... + return true; + default: + return false; // the other structuredbuffer types do not have a counter. + } +} + +void HlslParseContext::counterBufferType(const TSourceLoc& loc, TType& type) +{ + // Counter type + TType* counterType = new TType(EbtUint, EvqBuffer); + counterType->setFieldName(intermediate.implicitCounterName); + + TTypeList* blockStruct = new TTypeList; + TTypeLoc member = { counterType, loc }; + blockStruct->push_back(member); + + TType blockType(blockStruct, "", counterType->getQualifier()); + blockType.getQualifier().storage = EvqBuffer; + + type.shallowCopy(blockType); + shareStructBufferType(type); +} + +// declare counter for a structured buffer type +void HlslParseContext::declareStructBufferCounter(const TSourceLoc& loc, const TType& bufferType, const TString& name) +{ + // Bail out if not a struct buffer + if (! isStructBufferType(bufferType)) + return; + + if (! hasStructBuffCounter(bufferType)) + return; + + TType blockType; + counterBufferType(loc, blockType); + + TString* blockName = new TString(intermediate.addCounterBufferName(name)); + + // Counter buffer is not yet in use + structBufferCounter[*blockName] = false; + + shareStructBufferType(blockType); + declareBlock(loc, blockType, blockName); +} + +// return the counter that goes with a given structuredbuffer +TIntermTyped* HlslParseContext::getStructBufferCounter(const TSourceLoc& loc, TIntermTyped* buffer) +{ + // Bail out if not a struct buffer + if (buffer == nullptr || ! isStructBufferType(buffer->getType())) + return nullptr; + + const TString counterBlockName(intermediate.addCounterBufferName(buffer->getAsSymbolNode()->getName())); + + // Mark the counter as being used + structBufferCounter[counterBlockName] = true; + + TIntermTyped* counterVar = handleVariable(loc, &counterBlockName); // find the block structure + TIntermTyped* index = intermediate.addConstantUnion(0, loc); // index to counter inside block struct + + TIntermTyped* counterMember = intermediate.addIndex(EOpIndexDirectStruct, counterVar, index, loc); + counterMember->setType(TType(EbtUint)); + return counterMember; +} + +// +// Decompose structure buffer methods into AST +// +void HlslParseContext::decomposeStructBufferMethods(const TSourceLoc& loc, TIntermTyped*& node, TIntermNode* arguments) +{ + if (node == nullptr || node->getAsOperator() == nullptr || arguments == nullptr) + return; + + const TOperator op = node->getAsOperator()->getOp(); + TIntermAggregate* argAggregate = arguments->getAsAggregate(); + + // Buffer is the object upon which method is called, so always arg 0 + TIntermTyped* bufferObj = nullptr; + + // The parameters can be an aggregate, or just a the object as a symbol if there are no fn params. + if (argAggregate) { + if (argAggregate->getSequence().empty()) + return; + bufferObj = argAggregate->getSequence()[0]->getAsTyped(); + } else { + bufferObj = arguments->getAsSymbolNode(); + } + + if (bufferObj == nullptr || bufferObj->getAsSymbolNode() == nullptr) + return; + + // Some methods require a hidden internal counter, obtained via getStructBufferCounter(). + // This lambda adds something to it and returns the old value. + const auto incDecCounter = [&](int incval) -> TIntermTyped* { + TIntermTyped* incrementValue = intermediate.addConstantUnion(static_cast(incval), loc, true); + TIntermTyped* counter = getStructBufferCounter(loc, bufferObj); // obtain the counter member + + if (counter == nullptr) + return nullptr; + + TIntermAggregate* counterIncrement = new TIntermAggregate(EOpAtomicAdd); + counterIncrement->setType(TType(EbtUint, EvqTemporary)); + counterIncrement->setLoc(loc); + counterIncrement->getSequence().push_back(counter); + counterIncrement->getSequence().push_back(incrementValue); + + return counterIncrement; + }; + + // Index to obtain the runtime sized array out of the buffer. + TIntermTyped* argArray = indexStructBufferContent(loc, bufferObj); + if (argArray == nullptr) + return; // It might not be a struct buffer method. + + switch (op) { + case EOpMethodLoad: + { + TIntermTyped* argIndex = makeIntegerIndex(argAggregate->getSequence()[1]->getAsTyped()); // index + + const TType& bufferType = bufferObj->getType(); + + const TBuiltInVariable builtInType = bufferType.getQualifier().declaredBuiltIn; + + // Byte address buffers index in bytes (only multiples of 4 permitted... not so much a byte address + // buffer then, but that's what it calls itself. + const bool isByteAddressBuffer = (builtInType == EbvByteAddressBuffer || + builtInType == EbvRWByteAddressBuffer); + + + if (isByteAddressBuffer) + argIndex = intermediate.addBinaryNode(EOpRightShift, argIndex, + intermediate.addConstantUnion(2, loc, true), + loc, TType(EbtInt)); + + // Index into the array to find the item being loaded. + const TOperator idxOp = (argIndex->getQualifier().storage == EvqConst) ? EOpIndexDirect : EOpIndexIndirect; + + node = intermediate.addIndex(idxOp, argArray, argIndex, loc); + + const TType derefType(argArray->getType(), 0); + node->setType(derefType); + } + + break; + + case EOpMethodLoad2: + case EOpMethodLoad3: + case EOpMethodLoad4: + { + TIntermTyped* argIndex = makeIntegerIndex(argAggregate->getSequence()[1]->getAsTyped()); // index + + TOperator constructOp = EOpNull; + int size = 0; + + switch (op) { + case EOpMethodLoad2: size = 2; constructOp = EOpConstructVec2; break; + case EOpMethodLoad3: size = 3; constructOp = EOpConstructVec3; break; + case EOpMethodLoad4: size = 4; constructOp = EOpConstructVec4; break; + default: assert(0); + } + + TIntermTyped* body = nullptr; + + // First, we'll store the address in a variable to avoid multiple shifts + // (we must convert the byte address to an item address) + TIntermTyped* byteAddrIdx = intermediate.addBinaryNode(EOpRightShift, argIndex, + intermediate.addConstantUnion(2, loc, true), + loc, TType(EbtInt)); + + TVariable* byteAddrSym = makeInternalVariable("byteAddrTemp", TType(EbtInt, EvqTemporary)); + TIntermTyped* byteAddrIdxVar = intermediate.addSymbol(*byteAddrSym, loc); + + body = intermediate.growAggregate(body, intermediate.addAssign(EOpAssign, byteAddrIdxVar, byteAddrIdx, loc)); + + TIntermTyped* vec = nullptr; + + // These are only valid on (rw)byteaddressbuffers, so we can always perform the >>2 + // address conversion. + for (int idx=0; idxgetQualifier().storage == EvqConst) ? EOpIndexDirect + : EOpIndexIndirect; + + TIntermTyped* indexVal = intermediate.addIndex(idxOp, argArray, offsetIdx, loc); + + TType derefType(argArray->getType(), 0); + derefType.getQualifier().makeTemporary(); + indexVal->setType(derefType); + + vec = intermediate.growAggregate(vec, indexVal); + } + + vec->setType(TType(argArray->getBasicType(), EvqTemporary, size)); + vec->getAsAggregate()->setOperator(constructOp); + + body = intermediate.growAggregate(body, vec); + body->setType(vec->getType()); + body->getAsAggregate()->setOperator(EOpSequence); + + node = body; + } + + break; + + case EOpMethodStore: + case EOpMethodStore2: + case EOpMethodStore3: + case EOpMethodStore4: + { + TIntermTyped* argIndex = makeIntegerIndex(argAggregate->getSequence()[1]->getAsTyped()); // index + TIntermTyped* argValue = argAggregate->getSequence()[2]->getAsTyped(); // value + + // Index into the array to find the item being loaded. + // Byte address buffers index in bytes (only multiples of 4 permitted... not so much a byte address + // buffer then, but that's what it calls itself). + + int size = 0; + + switch (op) { + case EOpMethodStore: size = 1; break; + case EOpMethodStore2: size = 2; break; + case EOpMethodStore3: size = 3; break; + case EOpMethodStore4: size = 4; break; + default: assert(0); + } + + TIntermAggregate* body = nullptr; + + // First, we'll store the address in a variable to avoid multiple shifts + // (we must convert the byte address to an item address) + TIntermTyped* byteAddrIdx = intermediate.addBinaryNode(EOpRightShift, argIndex, + intermediate.addConstantUnion(2, loc, true), loc, TType(EbtInt)); + + TVariable* byteAddrSym = makeInternalVariable("byteAddrTemp", TType(EbtInt, EvqTemporary)); + TIntermTyped* byteAddrIdxVar = intermediate.addSymbol(*byteAddrSym, loc); + + body = intermediate.growAggregate(body, intermediate.addAssign(EOpAssign, byteAddrIdxVar, byteAddrIdx, loc)); + + for (int idx=0; idxgetQualifier().storage == EvqConst) ? EOpIndexDirect + : EOpIndexIndirect; + + TIntermTyped* lValue = intermediate.addIndex(idxOp, argArray, offsetIdx, loc); + const TType derefType(argArray->getType(), 0); + lValue->setType(derefType); + + TIntermTyped* rValue; + if (size == 1) { + rValue = argValue; + } else { + rValue = intermediate.addIndex(EOpIndexDirect, argValue, idxConst, loc); + const TType indexType(argValue->getType(), 0); + rValue->setType(indexType); + } + + TIntermTyped* assign = intermediate.addAssign(EOpAssign, lValue, rValue, loc); + + body = intermediate.growAggregate(body, assign); + } + + body->setOperator(EOpSequence); + node = body; + } + + break; + + case EOpMethodGetDimensions: + { + const int numArgs = (int)argAggregate->getSequence().size(); + TIntermTyped* argNumItems = argAggregate->getSequence()[1]->getAsTyped(); // out num items + TIntermTyped* argStride = numArgs > 2 ? argAggregate->getSequence()[2]->getAsTyped() : nullptr; // out stride + + TIntermAggregate* body = nullptr; + + // Length output: + if (argArray->getType().isSizedArray()) { + const int length = argArray->getType().getOuterArraySize(); + TIntermTyped* assign = intermediate.addAssign(EOpAssign, argNumItems, + intermediate.addConstantUnion(length, loc, true), loc); + body = intermediate.growAggregate(body, assign, loc); + } else { + TIntermTyped* lengthCall = intermediate.addBuiltInFunctionCall(loc, EOpArrayLength, true, argArray, + argNumItems->getType()); + TIntermTyped* assign = intermediate.addAssign(EOpAssign, argNumItems, lengthCall, loc); + body = intermediate.growAggregate(body, assign, loc); + } + + // Stride output: + if (argStride != nullptr) { + int size; + int stride; + intermediate.getBaseAlignment(argArray->getType(), size, stride, false, + argArray->getType().getQualifier().layoutMatrix == ElmRowMajor); + + TIntermTyped* assign = intermediate.addAssign(EOpAssign, argStride, + intermediate.addConstantUnion(stride, loc, true), loc); + + body = intermediate.growAggregate(body, assign); + } + + body->setOperator(EOpSequence); + node = body; + } + + break; + + case EOpInterlockedAdd: + case EOpInterlockedAnd: + case EOpInterlockedExchange: + case EOpInterlockedMax: + case EOpInterlockedMin: + case EOpInterlockedOr: + case EOpInterlockedXor: + case EOpInterlockedCompareExchange: + case EOpInterlockedCompareStore: + { + // We'll replace the first argument with the block dereference, and let + // downstream decomposition handle the rest. + + TIntermSequence& sequence = argAggregate->getSequence(); + + TIntermTyped* argIndex = makeIntegerIndex(sequence[1]->getAsTyped()); // index + argIndex = intermediate.addBinaryNode(EOpRightShift, argIndex, intermediate.addConstantUnion(2, loc, true), + loc, TType(EbtInt)); + + const TOperator idxOp = (argIndex->getQualifier().storage == EvqConst) ? EOpIndexDirect : EOpIndexIndirect; + TIntermTyped* element = intermediate.addIndex(idxOp, argArray, argIndex, loc); + + const TType derefType(argArray->getType(), 0); + element->setType(derefType); + + // Replace the numeric byte offset parameter with array reference. + sequence[1] = element; + sequence.erase(sequence.begin(), sequence.begin()+1); + } + break; + + case EOpMethodIncrementCounter: + { + node = incDecCounter(1); + break; + } + + case EOpMethodDecrementCounter: + { + TIntermTyped* preIncValue = incDecCounter(-1); // result is original value + node = intermediate.addBinaryNode(EOpAdd, preIncValue, intermediate.addConstantUnion(-1, loc, true), loc, + preIncValue->getType()); + break; + } + + case EOpMethodAppend: + { + TIntermTyped* oldCounter = incDecCounter(1); + + TIntermTyped* lValue = intermediate.addIndex(EOpIndexIndirect, argArray, oldCounter, loc); + TIntermTyped* rValue = argAggregate->getSequence()[1]->getAsTyped(); + + const TType derefType(argArray->getType(), 0); + lValue->setType(derefType); + + node = intermediate.addAssign(EOpAssign, lValue, rValue, loc); + + break; + } + + case EOpMethodConsume: + { + TIntermTyped* oldCounter = incDecCounter(-1); + + TIntermTyped* newCounter = intermediate.addBinaryNode(EOpAdd, oldCounter, + intermediate.addConstantUnion(-1, loc, true), loc, + oldCounter->getType()); + + node = intermediate.addIndex(EOpIndexIndirect, argArray, newCounter, loc); + + const TType derefType(argArray->getType(), 0); + node->setType(derefType); + + break; + } + + default: + break; // most pass through unchanged + } +} + +// Create array of standard sample positions for given sample count. +// TODO: remove when a real method to query sample pos exists in SPIR-V. +TIntermConstantUnion* HlslParseContext::getSamplePosArray(int count) +{ + struct tSamplePos { float x, y; }; + + static const tSamplePos pos1[] = { + { 0.0/16.0, 0.0/16.0 }, + }; + + // standard sample positions for 2, 4, 8, and 16 samples. + static const tSamplePos pos2[] = { + { 4.0/16.0, 4.0/16.0 }, {-4.0/16.0, -4.0/16.0 }, + }; + + static const tSamplePos pos4[] = { + {-2.0/16.0, -6.0/16.0 }, { 6.0/16.0, -2.0/16.0 }, {-6.0/16.0, 2.0/16.0 }, { 2.0/16.0, 6.0/16.0 }, + }; + + static const tSamplePos pos8[] = { + { 1.0/16.0, -3.0/16.0 }, {-1.0/16.0, 3.0/16.0 }, { 5.0/16.0, 1.0/16.0 }, {-3.0/16.0, -5.0/16.0 }, + {-5.0/16.0, 5.0/16.0 }, {-7.0/16.0, -1.0/16.0 }, { 3.0/16.0, 7.0/16.0 }, { 7.0/16.0, -7.0/16.0 }, + }; + + static const tSamplePos pos16[] = { + { 1.0/16.0, 1.0/16.0 }, {-1.0/16.0, -3.0/16.0 }, {-3.0/16.0, 2.0/16.0 }, { 4.0/16.0, -1.0/16.0 }, + {-5.0/16.0, -2.0/16.0 }, { 2.0/16.0, 5.0/16.0 }, { 5.0/16.0, 3.0/16.0 }, { 3.0/16.0, -5.0/16.0 }, + {-2.0/16.0, 6.0/16.0 }, { 0.0/16.0, -7.0/16.0 }, {-4.0/16.0, -6.0/16.0 }, {-6.0/16.0, 4.0/16.0 }, + {-8.0/16.0, 0.0/16.0 }, { 7.0/16.0, -4.0/16.0 }, { 6.0/16.0, 7.0/16.0 }, {-7.0/16.0, -8.0/16.0 }, + }; + + const tSamplePos* sampleLoc = nullptr; + int numSamples = count; + + switch (count) { + case 2: sampleLoc = pos2; break; + case 4: sampleLoc = pos4; break; + case 8: sampleLoc = pos8; break; + case 16: sampleLoc = pos16; break; + default: + sampleLoc = pos1; + numSamples = 1; + } + + TConstUnionArray* values = new TConstUnionArray(numSamples*2); + + for (int pos=0; posaddInnerSize(numSamples); + retType.transferArraySizes(arraySizes); + } + + return new TIntermConstantUnion(*values, retType); +} + // // Decompose DX9 and DX10 sample intrinsics & object methods into AST // void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermTyped*& node, TIntermNode* arguments) { - if (!node || !node->getAsOperator()) + if (node == nullptr || !node->getAsOperator()) return; + // Sampler return must always be a vec4, but we can construct a shorter vector or a structure from it. + const auto convertReturn = [&loc, &node, this](TIntermTyped* result, const TSampler& sampler) -> TIntermTyped* { + result->setType(TType(node->getType().getBasicType(), EvqTemporary, node->getVectorSize())); + + TIntermTyped* convertedResult = nullptr; + + TType retType; + getTextureReturnType(sampler, retType); + + if (retType.isStruct()) { + // For type convenience, conversionAggregate points to the convertedResult (we know it's an aggregate here) + TIntermAggregate* conversionAggregate = new TIntermAggregate; + convertedResult = conversionAggregate; + + // Convert vector output to return structure. We will need a temp symbol to copy the results to. + TVariable* structVar = makeInternalVariable("@sampleStructTemp", retType); + + // We also need a temp symbol to hold the result of the texture. We don't want to re-fetch the + // sample each time we'll index into the result, so we'll copy to this, and index into the copy. + TVariable* sampleShadow = makeInternalVariable("@sampleResultShadow", result->getType()); + + // Initial copy from texture to our sample result shadow. + TIntermTyped* shadowCopy = intermediate.addAssign(EOpAssign, intermediate.addSymbol(*sampleShadow, loc), + result, loc); + + conversionAggregate->getSequence().push_back(shadowCopy); + + unsigned vec4Pos = 0; + + for (unsigned m = 0; m < unsigned(retType.getStruct()->size()); ++m) { + const TType memberType(retType, m); // dereferenced type of the member we're about to assign. + + // Check for bad struct members. This should have been caught upstream. Complain, because + // wwe don't know what to do with it. This algorithm could be generalized to handle + // other things, e.g, sub-structures, but HLSL doesn't allow them. + if (!memberType.isVector() && !memberType.isScalar()) { + error(loc, "expected: scalar or vector type in texture structure", "", ""); + return nullptr; + } + + // Index into the struct variable to find the member to assign. + TIntermTyped* structMember = intermediate.addIndex(EOpIndexDirectStruct, + intermediate.addSymbol(*structVar, loc), + intermediate.addConstantUnion(m, loc), loc); + + structMember->setType(memberType); + + // Assign each component of (possible) vector in struct member. + for (int component = 0; component < memberType.getVectorSize(); ++component) { + TIntermTyped* vec4Member = intermediate.addIndex(EOpIndexDirect, + intermediate.addSymbol(*sampleShadow, loc), + intermediate.addConstantUnion(vec4Pos++, loc), loc); + vec4Member->setType(TType(memberType.getBasicType(), EvqTemporary, 1)); + + TIntermTyped* memberAssign = nullptr; + + if (memberType.isVector()) { + // Vector member: we need to create an access chain to the vector component. + + TIntermTyped* structVecComponent = intermediate.addIndex(EOpIndexDirect, structMember, + intermediate.addConstantUnion(component, loc), loc); + + memberAssign = intermediate.addAssign(EOpAssign, structVecComponent, vec4Member, loc); + } else { + // Scalar member: we can assign to it directly. + memberAssign = intermediate.addAssign(EOpAssign, structMember, vec4Member, loc); + } + + + conversionAggregate->getSequence().push_back(memberAssign); + } + } + + // Add completed variable so the expression results in the whole struct value we just built. + conversionAggregate->getSequence().push_back(intermediate.addSymbol(*structVar, loc)); + + // Make it a sequence. + intermediate.setAggregateOperator(conversionAggregate, EOpSequence, retType, loc); + } else { + // vector clamp the output if template vector type is smaller than sample result. + if (retType.getVectorSize() < node->getVectorSize()) { + // Too many components. Construct shorter vector from it. + const TOperator op = intermediate.mapTypeToConstructorOp(retType); + + convertedResult = constructBuiltIn(retType, op, result, loc, false); + } else { + // Enough components. Use directly. + convertedResult = result; + } + } + + convertedResult->setLoc(loc); + return convertedResult; + }; + const TOperator op = node->getAsOperator()->getOp(); const TIntermAggregate* argAggregate = arguments ? arguments->getAsAggregate() : nullptr; + // Bail out if not a sampler method. + // Note though this is odd to do before checking the op, because the op + // could be something that takes the arguments, and the function in question + // takes the result of the op. So, this is not the final word. + if (arguments != nullptr) { + if (argAggregate == nullptr) { + if (arguments->getAsTyped()->getBasicType() != EbtSampler) + return; + } else { + if (argAggregate->getSequence().size() == 0 || + argAggregate->getSequence()[0]->getAsTyped()->getBasicType() != EbtSampler) + return; + } + } + switch (op) { // **** DX9 intrinsics: **** case EOpTexture: { // Texture with ddx & ddy is really gradient form in HLSL - if (argAggregate->getSequence().size() == 4) { + if (argAggregate->getSequence().size() == 4) node->getAsAggregate()->setOperator(EOpTextureGrad); - break; - } break; } @@ -867,24 +3785,30 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType TIntermTyped* bias = intermediate.addIndex(EOpIndexDirect, arg1, w, loc); TOperator constructOp = EOpNull; - switch (arg0->getType().getSampler().dim) { + const TSampler& sampler = arg0->getType().getSampler(); + + switch (sampler.dim) { case Esd1D: constructOp = EOpConstructFloat; break; // 1D case Esd2D: constructOp = EOpConstructVec2; break; // 2D case Esd3D: constructOp = EOpConstructVec3; break; // 3D case EsdCube: constructOp = EOpConstructVec3; break; // also 3D default: break; } - + TIntermAggregate* constructCoord = new TIntermAggregate(constructOp); constructCoord->getSequence().push_back(arg1); constructCoord->setLoc(loc); + // The input vector should never be less than 2, since there's always a bias. + // The max is for safety, and should be a no-op. + constructCoord->setType(TType(arg1->getBasicType(), EvqTemporary, std::max(arg1->getVectorSize() - 1, 0))); + TIntermAggregate* tex = new TIntermAggregate(EOpTexture); tex->getSequence().push_back(arg0); // sampler tex->getSequence().push_back(constructCoord); // coordinate tex->getSequence().push_back(bias); // bias - tex->setLoc(loc); - node = tex; + + node = convertReturn(tex, sampler); break; } @@ -898,6 +3822,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType TIntermTyped* argCoord = argAggregate->getSequence()[2]->getAsTyped(); TIntermTyped* argBias = nullptr; TIntermTyped* argOffset = nullptr; + const TSampler& sampler = argTex->getType().getSampler(); int nextArg = 3; @@ -923,13 +3848,11 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType if (argOffset != nullptr) txsample->getSequence().push_back(argOffset); - txsample->setType(node->getType()); - txsample->setLoc(loc); - node = txsample; + node = convertReturn(txsample, sampler); break; } - + case EOpMethodSampleGrad: // ... { TIntermTyped* argTex = argAggregate->getSequence()[0]->getAsTyped(); @@ -938,6 +3861,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType TIntermTyped* argDDX = argAggregate->getSequence()[3]->getAsTyped(); TIntermTyped* argDDY = argAggregate->getSequence()[4]->getAsTyped(); TIntermTyped* argOffset = nullptr; + const TSampler& sampler = argTex->getType().getSampler(); TOperator textureOp = EOpTextureGrad; @@ -954,6 +3878,208 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType txsample->getSequence().push_back(argDDX); txsample->getSequence().push_back(argDDY); + if (argOffset != nullptr) + txsample->getSequence().push_back(argOffset); + + node = convertReturn(txsample, sampler); + + break; + } + + case EOpMethodGetDimensions: + { + // AST returns a vector of results, which we break apart component-wise into + // separate values to assign to the HLSL method's outputs, ala: + // tx . GetDimensions(width, height); + // float2 sizeQueryTemp = EOpTextureQuerySize + // width = sizeQueryTemp.X; + // height = sizeQueryTemp.Y; + + TIntermTyped* argTex = argAggregate->getSequence()[0]->getAsTyped(); + const TType& texType = argTex->getType(); + + assert(texType.getBasicType() == EbtSampler); + + const TSampler& sampler = texType.getSampler(); + const TSamplerDim dim = sampler.dim; + const bool isImage = sampler.isImage(); + const bool isMs = sampler.isMultiSample(); + const int numArgs = (int)argAggregate->getSequence().size(); + + int numDims = 0; + + switch (dim) { + case Esd1D: numDims = 1; break; // W + case Esd2D: numDims = 2; break; // W, H + case Esd3D: numDims = 3; break; // W, H, D + case EsdCube: numDims = 2; break; // W, H (cube) + case EsdBuffer: numDims = 1; break; // W (buffers) + case EsdRect: numDims = 2; break; // W, H (rect) + default: + assert(0 && "unhandled texture dimension"); + } + + // Arrayed adds another dimension for the number of array elements + if (sampler.isArrayed()) + ++numDims; + + // Establish whether the method itself is querying mip levels. This can be false even + // if the underlying query requires a MIP level, due to the available HLSL method overloads. + const bool mipQuery = (numArgs > (numDims + 1 + (isMs ? 1 : 0))); + + // Establish whether we must use the LOD form of query (even if the method did not supply a mip level to query). + // True if: + // 1. 1D/2D/3D/Cube AND multisample==0 AND NOT image (those can be sent to the non-LOD query) + // or, + // 2. There is a LOD (because the non-LOD query cannot be used in that case, per spec) + const bool mipRequired = + ((dim == Esd1D || dim == Esd2D || dim == Esd3D || dim == EsdCube) && !isMs && !isImage) || // 1... + mipQuery; // 2... + + // AST assumes integer return. Will be converted to float if required. + TIntermAggregate* sizeQuery = new TIntermAggregate(isImage ? EOpImageQuerySize : EOpTextureQuerySize); + sizeQuery->getSequence().push_back(argTex); + + // If we're building an LOD query, add the LOD. + if (mipRequired) { + // If the base HLSL query had no MIP level given, use level 0. + TIntermTyped* queryLod = mipQuery ? argAggregate->getSequence()[1]->getAsTyped() : + intermediate.addConstantUnion(0, loc, true); + sizeQuery->getSequence().push_back(queryLod); + } + + sizeQuery->setType(TType(EbtUint, EvqTemporary, numDims)); + sizeQuery->setLoc(loc); + + // Return value from size query + TVariable* tempArg = makeInternalVariable("sizeQueryTemp", sizeQuery->getType()); + tempArg->getWritableType().getQualifier().makeTemporary(); + TIntermTyped* sizeQueryAssign = intermediate.addAssign(EOpAssign, + intermediate.addSymbol(*tempArg, loc), + sizeQuery, loc); + + // Compound statement for assigning outputs + TIntermAggregate* compoundStatement = intermediate.makeAggregate(sizeQueryAssign, loc); + // Index of first output parameter + const int outParamBase = mipQuery ? 2 : 1; + + for (int compNum = 0; compNum < numDims; ++compNum) { + TIntermTyped* indexedOut = nullptr; + TIntermSymbol* sizeQueryReturn = intermediate.addSymbol(*tempArg, loc); + + if (numDims > 1) { + TIntermTyped* component = intermediate.addConstantUnion(compNum, loc, true); + indexedOut = intermediate.addIndex(EOpIndexDirect, sizeQueryReturn, component, loc); + indexedOut->setType(TType(EbtUint, EvqTemporary, 1)); + indexedOut->setLoc(loc); + } else { + indexedOut = sizeQueryReturn; + } + + TIntermTyped* outParam = argAggregate->getSequence()[outParamBase + compNum]->getAsTyped(); + TIntermTyped* compAssign = intermediate.addAssign(EOpAssign, outParam, indexedOut, loc); + + compoundStatement = intermediate.growAggregate(compoundStatement, compAssign); + } + + // handle mip level parameter + if (mipQuery) { + TIntermTyped* outParam = argAggregate->getSequence()[outParamBase + numDims]->getAsTyped(); + + TIntermAggregate* levelsQuery = new TIntermAggregate(EOpTextureQueryLevels); + levelsQuery->getSequence().push_back(argTex); + levelsQuery->setType(TType(EbtUint, EvqTemporary, 1)); + levelsQuery->setLoc(loc); + + TIntermTyped* compAssign = intermediate.addAssign(EOpAssign, outParam, levelsQuery, loc); + compoundStatement = intermediate.growAggregate(compoundStatement, compAssign); + } + + // 2DMS formats query # samples, which needs a different query op + if (sampler.isMultiSample()) { + TIntermTyped* outParam = argAggregate->getSequence()[outParamBase + numDims]->getAsTyped(); + + TIntermAggregate* samplesQuery = new TIntermAggregate(EOpImageQuerySamples); + samplesQuery->getSequence().push_back(argTex); + samplesQuery->setType(TType(EbtUint, EvqTemporary, 1)); + samplesQuery->setLoc(loc); + + TIntermTyped* compAssign = intermediate.addAssign(EOpAssign, outParam, samplesQuery, loc); + compoundStatement = intermediate.growAggregate(compoundStatement, compAssign); + } + + compoundStatement->setOperator(EOpSequence); + compoundStatement->setLoc(loc); + compoundStatement->setType(TType(EbtVoid)); + + node = compoundStatement; + + break; + } + + case EOpMethodSampleCmp: // fall through... + case EOpMethodSampleCmpLevelZero: + { + TIntermTyped* argTex = argAggregate->getSequence()[0]->getAsTyped(); + TIntermTyped* argSamp = argAggregate->getSequence()[1]->getAsTyped(); + TIntermTyped* argCoord = argAggregate->getSequence()[2]->getAsTyped(); + TIntermTyped* argCmpVal = argAggregate->getSequence()[3]->getAsTyped(); + TIntermTyped* argOffset = nullptr; + + // Sampler argument should be a sampler. + if (argSamp->getType().getBasicType() != EbtSampler) { + error(loc, "expected: sampler type", "", ""); + return; + } + + // Sampler should be a SamplerComparisonState + if (! argSamp->getType().getSampler().isShadow()) { + error(loc, "expected: SamplerComparisonState", "", ""); + return; + } + + // optional offset value + if (argAggregate->getSequence().size() > 4) + argOffset = argAggregate->getSequence()[4]->getAsTyped(); + + const int coordDimWithCmpVal = argCoord->getType().getVectorSize() + 1; // +1 for cmp + + // AST wants comparison value as one of the texture coordinates + TOperator constructOp = EOpNull; + switch (coordDimWithCmpVal) { + // 1D can't happen: there's always at least 1 coordinate dimension + 1 cmp val + case 2: constructOp = EOpConstructVec2; break; + case 3: constructOp = EOpConstructVec3; break; + case 4: constructOp = EOpConstructVec4; break; + case 5: constructOp = EOpConstructVec4; break; // cubeArrayShadow, cmp value is separate arg. + default: assert(0); break; + } + + TIntermAggregate* coordWithCmp = new TIntermAggregate(constructOp); + coordWithCmp->getSequence().push_back(argCoord); + if (coordDimWithCmpVal != 5) // cube array shadow is special. + coordWithCmp->getSequence().push_back(argCmpVal); + coordWithCmp->setLoc(loc); + coordWithCmp->setType(TType(argCoord->getBasicType(), EvqTemporary, std::min(coordDimWithCmpVal, 4))); + + TOperator textureOp = (op == EOpMethodSampleCmpLevelZero ? EOpTextureLod : EOpTexture); + if (argOffset != nullptr) + textureOp = (op == EOpMethodSampleCmpLevelZero ? EOpTextureLodOffset : EOpTextureOffset); + + // Create combined sampler & texture op + TIntermAggregate* txcombine = handleSamplerTextureCombine(loc, argTex, argSamp); + TIntermAggregate* txsample = new TIntermAggregate(textureOp); + txsample->getSequence().push_back(txcombine); + txsample->getSequence().push_back(coordWithCmp); + + if (coordDimWithCmpVal == 5) // cube array shadow is special: cmp val follows coord. + txsample->getSequence().push_back(argCmpVal); + + // the LevelZero form uses 0 as an explicit LOD + if (op == EOpMethodSampleCmpLevelZero) + txsample->getSequence().push_back(intermediate.addConstantUnion(0.0, EbtFloat, loc, true)); + + // Add offset if present if (argOffset != nullptr) txsample->getSequence().push_back(argOffset); @@ -964,6 +4090,454 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType break; } + case EOpMethodLoad: + { + TIntermTyped* argTex = argAggregate->getSequence()[0]->getAsTyped(); + TIntermTyped* argCoord = argAggregate->getSequence()[1]->getAsTyped(); + TIntermTyped* argOffset = nullptr; + TIntermTyped* lodComponent = nullptr; + TIntermTyped* coordSwizzle = nullptr; + + const TSampler& sampler = argTex->getType().getSampler(); + const bool isMS = sampler.isMultiSample(); + const bool isBuffer = sampler.dim == EsdBuffer; + const bool isImage = sampler.isImage(); + const TBasicType coordBaseType = argCoord->getType().getBasicType(); + + // Last component of coordinate is the mip level, for non-MS. we separate them here: + if (isMS || isBuffer || isImage) { + // MS, Buffer, and Image have no LOD + coordSwizzle = argCoord; + } else { + // Extract coordinate + int swizzleSize = argCoord->getType().getVectorSize() - (isMS ? 0 : 1); + TSwizzleSelectors coordFields; + for (int i = 0; i < swizzleSize; ++i) + coordFields.push_back(i); + TIntermTyped* coordIdx = intermediate.addSwizzle(coordFields, loc); + coordSwizzle = intermediate.addIndex(EOpVectorSwizzle, argCoord, coordIdx, loc); + coordSwizzle->setType(TType(coordBaseType, EvqTemporary, coordFields.size())); + + // Extract LOD + TIntermTyped* lodIdx = intermediate.addConstantUnion(coordFields.size(), loc, true); + lodComponent = intermediate.addIndex(EOpIndexDirect, argCoord, lodIdx, loc); + lodComponent->setType(TType(coordBaseType, EvqTemporary, 1)); + } + + const int numArgs = (int)argAggregate->getSequence().size(); + const bool hasOffset = ((!isMS && numArgs == 3) || (isMS && numArgs == 4)); + + // Create texel fetch + const TOperator fetchOp = (isImage ? EOpImageLoad : + hasOffset ? EOpTextureFetchOffset : + EOpTextureFetch); + TIntermAggregate* txfetch = new TIntermAggregate(fetchOp); + + // Build up the fetch + txfetch->getSequence().push_back(argTex); + txfetch->getSequence().push_back(coordSwizzle); + + if (isMS) { + // add 2DMS sample index + TIntermTyped* argSampleIdx = argAggregate->getSequence()[2]->getAsTyped(); + txfetch->getSequence().push_back(argSampleIdx); + } else if (isBuffer) { + // Nothing else to do for buffers. + } else if (isImage) { + // Nothing else to do for images. + } else { + // 2DMS and buffer have no LOD, but everything else does. + txfetch->getSequence().push_back(lodComponent); + } + + // Obtain offset arg, if there is one. + if (hasOffset) { + const int offsetPos = (isMS ? 3 : 2); + argOffset = argAggregate->getSequence()[offsetPos]->getAsTyped(); + txfetch->getSequence().push_back(argOffset); + } + + node = convertReturn(txfetch, sampler); + + break; + } + + case EOpMethodSampleLevel: + { + TIntermTyped* argTex = argAggregate->getSequence()[0]->getAsTyped(); + TIntermTyped* argSamp = argAggregate->getSequence()[1]->getAsTyped(); + TIntermTyped* argCoord = argAggregate->getSequence()[2]->getAsTyped(); + TIntermTyped* argLod = argAggregate->getSequence()[3]->getAsTyped(); + TIntermTyped* argOffset = nullptr; + const TSampler& sampler = argTex->getType().getSampler(); + + const int numArgs = (int)argAggregate->getSequence().size(); + + if (numArgs == 5) // offset, if present + argOffset = argAggregate->getSequence()[4]->getAsTyped(); + + const TOperator textureOp = (argOffset == nullptr ? EOpTextureLod : EOpTextureLodOffset); + TIntermAggregate* txsample = new TIntermAggregate(textureOp); + + TIntermAggregate* txcombine = handleSamplerTextureCombine(loc, argTex, argSamp); + + txsample->getSequence().push_back(txcombine); + txsample->getSequence().push_back(argCoord); + txsample->getSequence().push_back(argLod); + + if (argOffset != nullptr) + txsample->getSequence().push_back(argOffset); + + node = convertReturn(txsample, sampler); + + break; + } + + case EOpMethodGather: + { + TIntermTyped* argTex = argAggregate->getSequence()[0]->getAsTyped(); + TIntermTyped* argSamp = argAggregate->getSequence()[1]->getAsTyped(); + TIntermTyped* argCoord = argAggregate->getSequence()[2]->getAsTyped(); + TIntermTyped* argOffset = nullptr; + + // Offset is optional + if (argAggregate->getSequence().size() > 3) + argOffset = argAggregate->getSequence()[3]->getAsTyped(); + + const TOperator textureOp = (argOffset == nullptr ? EOpTextureGather : EOpTextureGatherOffset); + TIntermAggregate* txgather = new TIntermAggregate(textureOp); + + TIntermAggregate* txcombine = handleSamplerTextureCombine(loc, argTex, argSamp); + + txgather->getSequence().push_back(txcombine); + txgather->getSequence().push_back(argCoord); + // Offset if not given is implicitly channel 0 (red) + + if (argOffset != nullptr) + txgather->getSequence().push_back(argOffset); + + txgather->setType(node->getType()); + txgather->setLoc(loc); + node = txgather; + + break; + } + + case EOpMethodGatherRed: // fall through... + case EOpMethodGatherGreen: // ... + case EOpMethodGatherBlue: // ... + case EOpMethodGatherAlpha: // ... + case EOpMethodGatherCmpRed: // ... + case EOpMethodGatherCmpGreen: // ... + case EOpMethodGatherCmpBlue: // ... + case EOpMethodGatherCmpAlpha: // ... + { + int channel = 0; // the channel we are gathering + int cmpValues = 0; // 1 if there is a compare value (handier than a bool below) + + switch (op) { + case EOpMethodGatherCmpRed: cmpValues = 1; // fall through + case EOpMethodGatherRed: channel = 0; break; + case EOpMethodGatherCmpGreen: cmpValues = 1; // fall through + case EOpMethodGatherGreen: channel = 1; break; + case EOpMethodGatherCmpBlue: cmpValues = 1; // fall through + case EOpMethodGatherBlue: channel = 2; break; + case EOpMethodGatherCmpAlpha: cmpValues = 1; // fall through + case EOpMethodGatherAlpha: channel = 3; break; + default: assert(0); break; + } + + // For now, we have nothing to map the component-wise comparison forms + // to, because neither GLSL nor SPIR-V has such an opcode. Issue an + // unimplemented error instead. Most of the machinery is here if that + // should ever become available. However, red can be passed through + // to OpImageDrefGather. G/B/A cannot, because that opcode does not + // accept a component. + if (cmpValues != 0 && op != EOpMethodGatherCmpRed) { + error(loc, "unimplemented: component-level gather compare", "", ""); + return; + } + + int arg = 0; + + TIntermTyped* argTex = argAggregate->getSequence()[arg++]->getAsTyped(); + TIntermTyped* argSamp = argAggregate->getSequence()[arg++]->getAsTyped(); + TIntermTyped* argCoord = argAggregate->getSequence()[arg++]->getAsTyped(); + TIntermTyped* argOffset = nullptr; + TIntermTyped* argOffsets[4] = { nullptr, nullptr, nullptr, nullptr }; + // TIntermTyped* argStatus = nullptr; // TODO: residency + TIntermTyped* argCmp = nullptr; + + const TSamplerDim dim = argTex->getType().getSampler().dim; + + const int argSize = (int)argAggregate->getSequence().size(); + bool hasStatus = (argSize == (5+cmpValues) || argSize == (8+cmpValues)); + bool hasOffset1 = false; + bool hasOffset4 = false; + + // Sampler argument should be a sampler. + if (argSamp->getType().getBasicType() != EbtSampler) { + error(loc, "expected: sampler type", "", ""); + return; + } + + // Cmp forms require SamplerComparisonState + if (cmpValues > 0 && ! argSamp->getType().getSampler().isShadow()) { + error(loc, "expected: SamplerComparisonState", "", ""); + return; + } + + // Only 2D forms can have offsets. Discover if we have 0, 1 or 4 offsets. + if (dim == Esd2D) { + hasOffset1 = (argSize == (4+cmpValues) || argSize == (5+cmpValues)); + hasOffset4 = (argSize == (7+cmpValues) || argSize == (8+cmpValues)); + } + + assert(!(hasOffset1 && hasOffset4)); + + TOperator textureOp = EOpTextureGather; + + // Compare forms have compare value + if (cmpValues != 0) + argCmp = argOffset = argAggregate->getSequence()[arg++]->getAsTyped(); + + // Some forms have single offset + if (hasOffset1) { + textureOp = EOpTextureGatherOffset; // single offset form + argOffset = argAggregate->getSequence()[arg++]->getAsTyped(); + } + + // Some forms have 4 gather offsets + if (hasOffset4) { + textureOp = EOpTextureGatherOffsets; // note plural, for 4 offset form + for (int offsetNum = 0; offsetNum < 4; ++offsetNum) + argOffsets[offsetNum] = argAggregate->getSequence()[arg++]->getAsTyped(); + } + + // Residency status + if (hasStatus) { + // argStatus = argAggregate->getSequence()[arg++]->getAsTyped(); + error(loc, "unimplemented: residency status", "", ""); + return; + } + + TIntermAggregate* txgather = new TIntermAggregate(textureOp); + TIntermAggregate* txcombine = handleSamplerTextureCombine(loc, argTex, argSamp); + + TIntermTyped* argChannel = intermediate.addConstantUnion(channel, loc, true); + + txgather->getSequence().push_back(txcombine); + txgather->getSequence().push_back(argCoord); + + // AST wants an array of 4 offsets, where HLSL has separate args. Here + // we construct an array from the separate args. + if (hasOffset4) { + TType arrayType(EbtInt, EvqTemporary, 2); + TArraySizes* arraySizes = new TArraySizes; + arraySizes->addInnerSize(4); + arrayType.transferArraySizes(arraySizes); + + TIntermAggregate* initList = new TIntermAggregate(EOpNull); + + for (int offsetNum = 0; offsetNum < 4; ++offsetNum) + initList->getSequence().push_back(argOffsets[offsetNum]); + + argOffset = addConstructor(loc, initList, arrayType); + } + + // Add comparison value if we have one + if (argCmp != nullptr) + txgather->getSequence().push_back(argCmp); + + // Add offset (either 1, or an array of 4) if we have one + if (argOffset != nullptr) + txgather->getSequence().push_back(argOffset); + + // Add channel value if the sampler is not shadow + if (! argSamp->getType().getSampler().isShadow()) + txgather->getSequence().push_back(argChannel); + + txgather->setType(node->getType()); + txgather->setLoc(loc); + node = txgather; + + break; + } + + case EOpMethodCalculateLevelOfDetail: + case EOpMethodCalculateLevelOfDetailUnclamped: + { + TIntermTyped* argTex = argAggregate->getSequence()[0]->getAsTyped(); + TIntermTyped* argSamp = argAggregate->getSequence()[1]->getAsTyped(); + TIntermTyped* argCoord = argAggregate->getSequence()[2]->getAsTyped(); + + TIntermAggregate* txquerylod = new TIntermAggregate(EOpTextureQueryLod); + + TIntermAggregate* txcombine = handleSamplerTextureCombine(loc, argTex, argSamp); + txquerylod->getSequence().push_back(txcombine); + txquerylod->getSequence().push_back(argCoord); + + TIntermTyped* lodComponent = intermediate.addConstantUnion(0, loc, true); + TIntermTyped* lodComponentIdx = intermediate.addIndex(EOpIndexDirect, txquerylod, lodComponent, loc); + lodComponentIdx->setType(TType(EbtFloat, EvqTemporary, 1)); + + node = lodComponentIdx; + + // We cannot currently obtain the unclamped LOD + if (op == EOpMethodCalculateLevelOfDetailUnclamped) + error(loc, "unimplemented: CalculateLevelOfDetailUnclamped", "", ""); + + break; + } + + case EOpMethodGetSamplePosition: + { + // TODO: this entire decomposition exists because there is not yet a way to query + // the sample position directly through SPIR-V. Instead, we return fixed sample + // positions for common cases. *** If the sample positions are set differently, + // this will be wrong. *** + + TIntermTyped* argTex = argAggregate->getSequence()[0]->getAsTyped(); + TIntermTyped* argSampIdx = argAggregate->getSequence()[1]->getAsTyped(); + + TIntermAggregate* samplesQuery = new TIntermAggregate(EOpImageQuerySamples); + samplesQuery->getSequence().push_back(argTex); + samplesQuery->setType(TType(EbtUint, EvqTemporary, 1)); + samplesQuery->setLoc(loc); + + TIntermAggregate* compoundStatement = nullptr; + + TVariable* outSampleCount = makeInternalVariable("@sampleCount", TType(EbtUint)); + outSampleCount->getWritableType().getQualifier().makeTemporary(); + TIntermTyped* compAssign = intermediate.addAssign(EOpAssign, intermediate.addSymbol(*outSampleCount, loc), + samplesQuery, loc); + compoundStatement = intermediate.growAggregate(compoundStatement, compAssign); + + TIntermTyped* idxtest[4]; + + // Create tests against 2, 4, 8, and 16 sample values + int count = 0; + for (int val = 2; val <= 16; val *= 2) + idxtest[count++] = + intermediate.addBinaryNode(EOpEqual, + intermediate.addSymbol(*outSampleCount, loc), + intermediate.addConstantUnion(val, loc), + loc, TType(EbtBool)); + + const TOperator idxOp = (argSampIdx->getQualifier().storage == EvqConst) ? EOpIndexDirect : EOpIndexIndirect; + + // Create index ops into position arrays given sample index. + // TODO: should it be clamped? + TIntermTyped* index[4]; + count = 0; + for (int val = 2; val <= 16; val *= 2) { + index[count] = intermediate.addIndex(idxOp, getSamplePosArray(val), argSampIdx, loc); + index[count++]->setType(TType(EbtFloat, EvqTemporary, 2)); + } + + // Create expression as: + // (sampleCount == 2) ? pos2[idx] : + // (sampleCount == 4) ? pos4[idx] : + // (sampleCount == 8) ? pos8[idx] : + // (sampleCount == 16) ? pos16[idx] : float2(0,0); + TIntermTyped* test = + intermediate.addSelection(idxtest[0], index[0], + intermediate.addSelection(idxtest[1], index[1], + intermediate.addSelection(idxtest[2], index[2], + intermediate.addSelection(idxtest[3], index[3], + getSamplePosArray(1), loc), loc), loc), loc); + + compoundStatement = intermediate.growAggregate(compoundStatement, test); + compoundStatement->setOperator(EOpSequence); + compoundStatement->setLoc(loc); + compoundStatement->setType(TType(EbtFloat, EvqTemporary, 2)); + + node = compoundStatement; + + break; + } + + case EOpSubpassLoad: + { + const TIntermTyped* argSubpass = + argAggregate ? argAggregate->getSequence()[0]->getAsTyped() : + arguments->getAsTyped(); + + const TSampler& sampler = argSubpass->getType().getSampler(); + + // subpass load: the multisample form is overloaded. Here, we convert that to + // the EOpSubpassLoadMS opcode. + if (argAggregate != nullptr && argAggregate->getSequence().size() > 1) + node->getAsOperator()->setOp(EOpSubpassLoadMS); + + node = convertReturn(node, sampler); + + break; + } + + + default: + break; // most pass through unchanged + } +} + +// +// Decompose geometry shader methods +// +void HlslParseContext::decomposeGeometryMethods(const TSourceLoc& loc, TIntermTyped*& node, TIntermNode* arguments) +{ + if (node == nullptr || !node->getAsOperator()) + return; + + const TOperator op = node->getAsOperator()->getOp(); + const TIntermAggregate* argAggregate = arguments ? arguments->getAsAggregate() : nullptr; + + switch (op) { + case EOpMethodAppend: + if (argAggregate) { + // Don't emit these for non-GS stage, since we won't have the gsStreamOutput symbol. + if (language != EShLangGeometry) { + node = nullptr; + return; + } + + TIntermAggregate* sequence = nullptr; + TIntermAggregate* emit = new TIntermAggregate(EOpEmitVertex); + + emit->setLoc(loc); + emit->setType(TType(EbtVoid)); + + TIntermTyped* data = argAggregate->getSequence()[1]->getAsTyped(); + + // This will be patched in finalization during finalizeAppendMethods() + sequence = intermediate.growAggregate(sequence, data, loc); + sequence = intermediate.growAggregate(sequence, emit); + + sequence->setOperator(EOpSequence); + sequence->setLoc(loc); + sequence->setType(TType(EbtVoid)); + + gsAppends.push_back({sequence, loc}); + + node = sequence; + } + break; + + case EOpMethodRestartStrip: + { + // Don't emit these for non-GS stage, since we won't have the gsStreamOutput symbol. + if (language != EShLangGeometry) { + node = nullptr; + return; + } + + TIntermAggregate* cut = new TIntermAggregate(EOpEndPrimitive); + cut->setLoc(loc); + cut->setType(TType(EbtVoid)); + node = cut; + } + break; + default: break; // most pass through unchanged } @@ -974,13 +4548,50 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType // void HlslParseContext::decomposeIntrinsic(const TSourceLoc& loc, TIntermTyped*& node, TIntermNode* arguments) { + // Helper to find image data for image atomics: + // OpImageLoad(image[idx]) + // We take the image load apart and add its params to the atomic op aggregate node + const auto imageAtomicParams = [this, &loc, &node](TIntermAggregate* atomic, TIntermTyped* load) { + TIntermAggregate* loadOp = load->getAsAggregate(); + if (loadOp == nullptr) { + error(loc, "unknown image type in atomic operation", "", ""); + node = nullptr; + return; + } + + atomic->getSequence().push_back(loadOp->getSequence()[0]); + atomic->getSequence().push_back(loadOp->getSequence()[1]); + }; + + // Return true if this is an imageLoad, which we will change to an image atomic. + const auto isImageParam = [](TIntermTyped* image) -> bool { + TIntermAggregate* imageAggregate = image->getAsAggregate(); + return imageAggregate != nullptr && imageAggregate->getOp() == EOpImageLoad; + }; + + const auto lookupBuiltinVariable = [&](const char* name, TBuiltInVariable builtin, TType& type) -> TIntermTyped* { + TSymbol* symbol = symbolTable.find(name); + if (nullptr == symbol) { + type.getQualifier().builtIn = builtin; + + TVariable* variable = new TVariable(new TString(name), type); + + symbolTable.insert(*variable); + + symbol = symbolTable.find(name); + assert(symbol && "Inserted symbol could not be found!"); + } + + return intermediate.addSymbol(*(symbol->getAsVariable()), loc); + }; + // HLSL intrinsics can be pass through to native AST opcodes, or decomposed here to existing AST // opcodes for compatibility with existing software stacks. static const bool decomposeHlslIntrinsics = true; if (!decomposeHlslIntrinsics || !node || !node->getAsOperator()) return; - + const TIntermAggregate* argAggregate = arguments ? arguments->getAsAggregate() : nullptr; TIntermUnary* fnUnary = node->getAsUnaryNode(); const TOperator op = node->getAsOperator()->getOp(); @@ -989,8 +4600,10 @@ void HlslParseContext::decomposeIntrinsic(const TSourceLoc& loc, TIntermTyped*& case EOpGenMul: { // mul(a,b) -> MatrixTimesMatrix, MatrixTimesVector, MatrixTimesScalar, VectorTimesScalar, Dot, Mul - TIntermTyped* arg0 = argAggregate->getSequence()[0]->getAsTyped(); - TIntermTyped* arg1 = argAggregate->getSequence()[1]->getAsTyped(); + // Since we are treating HLSL rows like GLSL columns (the first matrix indirection), + // we must reverse the operand order here. Hence, arg0 gets sequence[1], etc. + TIntermTyped* arg0 = argAggregate->getSequence()[1]->getAsTyped(); + TIntermTyped* arg1 = argAggregate->getSequence()[0]->getAsTyped(); if (arg0->isVector() && arg1->isVector()) { // vec * vec node->getAsAggregate()->setOperator(EOpDot); @@ -1012,6 +4625,28 @@ void HlslParseContext::decomposeIntrinsic(const TSourceLoc& loc, TIntermTyped*& break; } + case EOpAny: // fall through + case EOpAll: + { + TIntermTyped* typedArg = arguments->getAsTyped(); + + // HLSL allows float/etc types here, and the SPIR-V opcode requires a bool. + // We'll convert here. Note that for efficiency, we could add a smarter + // decomposition for some type cases, e.g, maybe by decomposing a dot product. + if (typedArg->getType().getBasicType() != EbtBool) { + const TType boolType(EbtBool, EvqTemporary, + typedArg->getVectorSize(), + typedArg->getMatrixCols(), + typedArg->getMatrixRows(), + typedArg->isVector()); + + typedArg = intermediate.addConversion(EOpConstructBool, boolType, typedArg); + node->getAsUnaryNode()->setOperand(typedArg); + } + + break; + } + case EOpSaturate: { // saturate(a) -> clamp(a,0,1) @@ -1075,28 +4710,35 @@ void HlslParseContext::decomposeIntrinsic(const TSourceLoc& loc, TIntermTyped*& arg0->getType().isVector())); // calculate # of components for comparison const - const int constComponentCount = + const int constComponentCount = std::max(arg0->getType().getVectorSize(), 1) * std::max(arg0->getType().getMatrixCols(), 1) * std::max(arg0->getType().getMatrixRows(), 1); TConstUnion zero; - zero.setDConst(0.0); + if (arg0->getType().isIntegerDomain()) + zero.setDConst(0); + else + zero.setDConst(0.0); TConstUnionArray zeros(constComponentCount, zero); less->getSequence().push_back(intermediate.addConstantUnion(zeros, arg0->getType(), loc, true)); compareNode = intermediate.addBuiltInFunctionCall(loc, EOpAny, true, less, TType(EbtBool)); } else { - TIntermTyped* zero = intermediate.addConstantUnion(0, type0, loc, true); + TIntermTyped* zero; + if (arg0->getType().isIntegerDomain()) + zero = intermediate.addConstantUnion(0, loc, true); + else + zero = intermediate.addConstantUnion(0.0, type0, loc, true); compareNode = handleBinaryMath(loc, "clip", EOpLessThan, arg0, zero); } - + TIntermBranch* killNode = intermediate.addBranch(EOpKill, loc); node = new TIntermSelection(compareNode, killNode, nullptr); node->setLoc(loc); - + break; } @@ -1152,27 +4794,44 @@ void HlslParseContext::decomposeIntrinsic(const TSourceLoc& loc, TIntermTyped*& case EOpInterlockedXor: // ... case EOpInterlockedExchange: // always has output arg { - TIntermTyped* arg0 = argAggregate->getSequence()[0]->getAsTyped(); - TIntermTyped* arg1 = argAggregate->getSequence()[1]->getAsTyped(); + TIntermTyped* arg0 = argAggregate->getSequence()[0]->getAsTyped(); // dest + TIntermTyped* arg1 = argAggregate->getSequence()[1]->getAsTyped(); // value + TIntermTyped* arg2 = nullptr; - const bool isImage = arg0->getType().isImage(); + if (argAggregate->getSequence().size() > 2) + arg2 = argAggregate->getSequence()[2]->getAsTyped(); + + const bool isImage = isImageParam(arg0); const TOperator atomicOp = mapAtomicOp(loc, op, isImage); + TIntermAggregate* atomic = new TIntermAggregate(atomicOp); + atomic->setType(arg0->getType()); + atomic->getWritableType().getQualifier().makeTemporary(); + atomic->setLoc(loc); - if (argAggregate->getSequence().size() > 2) { - // optional output param is present. return value goes to arg2. - TIntermTyped* arg2 = argAggregate->getSequence()[2]->getAsTyped(); - - TIntermAggregate* atomic = new TIntermAggregate(atomicOp); - atomic->getSequence().push_back(arg0); + if (isImage) { + // orig_value = imageAtomicOp(image, loc, data) + imageAtomicParams(atomic, arg0); atomic->getSequence().push_back(arg1); - atomic->setLoc(loc); - atomic->setType(arg0->getType()); - atomic->getWritableType().getQualifier().makeTemporary(); - node = intermediate.addAssign(EOpAssign, arg2, atomic, loc); + if (argAggregate->getSequence().size() > 2) { + node = intermediate.addAssign(EOpAssign, arg2, atomic, loc); + } else { + node = atomic; // no assignment needed, as there was no out var. + } } else { - // Set the matching operator. Since output is absent, this is all we need to do. - node->getAsAggregate()->setOperator(atomicOp); + // Normal memory variable: + // arg0 = mem, arg1 = data, arg2(optional,out) = orig_value + if (argAggregate->getSequence().size() > 2) { + // optional output param is present. return value goes to arg2. + atomic->getSequence().push_back(arg0); + atomic->getSequence().push_back(arg1); + + node = intermediate.addAssign(EOpAssign, arg2, atomic, loc); + } else { + // Set the matching operator. Since output is absent, this is all we need to do. + node->getAsAggregate()->setOperator(atomicOp); + node->setType(atomic->getType()); + } } break; @@ -1185,17 +4844,22 @@ void HlslParseContext::decomposeIntrinsic(const TSourceLoc& loc, TIntermTyped*& TIntermTyped* arg2 = argAggregate->getSequence()[2]->getAsTyped(); // value TIntermTyped* arg3 = argAggregate->getSequence()[3]->getAsTyped(); // orig - const bool isImage = arg0->getType().isImage(); + const bool isImage = isImageParam(arg0); TIntermAggregate* atomic = new TIntermAggregate(mapAtomicOp(loc, op, isImage)); - atomic->getSequence().push_back(arg0); - atomic->getSequence().push_back(arg1); - atomic->getSequence().push_back(arg2); atomic->setLoc(loc); atomic->setType(arg2->getType()); atomic->getWritableType().getQualifier().makeTemporary(); + if (isImage) { + imageAtomicParams(atomic, arg0); + } else { + atomic->getSequence().push_back(arg0); + } + + atomic->getSequence().push_back(arg1); + atomic->getSequence().push_back(arg2); node = intermediate.addAssign(EOpAssign, arg3, atomic, loc); - + break; } @@ -1221,7 +4885,7 @@ void HlslParseContext::decomposeIntrinsic(const TSourceLoc& loc, TIntermTyped*& intermediate.addConversion(EOpConstructFloat, TType(EbtFloat, EvqTemporary, 2), iU), recip16); - + TIntermAggregate* interp = new TIntermAggregate(EOpInterpolateAtOffset); interp->getSequence().push_back(arg0); interp->getSequence().push_back(floatOffset); @@ -1265,7 +4929,7 @@ void HlslParseContext::decomposeIntrinsic(const TSourceLoc& loc, TIntermTyped*& TIntermTyped* n_dot_h_m = handleBinaryMath(loc, "mul", EOpMul, n_dot_h, m); // n_dot_h * m dst->getSequence().push_back(intermediate.addSelection(compare, zero, n_dot_h_m, loc)); - + // One: dst->getSequence().push_back(intermediate.addConstantUnion(1.0, EbtFloat, loc, true)); @@ -1300,15 +4964,240 @@ void HlslParseContext::decomposeIntrinsic(const TSourceLoc& loc, TIntermTyped*& convert->setLoc(loc); convert->setType(TType(EbtDouble, EvqTemporary)); node = convert; + + break; + } + + case EOpF16tof32: + { + // input uvecN with low 16 bits of each component holding a float16. convert to float32. + TIntermTyped* argValue = node->getAsUnaryNode()->getOperand(); + TIntermTyped* zero = intermediate.addConstantUnion(0, loc, true); + const int vecSize = argValue->getType().getVectorSize(); + + TOperator constructOp = EOpNull; + switch (vecSize) { + case 1: constructOp = EOpNull; break; // direct use, no construct needed + case 2: constructOp = EOpConstructVec2; break; + case 3: constructOp = EOpConstructVec3; break; + case 4: constructOp = EOpConstructVec4; break; + default: assert(0); break; + } + + // For scalar case, we don't need to construct another type. + TIntermAggregate* result = (vecSize > 1) ? new TIntermAggregate(constructOp) : nullptr; + + if (result) { + result->setType(TType(EbtFloat, EvqTemporary, vecSize)); + result->setLoc(loc); + } + + for (int idx = 0; idx < vecSize; ++idx) { + TIntermTyped* idxConst = intermediate.addConstantUnion(idx, loc, true); + TIntermTyped* component = argValue->getType().isVector() ? + intermediate.addIndex(EOpIndexDirect, argValue, idxConst, loc) : argValue; + + if (component != argValue) + component->setType(TType(argValue->getBasicType(), EvqTemporary)); + + TIntermTyped* unpackOp = new TIntermUnary(EOpUnpackHalf2x16); + unpackOp->setType(TType(EbtFloat, EvqTemporary, 2)); + unpackOp->getAsUnaryNode()->setOperand(component); + unpackOp->setLoc(loc); + + TIntermTyped* lowOrder = intermediate.addIndex(EOpIndexDirect, unpackOp, zero, loc); + + if (result != nullptr) { + result->getSequence().push_back(lowOrder); + node = result; + } else { + node = lowOrder; + } + } break; } - - case EOpF16tof32: + case EOpF32tof16: { - // Temporary until decomposition is available. - error(loc, "unimplemented intrinsic: handle natively", "f32tof16", ""); + // input floatN converted to 16 bit float in low order bits of each component of uintN + TIntermTyped* argValue = node->getAsUnaryNode()->getOperand(); + + TIntermTyped* zero = intermediate.addConstantUnion(0.0, EbtFloat, loc, true); + const int vecSize = argValue->getType().getVectorSize(); + + TOperator constructOp = EOpNull; + switch (vecSize) { + case 1: constructOp = EOpNull; break; // direct use, no construct needed + case 2: constructOp = EOpConstructUVec2; break; + case 3: constructOp = EOpConstructUVec3; break; + case 4: constructOp = EOpConstructUVec4; break; + default: assert(0); break; + } + + // For scalar case, we don't need to construct another type. + TIntermAggregate* result = (vecSize > 1) ? new TIntermAggregate(constructOp) : nullptr; + + if (result) { + result->setType(TType(EbtUint, EvqTemporary, vecSize)); + result->setLoc(loc); + } + + for (int idx = 0; idx < vecSize; ++idx) { + TIntermTyped* idxConst = intermediate.addConstantUnion(idx, loc, true); + TIntermTyped* component = argValue->getType().isVector() ? + intermediate.addIndex(EOpIndexDirect, argValue, idxConst, loc) : argValue; + + if (component != argValue) + component->setType(TType(argValue->getBasicType(), EvqTemporary)); + + TIntermAggregate* vec2ComponentAndZero = new TIntermAggregate(EOpConstructVec2); + vec2ComponentAndZero->getSequence().push_back(component); + vec2ComponentAndZero->getSequence().push_back(zero); + vec2ComponentAndZero->setType(TType(EbtFloat, EvqTemporary, 2)); + vec2ComponentAndZero->setLoc(loc); + + TIntermTyped* packOp = new TIntermUnary(EOpPackHalf2x16); + packOp->getAsUnaryNode()->setOperand(vec2ComponentAndZero); + packOp->setLoc(loc); + packOp->setType(TType(EbtUint, EvqTemporary)); + + if (result != nullptr) { + result->getSequence().push_back(packOp); + node = result; + } else { + node = packOp; + } + } + + break; + } + + case EOpD3DCOLORtoUBYTE4: + { + // ivec4 ( x.zyxw * 255.001953 ); + TIntermTyped* arg0 = node->getAsUnaryNode()->getOperand(); + TSwizzleSelectors selectors; + selectors.push_back(2); + selectors.push_back(1); + selectors.push_back(0); + selectors.push_back(3); + TIntermTyped* swizzleIdx = intermediate.addSwizzle(selectors, loc); + TIntermTyped* swizzled = intermediate.addIndex(EOpVectorSwizzle, arg0, swizzleIdx, loc); + swizzled->setType(arg0->getType()); + swizzled->getWritableType().getQualifier().makeTemporary(); + + TIntermTyped* conversion = intermediate.addConstantUnion(255.001953f, EbtFloat, loc, true); + TIntermTyped* rangeConverted = handleBinaryMath(loc, "mul", EOpMul, conversion, swizzled); + rangeConverted->setType(arg0->getType()); + rangeConverted->getWritableType().getQualifier().makeTemporary(); + + node = intermediate.addConversion(EOpConstructInt, TType(EbtInt, EvqTemporary, 4), rangeConverted); + node->setLoc(loc); + node->setType(TType(EbtInt, EvqTemporary, 4)); + break; + } + + case EOpIsFinite: + { + // Since OPIsFinite in SPIR-V is only supported with the Kernel capability, we translate + // it to !isnan && !isinf + + TIntermTyped* arg0 = node->getAsUnaryNode()->getOperand(); + + // We'll make a temporary in case the RHS is cmoplex + TVariable* tempArg = makeInternalVariable("@finitetmp", arg0->getType()); + tempArg->getWritableType().getQualifier().makeTemporary(); + + TIntermTyped* tmpArgAssign = intermediate.addAssign(EOpAssign, + intermediate.addSymbol(*tempArg, loc), + arg0, loc); + + TIntermAggregate* compoundStatement = intermediate.makeAggregate(tmpArgAssign, loc); + + const TType boolType(EbtBool, EvqTemporary, arg0->getVectorSize(), arg0->getMatrixCols(), + arg0->getMatrixRows()); + + TIntermTyped* isnan = handleUnaryMath(loc, "isnan", EOpIsNan, intermediate.addSymbol(*tempArg, loc)); + isnan->setType(boolType); + + TIntermTyped* notnan = handleUnaryMath(loc, "!", EOpLogicalNot, isnan); + notnan->setType(boolType); + + TIntermTyped* isinf = handleUnaryMath(loc, "isinf", EOpIsInf, intermediate.addSymbol(*tempArg, loc)); + isinf->setType(boolType); + + TIntermTyped* notinf = handleUnaryMath(loc, "!", EOpLogicalNot, isinf); + notinf->setType(boolType); + + TIntermTyped* andNode = handleBinaryMath(loc, "and", EOpLogicalAnd, notnan, notinf); + andNode->setType(boolType); + + compoundStatement = intermediate.growAggregate(compoundStatement, andNode); + compoundStatement->setOperator(EOpSequence); + compoundStatement->setLoc(loc); + compoundStatement->setType(boolType); + + node = compoundStatement; + + break; + } + case EOpWaveGetLaneCount: + { + // Mapped to gl_SubgroupSize builtin (We preprend @ to the symbol + // so that it inhabits the symbol table, but has a user-invalid name + // in-case some source HLSL defined the symbol also). + TType type(EbtUint, EvqVaryingIn); + node = lookupBuiltinVariable("@gl_SubgroupSize", EbvSubgroupSize2, type); + break; + } + case EOpWaveGetLaneIndex: + { + // Mapped to gl_SubgroupInvocationID builtin (We preprend @ to the + // symbol so that it inhabits the symbol table, but has a + // user-invalid name in-case some source HLSL defined the symbol + // also). + TType type(EbtUint, EvqVaryingIn); + node = lookupBuiltinVariable("@gl_SubgroupInvocationID", EbvSubgroupInvocation2, type); + break; + } + case EOpWaveActiveCountBits: + { + // Mapped to subgroupBallotBitCount(subgroupBallot()) builtin + + // uvec4 type. + TType uvec4Type(EbtUint, EvqTemporary, 4); + + // Get the uvec4 return from subgroupBallot(). + TIntermTyped* res = intermediate.addBuiltInFunctionCall(loc, + EOpSubgroupBallot, true, arguments, uvec4Type); + + // uint type. + TType uintType(EbtUint, EvqTemporary); + + node = intermediate.addBuiltInFunctionCall(loc, + EOpSubgroupBallotBitCount, true, res, uintType); + + break; + } + case EOpWavePrefixCountBits: + { + // Mapped to subgroupBallotInclusiveBitCount(subgroupBallot()) + // builtin + + // uvec4 type. + TType uvec4Type(EbtUint, EvqTemporary, 4); + + // Get the uvec4 return from subgroupBallot(). + TIntermTyped* res = intermediate.addBuiltInFunctionCall(loc, + EOpSubgroupBallot, true, arguments, uvec4Type); + + // uint type. + TType uintType(EbtUint, EvqTemporary); + + node = intermediate.addBuiltInFunctionCall(loc, + EOpSubgroupBallotInclusiveBitCount, true, res, uintType); + break; } @@ -1326,14 +5215,12 @@ void HlslParseContext::decomposeIntrinsic(const TSourceLoc& loc, TIntermTyped*& // - user function // - subroutine call (not implemented yet) // -TIntermTyped* HlslParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction* function, TIntermNode* arguments) +TIntermTyped* HlslParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction* function, TIntermTyped* arguments) { TIntermTyped* result = nullptr; TOperator op = function->getBuiltInOp(); - if (op == EOpArrayLength) - result = handleLengthMethod(loc, function, arguments); - else if (op != EOpNull) { + if (op != EOpNull) { // // Then this should be a constructor. // Don't go through the symbol table for constructors. @@ -1344,17 +5231,59 @@ TIntermTyped* HlslParseContext::handleFunctionCall(const TSourceLoc& loc, TFunct // // It's a constructor, of type 'type'. // - result = addConstructor(loc, arguments, type, op); - if (result == nullptr) + result = handleConstructor(loc, arguments, type); + if (result == nullptr) { error(loc, "cannot construct with these arguments", type.getCompleteString().c_str(), ""); + return nullptr; + } } } else { // // Find it in the symbol table. // - const TFunction* fnCandidate; - bool builtIn; - fnCandidate = findFunction(loc, *function, builtIn); + const TFunction* fnCandidate = nullptr; + bool builtIn = false; + int thisDepth = 0; + + // For mat mul, the situation is unusual: we have to compare vector sizes to mat row or col sizes, + // and clamp the opposite arg. Since that's complex, we farm it off to a separate method. + // It doesn't naturally fall out of processing an argument at a time in isolation. + if (function->getName() == "mul") + addGenMulArgumentConversion(loc, *function, arguments); + + TIntermAggregate* aggregate = arguments ? arguments->getAsAggregate() : nullptr; + + // TODO: this needs improvement: there's no way at present to look up a signature in + // the symbol table for an arbitrary type. This is a temporary hack until that ability exists. + // It will have false positives, since it doesn't check arg counts or types. + if (arguments) { + // Check if first argument is struct buffer type. It may be an aggregate or a symbol, so we + // look for either case. + + TIntermTyped* arg0 = nullptr; + + if (aggregate && aggregate->getSequence().size() > 0) + arg0 = aggregate->getSequence()[0]->getAsTyped(); + else if (arguments->getAsSymbolNode()) + arg0 = arguments->getAsSymbolNode(); + + if (arg0 != nullptr && isStructBufferType(arg0->getType())) { + static const int methodPrefixSize = sizeof(BUILTIN_PREFIX)-1; + + if (function->getName().length() > methodPrefixSize && + isStructBufferMethod(function->getName().substr(methodPrefixSize))) { + const TString mangle = function->getName() + "("; + TSymbol* symbol = symbolTable.find(mangle, &builtIn); + + if (symbol) + fnCandidate = symbol->getAsFunction(); + } + } + } + + if (fnCandidate == nullptr) + fnCandidate = findFunction(loc, *function, builtIn, thisDepth, arguments); + if (fnCandidate) { // This is a declared function that might map to // - a built-in operator, @@ -1363,28 +5292,39 @@ TIntermTyped* HlslParseContext::handleFunctionCall(const TSourceLoc& loc, TFunct // Error check for a function requiring specific extensions present. if (builtIn && fnCandidate->getNumExtensions()) - requireExtensions(loc, fnCandidate->getNumExtensions(), fnCandidate->getExtensions(), fnCandidate->getName().c_str()); + requireExtensions(loc, fnCandidate->getNumExtensions(), fnCandidate->getExtensions(), + fnCandidate->getName().c_str()); - if (arguments) { - // Make sure qualifications work for these arguments. - //TIntermAggregate* aggregate = arguments->getAsAggregate(); - //for (int i = 0; i < fnCandidate->getParamCount(); ++i) { - // // At this early point there is a slight ambiguity between whether an aggregate 'arguments' - // // is the single argument itself or its children are the arguments. Only one argument - // // means take 'arguments' itself as the one argument. - // TIntermNode* arg = fnCandidate->getParamCount() == 1 ? arguments : (aggregate ? aggregate->getSequence()[i] : arguments); - // TQualifier& formalQualifier = (*fnCandidate)[i].type->getQualifier(); - // TQualifier& argQualifier = arg->getAsTyped()->getQualifier(); - //} - - // Convert 'in' arguments - addInputArgumentConversions(*fnCandidate, arguments); // arguments may be modified if it's just a single argument node + // turn an implicit member-function resolution into an explicit call + TString callerName; + if (thisDepth == 0) + callerName = fnCandidate->getMangledName(); + else { + // get the explicit (full) name of the function + callerName = currentTypePrefix[currentTypePrefix.size() - thisDepth]; + callerName += fnCandidate->getMangledName(); + // insert the implicit calling argument + pushFrontArguments(intermediate.addSymbol(*getImplicitThis(thisDepth)), arguments); } + // Convert 'in' arguments, so that types match. + // However, skip those that need expansion, that is covered next. + if (arguments) + addInputArgumentConversions(*fnCandidate, arguments); + + // Expand arguments. Some arguments must physically expand to a different set + // than what the shader declared and passes. + if (arguments && !builtIn) + expandArguments(loc, *fnCandidate, arguments); + + // Expansion may have changed the form of arguments + aggregate = arguments ? arguments->getAsAggregate() : nullptr; + op = fnCandidate->getBuiltInOp(); if (builtIn && op != EOpNull) { // A function call mapped to a built-in operation. - result = intermediate.addBuiltInFunctionCall(loc, op, fnCandidate->getParamCount() == 1, arguments, fnCandidate->getType()); + result = intermediate.addBuiltInFunctionCall(loc, op, fnCandidate->getParamCount() == 1, arguments, + fnCandidate->getType()); if (result == nullptr) { error(arguments->getLoc(), " wrong operand type", "Internal Error", "built in unary operator function. Type: %s", @@ -1397,126 +5337,300 @@ TIntermTyped* HlslParseContext::handleFunctionCall(const TSourceLoc& loc, TFunct // It could still be a built-in function, but only if PureOperatorBuiltins == false. result = intermediate.setAggregateOperator(arguments, EOpFunctionCall, fnCandidate->getType(), loc); TIntermAggregate* call = result->getAsAggregate(); - call->setName(fnCandidate->getMangledName()); + call->setName(callerName); // this is how we know whether the given function is a built-in function or a user-defined function // if builtIn == false, it's a userDefined -> could be an overloaded built-in function also // if builtIn == true, it's definitely a built-in function with EOpNull if (! builtIn) { call->setUserDefined(); - intermediate.addToCallGraph(infoSink, currentCaller, fnCandidate->getMangledName()); + intermediate.addToCallGraph(infoSink, currentCaller, callerName); + } + } + + // for decompositions, since we want to operate on the function node, not the aggregate holding + // output conversions. + const TIntermTyped* fnNode = result; + + decomposeStructBufferMethods(loc, result, arguments); // HLSL->AST struct buffer method decompositions + decomposeIntrinsic(loc, result, arguments); // HLSL->AST intrinsic decompositions + decomposeSampleMethods(loc, result, arguments); // HLSL->AST sample method decompositions + decomposeGeometryMethods(loc, result, arguments); // HLSL->AST geometry method decompositions + + // Create the qualifier list, carried in the AST for the call. + // Because some arguments expand to multiple arguments, the qualifier list will + // be longer than the formal parameter list. + if (result == fnNode && result->getAsAggregate()) { + TQualifierList& qualifierList = result->getAsAggregate()->getQualifierList(); + for (int i = 0; i < fnCandidate->getParamCount(); ++i) { + TStorageQualifier qual = (*fnCandidate)[i].type->getQualifier().storage; + if (hasStructBuffCounter(*(*fnCandidate)[i].type)) { + // add buffer and counter buffer argument qualifier + qualifierList.push_back(qual); + qualifierList.push_back(qual); + } else if (shouldFlatten(*(*fnCandidate)[i].type, (*fnCandidate)[i].type->getQualifier().storage, + true)) { + // add structure member expansion + for (int memb = 0; memb < (int)(*fnCandidate)[i].type->getStruct()->size(); ++memb) + qualifierList.push_back(qual); + } else { + // Normal 1:1 case + qualifierList.push_back(qual); + } } } // Convert 'out' arguments. If it was a constant folded built-in, it won't be an aggregate anymore. // Built-ins with a single argument aren't called with an aggregate, but they also don't have an output. // Also, build the qualifier list for user function calls, which are always called with an aggregate. - if (result->getAsAggregate()) { - TQualifierList& qualifierList = result->getAsAggregate()->getQualifierList(); - for (int i = 0; i < fnCandidate->getParamCount(); ++i) { - TStorageQualifier qual = (*fnCandidate)[i].type->getQualifier().storage; - qualifierList.push_back(qual); - } - result = addOutputArgumentConversions(*fnCandidate, *result->getAsAggregate()); - } - - decomposeIntrinsic(loc, result, arguments); // HLSL->AST intrinsic decompositions - decomposeSampleMethods(loc, result, arguments); // HLSL->AST sample method decompositions + // We don't do this is if there has been a decomposition, which will have added its own conversions + // for output parameters. + if (result == fnNode && result->getAsAggregate()) + result = addOutputArgumentConversions(*fnCandidate, *result->getAsOperator()); } } // generic error recovery - // TODO: simplification: localize all the error recoveries that look like this, and taking type into account to reduce cascades + // TODO: simplification: localize all the error recoveries that look like this, and taking type into account to + // reduce cascades if (result == nullptr) result = intermediate.addConstantUnion(0.0, EbtFloat, loc); return result; } -// Finish processing object.length(). This started earlier in handleDotDereference(), where -// the ".length" part was recognized and semantically checked, and finished here where the -// function syntax "()" is recognized. -// -// Return resulting tree node. -TIntermTyped* HlslParseContext::handleLengthMethod(const TSourceLoc& loc, TFunction* function, TIntermNode* intermNode) +// An initial argument list is difficult: it can be null, or a single node, +// or an aggregate if more than one argument. Add one to the front, maintaining +// this lack of uniformity. +void HlslParseContext::pushFrontArguments(TIntermTyped* front, TIntermTyped*& arguments) { - int length = 0; + if (arguments == nullptr) + arguments = front; + else if (arguments->getAsAggregate() != nullptr) + arguments->getAsAggregate()->getSequence().insert(arguments->getAsAggregate()->getSequence().begin(), front); + else + arguments = intermediate.growAggregate(front, arguments); +} - if (function->getParamCount() > 0) - error(loc, "method does not accept any arguments", function->getName().c_str(), ""); - else { - const TType& type = intermNode->getAsTyped()->getType(); - if (type.isArray()) { - if (type.isRuntimeSizedArray()) { - // Create a unary op and let the back end handle it - return intermediate.addBuiltInFunctionCall(loc, EOpArrayLength, true, intermNode, TType(EbtInt)); - } else if (type.isImplicitlySizedArray()) { - if (intermNode->getAsSymbolNode() && isIoResizeArray(type)) { - // We could be between a layout declaration that gives a built-in io array implicit size and - // a user redeclaration of that array, meaning we have to substitute its implicit size here - // without actually redeclaring the array. (It is an error to use a member before the - // redeclaration, but not an error to use the array name itself.) - const TString& name = intermNode->getAsSymbolNode()->getName(); - if (name == "gl_in" || name == "gl_out") - length = getIoArrayImplicitSize(); - } - if (length == 0) { - if (intermNode->getAsSymbolNode() && isIoResizeArray(type)) - error(loc, "", function->getName().c_str(), "array must first be sized by a redeclaration or layout qualifier"); - else - error(loc, "", function->getName().c_str(), "array must be declared with a size before using this method"); - } - } else - length = type.getOuterArraySize(); - } else if (type.isMatrix()) - length = type.getMatrixCols(); - else if (type.isVector()) - length = type.getVectorSize(); - else { - // we should not get here, because earlier semantic checking should have prevented this path - error(loc, ".length()", "unexpected use of .length()", ""); - } +// +// HLSL allows mismatched dimensions on vec*mat, mat*vec, vec*vec, and mat*mat. This is a +// situation not well suited to resolution in intrinsic selection, but we can do so here, since we +// can look at both arguments insert explicit shape changes if required. +// +void HlslParseContext::addGenMulArgumentConversion(const TSourceLoc& loc, TFunction& call, TIntermTyped*& args) +{ + TIntermAggregate* argAggregate = args ? args->getAsAggregate() : nullptr; + + if (argAggregate == nullptr || argAggregate->getSequence().size() != 2) { + // It really ought to have two arguments. + error(loc, "expected: mul arguments", "", ""); + return; } - if (length == 0) - length = 1; + TIntermTyped* arg0 = argAggregate->getSequence()[0]->getAsTyped(); + TIntermTyped* arg1 = argAggregate->getSequence()[1]->getAsTyped(); - return intermediate.addConstantUnion(length, loc); + if (arg0->isVector() && arg1->isVector()) { + // For: + // vec * vec: it's handled during intrinsic selection, so while we could do it here, + // we can also ignore it, which is easier. + } else if (arg0->isVector() && arg1->isMatrix()) { + // vec * mat: we clamp the vec if the mat col is smaller, else clamp the mat col. + if (arg0->getVectorSize() < arg1->getMatrixCols()) { + // vec is smaller, so truncate larger mat dimension + const TType truncType(arg1->getBasicType(), arg1->getQualifier().storage, arg1->getQualifier().precision, + 0, arg0->getVectorSize(), arg1->getMatrixRows()); + arg1 = addConstructor(loc, arg1, truncType); + } else if (arg0->getVectorSize() > arg1->getMatrixCols()) { + // vec is larger, so truncate vec to mat size + const TType truncType(arg0->getBasicType(), arg0->getQualifier().storage, arg0->getQualifier().precision, + arg1->getMatrixCols()); + arg0 = addConstructor(loc, arg0, truncType); + } + } else if (arg0->isMatrix() && arg1->isVector()) { + // mat * vec: we clamp the vec if the mat col is smaller, else clamp the mat col. + if (arg1->getVectorSize() < arg0->getMatrixRows()) { + // vec is smaller, so truncate larger mat dimension + const TType truncType(arg0->getBasicType(), arg0->getQualifier().storage, arg0->getQualifier().precision, + 0, arg0->getMatrixCols(), arg1->getVectorSize()); + arg0 = addConstructor(loc, arg0, truncType); + } else if (arg1->getVectorSize() > arg0->getMatrixRows()) { + // vec is larger, so truncate vec to mat size + const TType truncType(arg1->getBasicType(), arg1->getQualifier().storage, arg1->getQualifier().precision, + arg0->getMatrixRows()); + arg1 = addConstructor(loc, arg1, truncType); + } + } else if (arg0->isMatrix() && arg1->isMatrix()) { + // mat * mat: we clamp the smaller inner dimension to match the other matrix size. + // Remember, HLSL Mrc = GLSL/SPIRV Mcr. + if (arg0->getMatrixRows() > arg1->getMatrixCols()) { + const TType truncType(arg0->getBasicType(), arg0->getQualifier().storage, arg0->getQualifier().precision, + 0, arg0->getMatrixCols(), arg1->getMatrixCols()); + arg0 = addConstructor(loc, arg0, truncType); + } else if (arg0->getMatrixRows() < arg1->getMatrixCols()) { + const TType truncType(arg1->getBasicType(), arg1->getQualifier().storage, arg1->getQualifier().precision, + 0, arg0->getMatrixRows(), arg1->getMatrixRows()); + arg1 = addConstructor(loc, arg1, truncType); + } + } else { + // It's something with scalars: we'll just leave it alone. Function selection will handle it + // downstream. + } + + // Warn if we altered one of the arguments + if (arg0 != argAggregate->getSequence()[0] || arg1 != argAggregate->getSequence()[1]) + warn(loc, "mul() matrix size mismatch", "", ""); + + // Put arguments back. (They might be unchanged, in which case this is harmless). + argAggregate->getSequence()[0] = arg0; + argAggregate->getSequence()[1] = arg1; + + call[0].type = &arg0->getWritableType(); + call[1].type = &arg1->getWritableType(); } // // Add any needed implicit conversions for function-call arguments to input parameters. // -void HlslParseContext::addInputArgumentConversions(const TFunction& function, TIntermNode*& arguments) const +void HlslParseContext::addInputArgumentConversions(const TFunction& function, TIntermTyped*& arguments) { TIntermAggregate* aggregate = arguments->getAsAggregate(); + // Replace a single argument with a single argument. + const auto setArg = [&](int paramNum, TIntermTyped* arg) { + if (function.getParamCount() == 1) + arguments = arg; + else { + if (aggregate == nullptr) + arguments = arg; + else + aggregate->getSequence()[paramNum] = arg; + } + }; + // Process each argument's conversion - for (int i = 0; i < function.getParamCount(); ++i) { + for (int param = 0; param < function.getParamCount(); ++param) { + if (! function[param].type->getQualifier().isParamInput()) + continue; + // At this early point there is a slight ambiguity between whether an aggregate 'arguments' // is the single argument itself or its children are the arguments. Only one argument // means take 'arguments' itself as the one argument. - TIntermTyped* arg = function.getParamCount() == 1 ? arguments->getAsTyped() : (aggregate ? aggregate->getSequence()[i]->getAsTyped() : arguments->getAsTyped()); - if (*function[i].type != arg->getType()) { - if (function[i].type->getQualifier().isParamInput()) { - // In-qualified arguments just need an extra node added above the argument to - // convert to the correct type. - arg = intermediate.addConversion(EOpFunctionCall, *function[i].type, arg); - if (arg) { - if (function.getParamCount() == 1) - arguments = arg; - else { - if (aggregate) - aggregate->getSequence()[i] = arg; - else - arguments = arg; - } + TIntermTyped* arg = function.getParamCount() == 1 + ? arguments->getAsTyped() + : (aggregate ? + aggregate->getSequence()[param]->getAsTyped() : + arguments->getAsTyped()); + if (*function[param].type != arg->getType()) { + // In-qualified arguments just need an extra node added above the argument to + // convert to the correct type. + TIntermTyped* convArg = intermediate.addConversion(EOpFunctionCall, *function[param].type, arg); + if (convArg != nullptr) + convArg = intermediate.addUniShapeConversion(EOpFunctionCall, *function[param].type, convArg); + if (convArg != nullptr) + setArg(param, convArg); + else + error(arg->getLoc(), "cannot convert input argument, argument", "", "%d", param); + } else { + if (wasFlattened(arg)) { + // If both formal and calling arg are to be flattened, leave that to argument + // expansion, not conversion. + if (!shouldFlatten(*function[param].type, function[param].type->getQualifier().storage, true)) { + // Will make a two-level subtree. + // The deepest will copy member-by-member to build the structure to pass. + // The level above that will be a two-operand EOpComma sequence that follows the copy by the + // object itself. + TVariable* internalAggregate = makeInternalVariable("aggShadow", *function[param].type); + internalAggregate->getWritableType().getQualifier().makeTemporary(); + TIntermSymbol* internalSymbolNode = new TIntermSymbol(internalAggregate->getUniqueId(), + internalAggregate->getName(), + internalAggregate->getType()); + internalSymbolNode->setLoc(arg->getLoc()); + // This makes the deepest level, the member-wise copy + TIntermAggregate* assignAgg = handleAssign(arg->getLoc(), EOpAssign, + internalSymbolNode, arg)->getAsAggregate(); + + // Now, pair that with the resulting aggregate. + assignAgg = intermediate.growAggregate(assignAgg, internalSymbolNode, arg->getLoc()); + assignAgg->setOperator(EOpComma); + assignAgg->setType(internalAggregate->getType()); + setArg(param, assignAgg); } } } } } +// +// Add any needed implicit expansion of calling arguments from what the shader listed to what's +// internally needed for the AST (given the constraints downstream). +// +void HlslParseContext::expandArguments(const TSourceLoc& loc, const TFunction& function, TIntermTyped*& arguments) +{ + TIntermAggregate* aggregate = arguments->getAsAggregate(); + int functionParamNumberOffset = 0; + + // Replace a single argument with a single argument. + const auto setArg = [&](int paramNum, TIntermTyped* arg) { + if (function.getParamCount() + functionParamNumberOffset == 1) + arguments = arg; + else { + if (aggregate == nullptr) + arguments = arg; + else + aggregate->getSequence()[paramNum] = arg; + } + }; + + // Replace a single argument with a list of arguments + const auto setArgList = [&](int paramNum, const TVector& args) { + if (args.size() == 1) + setArg(paramNum, args.front()); + else if (args.size() > 1) { + if (function.getParamCount() + functionParamNumberOffset == 1) { + arguments = intermediate.makeAggregate(args.front()); + std::for_each(args.begin() + 1, args.end(), + [&](TIntermTyped* arg) { + arguments = intermediate.growAggregate(arguments, arg); + }); + } else { + auto it = aggregate->getSequence().erase(aggregate->getSequence().begin() + paramNum); + aggregate->getSequence().insert(it, args.begin(), args.end()); + } + functionParamNumberOffset += (int)(args.size() - 1); + } + }; + + // Process each argument's conversion + for (int param = 0; param < function.getParamCount(); ++param) { + // At this early point there is a slight ambiguity between whether an aggregate 'arguments' + // is the single argument itself or its children are the arguments. Only one argument + // means take 'arguments' itself as the one argument. + TIntermTyped* arg = function.getParamCount() == 1 + ? arguments->getAsTyped() + : (aggregate ? + aggregate->getSequence()[param + functionParamNumberOffset]->getAsTyped() : + arguments->getAsTyped()); + + if (wasFlattened(arg) && shouldFlatten(*function[param].type, function[param].type->getQualifier().storage, true)) { + // Need to pass the structure members instead of the structure. + TVector memberArgs; + for (int memb = 0; memb < (int)arg->getType().getStruct()->size(); ++memb) + memberArgs.push_back(flattenAccess(arg, memb)); + setArgList(param + functionParamNumberOffset, memberArgs); + } + } + + // TODO: if we need both hidden counter args (below) and struct expansion (above) + // the two algorithms need to be merged: Each assumes the list starts out 1:1 between + // parameters and arguments. + + // If any argument is a pass-by-reference struct buffer with an associated counter + // buffer, we have to add another hidden parameter for that counter. + if (aggregate) + addStructBuffArguments(loc, aggregate); +} + // // Add any needed implicit output conversions for function-call arguments. This // can require a new tree topology, complicated further by whether the function @@ -1524,14 +5638,30 @@ void HlslParseContext::addInputArgumentConversions(const TFunction& function, TI // // Returns a node of a subtree that evaluates to the return value of the function. // -TIntermTyped* HlslParseContext::addOutputArgumentConversions(const TFunction& function, TIntermAggregate& intermNode) const +TIntermTyped* HlslParseContext::addOutputArgumentConversions(const TFunction& function, TIntermOperator& intermNode) { - TIntermSequence& arguments = intermNode.getSequence(); + assert (intermNode.getAsAggregate() != nullptr || intermNode.getAsUnaryNode() != nullptr); + + const TSourceLoc& loc = intermNode.getLoc(); + + TIntermSequence argSequence; // temp sequence for unary node args + + if (intermNode.getAsUnaryNode()) + argSequence.push_back(intermNode.getAsUnaryNode()->getOperand()); + + TIntermSequence& arguments = argSequence.empty() ? intermNode.getAsAggregate()->getSequence() : argSequence; + + const auto needsConversion = [&](int argNum) { + return function[argNum].type->getQualifier().isParamOutput() && + (*function[argNum].type != arguments[argNum]->getAsTyped()->getType() || + shouldConvertLValue(arguments[argNum]) || + wasFlattened(arguments[argNum]->getAsTyped())); + }; // Will there be any output conversions? bool outputConversions = false; for (int i = 0; i < function.getParamCount(); ++i) { - if (*function[i].type != arguments[i]->getAsTyped()->getType() && function[i].type->getQualifier().storage == EvqOut) { + if (needsConversion(i)) { outputConversions = true; break; } @@ -1553,8 +5683,8 @@ TIntermTyped* HlslParseContext::addOutputArgumentConversions(const TFunction& fu if (intermNode.getBasicType() != EbtVoid) { // do the "tempRet = function(...), " bit from above tempRet = makeInternalVariable("tempReturn", intermNode.getType()); - TIntermSymbol* tempRetNode = intermediate.addSymbol(*tempRet, intermNode.getLoc()); - conversionTree = intermediate.addAssign(EOpAssign, tempRetNode, &intermNode, intermNode.getLoc()); + TIntermSymbol* tempRetNode = intermediate.addSymbol(*tempRet, loc); + conversionTree = intermediate.addAssign(EOpAssign, tempRetNode, &intermNode, loc); } else conversionTree = &intermNode; @@ -1562,32 +5692,86 @@ TIntermTyped* HlslParseContext::addOutputArgumentConversions(const TFunction& fu // Process each argument's conversion for (int i = 0; i < function.getParamCount(); ++i) { - if (*function[i].type != arguments[i]->getAsTyped()->getType()) { - if (function[i].type->getQualifier().isParamOutput()) { - // Out-qualified arguments need to use the topology set up above. - // do the " ...(tempArg, ...), arg = tempArg" bit from above - TVariable* tempArg = makeInternalVariable("tempArg", *function[i].type); - tempArg->getWritableType().getQualifier().makeTemporary(); - TIntermSymbol* tempArgNode = intermediate.addSymbol(*tempArg, intermNode.getLoc()); - TIntermTyped* tempAssign = intermediate.addAssign(EOpAssign, arguments[i]->getAsTyped(), tempArgNode, arguments[i]->getLoc()); - conversionTree = intermediate.growAggregate(conversionTree, tempAssign, arguments[i]->getLoc()); - // replace the argument with another node for the same tempArg variable - arguments[i] = intermediate.addSymbol(*tempArg, intermNode.getLoc()); - } + if (needsConversion(i)) { + // Out-qualified arguments needing conversion need to use the topology setup above. + // Do the " ...(tempArg, ...), arg = tempArg" bit from above. + + // Make a temporary for what the function expects the argument to look like. + TVariable* tempArg = makeInternalVariable("tempArg", *function[i].type); + tempArg->getWritableType().getQualifier().makeTemporary(); + TIntermSymbol* tempArgNode = intermediate.addSymbol(*tempArg, loc); + + // This makes the deepest level, the member-wise copy + TIntermTyped* tempAssign = handleAssign(arguments[i]->getLoc(), EOpAssign, arguments[i]->getAsTyped(), + tempArgNode); + tempAssign = handleLvalue(arguments[i]->getLoc(), "assign", tempAssign); + conversionTree = intermediate.growAggregate(conversionTree, tempAssign, arguments[i]->getLoc()); + + // replace the argument with another node for the same tempArg variable + arguments[i] = intermediate.addSymbol(*tempArg, loc); } } // Finalize the tree topology (see bigger comment above). if (tempRet) { // do the "..., tempRet" bit from above - TIntermSymbol* tempRetNode = intermediate.addSymbol(*tempRet, intermNode.getLoc()); - conversionTree = intermediate.growAggregate(conversionTree, tempRetNode, intermNode.getLoc()); + TIntermSymbol* tempRetNode = intermediate.addSymbol(*tempRet, loc); + conversionTree = intermediate.growAggregate(conversionTree, tempRetNode, loc); } - conversionTree = intermediate.setAggregateOperator(conversionTree, EOpComma, intermNode.getType(), intermNode.getLoc()); + + conversionTree = intermediate.setAggregateOperator(conversionTree, EOpComma, intermNode.getType(), loc); return conversionTree; } +// +// Add any needed "hidden" counter buffer arguments for function calls. +// +// Modifies the 'aggregate' argument if needed. Otherwise, is no-op. +// +void HlslParseContext::addStructBuffArguments(const TSourceLoc& loc, TIntermAggregate*& aggregate) +{ + // See if there are any SB types with counters. + const bool hasStructBuffArg = + std::any_of(aggregate->getSequence().begin(), + aggregate->getSequence().end(), + [this](const TIntermNode* node) { + return (node->getAsTyped() != nullptr) && hasStructBuffCounter(node->getAsTyped()->getType()); + }); + + // Nothing to do, if we didn't find one. + if (! hasStructBuffArg) + return; + + TIntermSequence argsWithCounterBuffers; + + for (int param = 0; param < int(aggregate->getSequence().size()); ++param) { + argsWithCounterBuffers.push_back(aggregate->getSequence()[param]); + + if (hasStructBuffCounter(aggregate->getSequence()[param]->getAsTyped()->getType())) { + const TIntermSymbol* blockSym = aggregate->getSequence()[param]->getAsSymbolNode(); + if (blockSym != nullptr) { + TType counterType; + counterBufferType(loc, counterType); + + const TString counterBlockName(intermediate.addCounterBufferName(blockSym->getName())); + + TVariable* variable = makeInternalVariable(counterBlockName, counterType); + + // Mark this buffer's counter block as being in use + structBufferCounter[counterBlockName] = true; + + TIntermSymbol* sym = intermediate.addSymbol(*variable, loc); + argsWithCounterBuffers.push_back(sym); + } + } + } + + // Swap with the temp list we've built up. + aggregate->getSequence().swap(argsWithCounterBuffers); +} + + // // Do additional checking of built-in function calls that is not caught // by normal semantic checks on argument type, extension tagging, etc. @@ -1613,11 +5797,6 @@ void HlslParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fn } const TIntermSequence& aggArgs = *argp; // only valid when unaryArg is nullptr - // built-in texturing functions get their return value precision from the precision of the sampler - if (fnCandidate.getType().getQualifier().precision == EpqNone && - fnCandidate.getParamCount() > 0 && fnCandidate[0].type->getBasicType() == EbtSampler) - callNode.getQualifier().precision = arg0->getQualifier().precision; - switch (callNode.getOp()) { case EOpTextureGather: case EOpTextureGatherOffset: @@ -1633,7 +5812,8 @@ void HlslParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fn case EOpTextureGather: // More than two arguments needs gpu_shader5, and rectangular or shadow needs gpu_shader5, // otherwise, need GL_ARB_texture_gather. - if (fnCandidate.getParamCount() > 2 || fnCandidate[0].type->getSampler().dim == EsdRect || fnCandidate[0].type->getSampler().shadow) { + if (fnCandidate.getParamCount() > 2 || fnCandidate[0].type->getSampler().dim == EsdRect || + fnCandidate[0].type->getSampler().shadow) { if (! fnCandidate[0].type->getSampler().shadow) compArg = 2; } @@ -1688,14 +5868,15 @@ void HlslParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fn } if (arg > 0) { - if (! aggArgs[arg]->getAsConstantUnion()) + if (aggArgs[arg]->getAsConstantUnion() == nullptr) error(loc, "argument must be compile-time constant", "texel offset", ""); else { const TType& type = aggArgs[arg]->getAsTyped()->getType(); for (int c = 0; c < type.getVectorSize(); ++c) { int offset = aggArgs[arg]->getAsConstantUnion()->getConstArray()[c].getIConst(); if (offset > resources.maxProgramTexelOffset || offset < resources.minProgramTexelOffset) - error(loc, "value is out of range:", "texel offset", "[gl_MinProgramTexelOffset, gl_MaxProgramTexelOffset]"); + error(loc, "value is out of range:", "texel offset", + "[gl_MinProgramTexelOffset, gl_MaxProgramTexelOffset]"); } } } @@ -1720,11 +5901,6 @@ void HlslParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fn case EOpInterpolateAtCentroid: case EOpInterpolateAtSample: case EOpInterpolateAtOffset: - // "For the interpolateAt* functions, the call will return a precision - // qualification matching the precision of the 'interpolant' argument to - // the function call." - callNode.getQualifier().precision = arg0->getQualifier().precision; - // Make sure the first argument is an interpolant, or an array element of an interpolant if (arg0->getType().getQualifier().storage != EvqVaryingIn) { // It might still be an array element. @@ -1736,7 +5912,8 @@ void HlslParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fn // desktop 4.4 and later: swizzles may be used const TIntermTyped* base = TIntermediate::findLValueBase(arg0, true); if (base == nullptr || base->getType().getQualifier().storage != EvqVaryingIn) - error(loc, "first argument must be an interpolant, or interpolant-array element", fnCandidate.getName().c_str(), ""); + error(loc, "first argument must be an interpolant, or interpolant-array element", + fnCandidate.getName().c_str(), ""); } break; @@ -1746,11 +5923,15 @@ void HlslParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fn } // -// Handle seeing a built-in constructor in a grammar production. +// Handle seeing something in a grammar production that can be done by calling +// a constructor. // -TFunction* HlslParseContext::handleConstructorCall(const TSourceLoc& loc, const TType& type) +// The constructor still must be "handled" by handleFunctionCall(), which will +// then call handleConstructor(). +// +TFunction* HlslParseContext::makeConstructorCall(const TSourceLoc& loc, const TType& type) { - TOperator op = mapTypeToConstructorOp(type); + TOperator op = intermediate.mapTypeToConstructorOp(type); if (op == EOpNull) { error(loc, "cannot construct this type", type.getBasicString(), ""); @@ -1766,158 +5947,199 @@ TFunction* HlslParseContext::handleConstructorCall(const TSourceLoc& loc, const // Handle seeing a "COLON semantic" at the end of a type declaration, // by updating the type according to the semantic. // -void HlslParseContext::handleSemantic(TType& type, const TString& semantic) +void HlslParseContext::handleSemantic(TSourceLoc loc, TQualifier& qualifier, TBuiltInVariable builtIn, + const TString& upperCase) { - // TODO: need to know if it's an input or an output - // The following sketches what needs to be done, but can't be right - // without taking into account stage and input/output. - - if (semantic == "PSIZE") - type.getQualifier().builtIn = EbvPointSize; - else if (semantic == "POSITION") - type.getQualifier().builtIn = EbvPosition; - else if (semantic == "FOG") - type.getQualifier().builtIn = EbvFogFragCoord; - else if (semantic == "DEPTH" || semantic == "SV_Depth") - type.getQualifier().builtIn = EbvFragDepth; - else if (semantic == "VFACE" || semantic == "SV_IsFrontFace") - type.getQualifier().builtIn = EbvFace; - else if (semantic == "VPOS" || semantic == "SV_Position") - type.getQualifier().builtIn = EbvFragCoord; - else if (semantic == "SV_ClipDistance") - type.getQualifier().builtIn = EbvClipDistance; - else if (semantic == "SV_CullDistance") - type.getQualifier().builtIn = EbvCullDistance; - else if (semantic == "SV_VertexID") - type.getQualifier().builtIn = EbvVertexId; - else if (semantic == "SV_ViewportArrayIndex") - type.getQualifier().builtIn = EbvViewportIndex; -} + // Parse and return semantic number. If limit is 0, it will be ignored. Otherwise, if the parsed + // semantic number is >= limit, errorMsg is issued and 0 is returned. + // TODO: it would be nicer if limit and errorMsg had default parameters, but some compilers don't yet + // accept those in lambda functions. + const auto getSemanticNumber = [this, loc](const TString& semantic, unsigned int limit, const char* errorMsg) -> unsigned int { + size_t pos = semantic.find_last_not_of("0123456789"); + if (pos == std::string::npos) + return 0u; -// -// Given a type, find what operation would fully construct it. -// -TOperator HlslParseContext::mapTypeToConstructorOp(const TType& type) const -{ - TOperator op = EOpNull; + unsigned int semanticNum = (unsigned int)atoi(semantic.c_str() + pos + 1); - switch (type.getBasicType()) { - case EbtStruct: - op = EOpConstructStruct; - break; - case EbtSampler: - if (type.getSampler().combined) - op = EOpConstructTextureSampler; - break; - case EbtFloat: - if (type.isMatrix()) { - switch (type.getMatrixCols()) { - case 2: - switch (type.getMatrixRows()) { - case 2: op = EOpConstructMat2x2; break; - case 3: op = EOpConstructMat2x3; break; - case 4: op = EOpConstructMat2x4; break; - default: break; // some compilers want this - } - break; - case 3: - switch (type.getMatrixRows()) { - case 2: op = EOpConstructMat3x2; break; - case 3: op = EOpConstructMat3x3; break; - case 4: op = EOpConstructMat3x4; break; - default: break; // some compilers want this - } - break; - case 4: - switch (type.getMatrixRows()) { - case 2: op = EOpConstructMat4x2; break; - case 3: op = EOpConstructMat4x3; break; - case 4: op = EOpConstructMat4x4; break; - default: break; // some compilers want this - } - break; - default: break; // some compilers want this - } - } else { - switch (type.getVectorSize()) { - case 1: op = EOpConstructFloat; break; - case 2: op = EOpConstructVec2; break; - case 3: op = EOpConstructVec3; break; - case 4: op = EOpConstructVec4; break; - default: break; // some compilers want this - } + if (limit != 0 && semanticNum >= limit) { + error(loc, errorMsg, semantic.c_str(), ""); + return 0u; + } + + return semanticNum; + }; + + switch(builtIn) { + case EbvNone: + // Get location numbers from fragment outputs, instead of + // auto-assigning them. + if (language == EShLangFragment && upperCase.compare(0, 9, "SV_TARGET") == 0) { + qualifier.layoutLocation = getSemanticNumber(upperCase, 0, nullptr); + nextOutLocation = std::max(nextOutLocation, qualifier.layoutLocation + 1u); + } else if (upperCase.compare(0, 15, "SV_CLIPDISTANCE") == 0) { + builtIn = EbvClipDistance; + qualifier.layoutLocation = getSemanticNumber(upperCase, maxClipCullRegs, "invalid clip semantic"); + } else if (upperCase.compare(0, 15, "SV_CULLDISTANCE") == 0) { + builtIn = EbvCullDistance; + qualifier.layoutLocation = getSemanticNumber(upperCase, maxClipCullRegs, "invalid cull semantic"); } break; - case EbtDouble: - if (type.getMatrixCols()) { - switch (type.getMatrixCols()) { - case 2: - switch (type.getMatrixRows()) { - case 2: op = EOpConstructDMat2x2; break; - case 3: op = EOpConstructDMat2x3; break; - case 4: op = EOpConstructDMat2x4; break; - default: break; // some compilers want this - } - break; - case 3: - switch (type.getMatrixRows()) { - case 2: op = EOpConstructDMat3x2; break; - case 3: op = EOpConstructDMat3x3; break; - case 4: op = EOpConstructDMat3x4; break; - default: break; // some compilers want this - } - break; - case 4: - switch (type.getMatrixRows()) { - case 2: op = EOpConstructDMat4x2; break; - case 3: op = EOpConstructDMat4x3; break; - case 4: op = EOpConstructDMat4x4; break; - default: break; // some compilers want this - } - break; - } - } else { - switch (type.getVectorSize()) { - case 1: op = EOpConstructDouble; break; - case 2: op = EOpConstructDVec2; break; - case 3: op = EOpConstructDVec3; break; - case 4: op = EOpConstructDVec4; break; - default: break; // some compilers want this - } - } + case EbvPosition: + // adjust for stage in/out + if (language == EShLangFragment) + builtIn = EbvFragCoord; break; - case EbtInt: - switch (type.getVectorSize()) { - case 1: op = EOpConstructInt; break; - case 2: op = EOpConstructIVec2; break; - case 3: op = EOpConstructIVec3; break; - case 4: op = EOpConstructIVec4; break; - default: break; // some compilers want this - } + case EbvFragStencilRef: + error(loc, "unimplemented; need ARB_shader_stencil_export", "SV_STENCILREF", ""); break; - case EbtUint: - switch (type.getVectorSize()) { - case 1: op = EOpConstructUint; break; - case 2: op = EOpConstructUVec2; break; - case 3: op = EOpConstructUVec3; break; - case 4: op = EOpConstructUVec4; break; - default: break; // some compilers want this - } - break; - case EbtBool: - switch (type.getVectorSize()) { - case 1: op = EOpConstructBool; break; - case 2: op = EOpConstructBVec2; break; - case 3: op = EOpConstructBVec3; break; - case 4: op = EOpConstructBVec4; break; - default: break; // some compilers want this - } + case EbvTessLevelInner: + case EbvTessLevelOuter: + qualifier.patch = true; break; default: break; } - return op; + if (qualifier.builtIn == EbvNone) + qualifier.builtIn = builtIn; + qualifier.semanticName = intermediate.addSemanticName(upperCase); +} + +// +// Handle seeing something like "PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN" +// +// 'location' has the "c[Subcomponent]" part. +// 'component' points to the "component" part, or nullptr if not present. +// +void HlslParseContext::handlePackOffset(const TSourceLoc& loc, TQualifier& qualifier, const glslang::TString& location, + const glslang::TString* component) +{ + if (location.size() == 0 || location[0] != 'c') { + error(loc, "expected 'c'", "packoffset", ""); + return; + } + if (location.size() == 1) + return; + if (! isdigit(location[1])) { + error(loc, "expected number after 'c'", "packoffset", ""); + return; + } + + qualifier.layoutOffset = 16 * atoi(location.substr(1, location.size()).c_str()); + if (component != nullptr) { + int componentOffset = 0; + switch ((*component)[0]) { + case 'x': componentOffset = 0; break; + case 'y': componentOffset = 4; break; + case 'z': componentOffset = 8; break; + case 'w': componentOffset = 12; break; + default: + componentOffset = -1; + break; + } + if (componentOffset < 0 || component->size() > 1) { + error(loc, "expected {x, y, z, w} for component", "packoffset", ""); + return; + } + qualifier.layoutOffset += componentOffset; + } +} + +// +// Handle seeing something like "REGISTER LEFT_PAREN [shader_profile,] Type# RIGHT_PAREN" +// +// 'profile' points to the shader_profile part, or nullptr if not present. +// 'desc' is the type# part. +// +void HlslParseContext::handleRegister(const TSourceLoc& loc, TQualifier& qualifier, const glslang::TString* profile, + const glslang::TString& desc, int subComponent, const glslang::TString* spaceDesc) +{ + if (profile != nullptr) + warn(loc, "ignoring shader_profile", "register", ""); + + if (desc.size() < 1) { + error(loc, "expected register type", "register", ""); + return; + } + + int regNumber = 0; + if (desc.size() > 1) { + if (isdigit(desc[1])) + regNumber = atoi(desc.substr(1, desc.size()).c_str()); + else { + error(loc, "expected register number after register type", "register", ""); + return; + } + } + + // TODO: learn what all these really mean and how they interact with regNumber and subComponent + const std::vector& resourceInfo = intermediate.getResourceSetBinding(); + switch (std::tolower(desc[0])) { + case 'b': + case 't': + case 'c': + case 's': + case 'u': + // if nothing else has set the binding, do so now + // (other mechanisms override this one) + if (!qualifier.hasBinding()) + qualifier.layoutBinding = regNumber + subComponent; + + // This handles per-register layout sets numbers. For the global mode which sets + // every symbol to the same value, see setLinkageLayoutSets(). + if ((resourceInfo.size() % 3) == 0) { + // Apply per-symbol resource set and binding. + for (auto it = resourceInfo.cbegin(); it != resourceInfo.cend(); it = it + 3) { + if (strcmp(desc.c_str(), it[0].c_str()) == 0) { + qualifier.layoutSet = atoi(it[1].c_str()); + qualifier.layoutBinding = atoi(it[2].c_str()) + subComponent; + break; + } + } + } + break; + default: + warn(loc, "ignoring unrecognized register type", "register", "%c", desc[0]); + break; + } + + // space + unsigned int setNumber; + const auto crackSpace = [&]() -> bool { + const int spaceLen = 5; + if (spaceDesc->size() < spaceLen + 1) + return false; + if (spaceDesc->compare(0, spaceLen, "space") != 0) + return false; + if (! isdigit((*spaceDesc)[spaceLen])) + return false; + setNumber = atoi(spaceDesc->substr(spaceLen, spaceDesc->size()).c_str()); + return true; + }; + + // if nothing else has set the set, do so now + // (other mechanisms override this one) + if (spaceDesc && !qualifier.hasSet()) { + if (! crackSpace()) { + error(loc, "expected spaceN", "register", ""); + return; + } + qualifier.layoutSet = setNumber; + } +} + +// Convert to a scalar boolean, or if not allowed by HLSL semantics, +// report an error and return nullptr. +TIntermTyped* HlslParseContext::convertConditionalExpression(const TSourceLoc& loc, TIntermTyped* condition, + bool mustBeScalar) +{ + if (mustBeScalar && !condition->getType().isScalarOrVec1()) { + error(loc, "requires a scalar", "conditional expression", ""); + return nullptr; + } + + return intermediate.addConversion(EOpConstructBool, TType(EbtBool, EvqTemporary, condition->getVectorSize()), + condition); } // @@ -2007,7 +6229,6 @@ void HlslParseContext::globalCheck(const TSourceLoc& loc, const char* token) error(loc, "not allowed in nested scope", token, ""); } - bool HlslParseContext::builtInName(const TString& /*identifier*/) { return false; @@ -2020,7 +6241,7 @@ bool HlslParseContext::builtInName(const TString& /*identifier*/) // // Returns true if there was an error in construction. // -bool HlslParseContext::constructorError(const TSourceLoc& loc, TIntermNode* /*node*/, TFunction& function, +bool HlslParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, TFunction& function, TOperator op, TType& type) { type.shallowCopy(function.getType()); @@ -2047,6 +6268,33 @@ bool HlslParseContext::constructorError(const TSourceLoc& loc, TIntermNode* /*no case EOpConstructDMat4x2: case EOpConstructDMat4x3: case EOpConstructDMat4x4: + case EOpConstructIMat2x2: + case EOpConstructIMat2x3: + case EOpConstructIMat2x4: + case EOpConstructIMat3x2: + case EOpConstructIMat3x3: + case EOpConstructIMat3x4: + case EOpConstructIMat4x2: + case EOpConstructIMat4x3: + case EOpConstructIMat4x4: + case EOpConstructUMat2x2: + case EOpConstructUMat2x3: + case EOpConstructUMat2x4: + case EOpConstructUMat3x2: + case EOpConstructUMat3x3: + case EOpConstructUMat3x4: + case EOpConstructUMat4x2: + case EOpConstructUMat4x3: + case EOpConstructUMat4x4: + case EOpConstructBMat2x2: + case EOpConstructBMat2x3: + case EOpConstructBMat2x4: + case EOpConstructBMat3x2: + case EOpConstructBMat3x3: + case EOpConstructBMat3x4: + case EOpConstructBMat4x2: + case EOpConstructBMat4x3: + case EOpConstructBMat4x4: constructingMatrix = true; break; default: @@ -2065,7 +6313,7 @@ bool HlslParseContext::constructorError(const TSourceLoc& loc, TIntermNode* /*no bool arrayArg = false; for (int arg = 0; arg < function.getParamCount(); ++arg) { if (function[arg].type->isArray()) { - if (! function[arg].type->isExplicitlySizedArray()) { + if (function[arg].type->isUnsizedArray()) { // Can't construct from an unsized array. error(loc, "array argument must be sized", "constructor", ""); return true; @@ -2100,10 +6348,10 @@ bool HlslParseContext::constructorError(const TSourceLoc& loc, TIntermNode* /*no return true; } - if (type.isImplicitlySizedArray()) { + if (type.isUnsizedArray()) { // auto adapt the constructor type to the number of arguments type.changeOuterArraySize(function.getParamCount()); - } else if (type.getOuterArraySize() != function.getParamCount()) { + } else if (type.getOuterArraySize() != function.getParamCount() && type.computeNumComponents() > size) { error(loc, "array constructor needs one argument per array element", "constructor", ""); return true; } @@ -2112,26 +6360,33 @@ bool HlslParseContext::constructorError(const TSourceLoc& loc, TIntermNode* /*no // Types have to match, but we're still making the type. // Finish making the type, and the comparison is done later // when checking for conversion. - TArraySizes& arraySizes = type.getArraySizes(); + TArraySizes& arraySizes = *type.getArraySizes(); // At least the dimensionalities have to match. - if (! function[0].type->isArray() || arraySizes.getNumDims() != function[0].type->getArraySizes().getNumDims() + 1) { - error(loc, "array constructor argument not correct type to construct array element", "constructior", ""); + if (! function[0].type->isArray() || + arraySizes.getNumDims() != function[0].type->getArraySizes()->getNumDims() + 1) { + error(loc, "array constructor argument not correct type to construct array element", "constructor", ""); return true; } - if (arraySizes.isInnerImplicit()) { + if (arraySizes.isInnerUnsized()) { // "Arrays of arrays ..., and the size for any dimension is optional" // That means we need to adopt (from the first argument) the other array sizes into the type. for (int d = 1; d < arraySizes.getNumDims(); ++d) { if (arraySizes.getDimSize(d) == UnsizedArraySize) { - arraySizes.setDimSize(d, function[0].type->getArraySizes().getDimSize(d - 1)); + arraySizes.setDimSize(d, function[0].type->getArraySizes()->getDimSize(d - 1)); } } } } } + // Some array -> array type casts are okay + if (arrayArg && function.getParamCount() == 1 && op != EOpConstructStruct && type.isArray() && + !type.isArrayOfArrays() && !function[0].type->isArrayOfArrays() && + type.getVectorSize() >= 1 && function[0].type->getVectorSize() >= 1) + return false; + if (arrayArg && op != EOpConstructStruct && ! type.isArrayOfArrays()) { error(loc, "constructing non-array constituent from array argument", "constructor", ""); return true; @@ -2146,9 +6401,18 @@ bool HlslParseContext::constructorError(const TSourceLoc& loc, TIntermNode* /*no return true; } - if (op == EOpConstructStruct && ! type.isArray() && (int)type.getStruct()->size() != function.getParamCount()) { - error(loc, "Number of constructor parameters does not match the number of structure fields", "constructor", ""); - return true; + if (op == EOpConstructStruct && ! type.isArray()) { + if (isScalarConstructor(node)) + return false; + + // Self-type construction: e.g, we can construct a struct from a single identically typed object. + if (function.getParamCount() == 1 && type == *function[0].type) + return false; + + if ((int)type.getStruct()->size() != function.getParamCount()) { + error(loc, "Number of constructor parameters does not match the number of structure fields", "constructor", ""); + return true; + } } if ((op != EOpConstructStruct && size != 1 && size < type.computeNumComponents()) || @@ -2157,11 +6421,26 @@ bool HlslParseContext::constructorError(const TSourceLoc& loc, TIntermNode* /*no return true; } - // TIntermTyped* typed = node->getAsTyped(); - return false; } +// See if 'node', in the context of constructing aggregates, is a scalar argument +// to a constructor. +// +bool HlslParseContext::isScalarConstructor(const TIntermNode* node) +{ + // Obviously, it must be a scalar, but an aggregate node might not be fully + // completed yet: holding a sequence of initializers under an aggregate + // would not yet be typed, so don't check it's type. This corresponds to + // the aggregate operator also not being set yet. (An aggregate operation + // that legitimately yields a scalar will have a getOp() of that operator, + // not EOpNull.) + + return node->getAsTyped() != nullptr && + node->getAsTyped()->isScalar() && + (node->getAsAggregate() == nullptr || node->getAsAggregate()->getOp() != EOpNull); +} + // Verify all the correct semantics for constructing a combined texture/sampler. // Return true if the semantics are incorrect. bool HlslParseContext::constructorTextureSamplerError(const TSourceLoc& loc, const TFunction& function) @@ -2215,7 +6494,8 @@ bool HlslParseContext::constructorTextureSamplerError(const TSourceLoc& loc, con return true; } if (function.getType().getSampler().shadow != function[1].type->getSampler().shadow) { - error(loc, "sampler-constructor second argument presence of shadow must match constructor presence of shadow", token, ""); + error(loc, "sampler-constructor second argument presence of shadow must match constructor presence of shadow", + token, ""); return true; } @@ -2236,13 +6516,6 @@ bool HlslParseContext::voidErrorCheck(const TSourceLoc& loc, const TString& iden return false; } -// Checks to see if the node (for the expression) contains a scalar boolean expression or not -void HlslParseContext::boolCheck(const TSourceLoc& loc, const TIntermTyped* type) -{ - if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) - error(loc, "boolean expression expected", "", ""); -} - // // Fix just a full qualifier (no variables or types yet, but qualifier is complete) at global level. // @@ -2270,23 +6543,17 @@ void HlslParseContext::globalQualifierFix(const TSourceLoc&, TQualifier& qualifi // 'dst', for the purpose of error checking order for versions // that require specific orderings of qualifiers. // -void HlslParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, const TQualifier& src, bool force) +void HlslParseContext::mergeQualifiers(TQualifier& dst, const TQualifier& src) { // Storage qualification if (dst.storage == EvqTemporary || dst.storage == EvqGlobal) dst.storage = src.storage; else if ((dst.storage == EvqIn && src.storage == EvqOut) || - (dst.storage == EvqOut && src.storage == EvqIn)) + (dst.storage == EvqOut && src.storage == EvqIn)) dst.storage = EvqInOut; else if ((dst.storage == EvqIn && src.storage == EvqConst) || - (dst.storage == EvqConst && src.storage == EvqIn)) + (dst.storage == EvqConst && src.storage == EvqIn)) dst.storage = EvqConstReadOnly; - else if (src.storage != EvqTemporary && src.storage != EvqGlobal) - error(loc, "too many storage qualifiers", GetStorageQualifierString(src.storage), ""); - - // Precision qualifiers - if (dst.precision == EpqNone || (force && src.precision != EpqNone)) - dst.precision = src.precision; // Layout qualifiers mergeObjectLayoutQualifiers(dst, src, false); @@ -2308,6 +6575,7 @@ void HlslParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, c MERGE_SINGLETON(readonly); MERGE_SINGLETON(writeonly); MERGE_SINGLETON(specConstant); + MERGE_SINGLETON(nonUniform); } // used to flatten the sampler type space into a single dimension @@ -2318,7 +6586,8 @@ int HlslParseContext::computeSamplerTypeIndex(TSampler& sampler) int shadowIndex = sampler.shadow ? 1 : 0; int externalIndex = sampler.external ? 1 : 0; - return EsdNumDims * (EbtNumTypes * (2 * (2 * arrayIndex + shadowIndex) + externalIndex) + sampler.type) + sampler.dim; + return EsdNumDims * + (EbtNumTypes * (2 * (2 * arrayIndex + shadowIndex) + externalIndex) + sampler.type) + sampler.dim; } // @@ -2362,7 +6631,7 @@ void HlslParseContext::arraySizeCheck(const TSourceLoc& loc, TIntermTyped* expr, // void HlslParseContext::arraySizeRequiredCheck(const TSourceLoc& loc, const TArraySizes& arraySizes) { - if (arraySizes.isImplicit()) + if (arraySizes.hasUnsized()) error(loc, "array size required", "", ""); } @@ -2376,27 +6645,14 @@ void HlslParseContext::structArrayCheck(const TSourceLoc& /*loc*/, const TType& } } -// Merge array dimensions listed in 'sizes' onto the type's array dimensions. -// -// From the spec: "vec4[2] a[3]; // size-3 array of size-2 array of vec4" -// -// That means, the 'sizes' go in front of the 'type' as outermost sizes. -// 'type' is the type part of the declaration (to the left) -// 'sizes' is the arrayness tagged on the identifier (to the right) -// -void HlslParseContext::arrayDimMerge(TType& type, const TArraySizes* sizes) -{ - if (sizes) - type.addArrayOuterSizes(*sizes); -} - // // Do all the semantic checking for declaring or redeclaring an array, with and // without a size, and make the right changes to the symbol table. // -void HlslParseContext::declareArray(const TSourceLoc& loc, TString& identifier, const TType& type, TSymbol*& symbol, bool& newDeclaration) +void HlslParseContext::declareArray(const TSourceLoc& loc, const TString& identifier, const TType& type, + TSymbol*& symbol, bool track) { - if (! symbol) { + if (symbol == nullptr) { bool currentScope; symbol = symbolTable.find(identifier, nullptr, ¤tScope); @@ -2411,15 +6667,8 @@ void HlslParseContext::declareArray(const TSourceLoc& loc, TString& identifier, // symbol = new TVariable(&identifier, type); symbolTable.insert(*symbol); - newDeclaration = true; - - if (! symbolTable.atBuiltInLevel()) { - if (isIoResizeArray(type)) { - ioArraySymbolResizeList.push_back(symbol); - checkIoArraysConsistency(loc, true); - } else - fixIoArraySize(loc, symbol->getWritableType()); - } + if (track && symbolTable.atGlobalLevel()) + trackLinkage(*symbol); return; } @@ -2434,7 +6683,7 @@ void HlslParseContext::declareArray(const TSourceLoc& loc, TString& identifier, // Process a redeclaration. // - if (! symbol) { + if (symbol == nullptr) { error(loc, "array variable name expected", identifier.c_str(), ""); return; } @@ -2442,64 +6691,31 @@ void HlslParseContext::declareArray(const TSourceLoc& loc, TString& identifier, // redeclareBuiltinVariable() should have already done the copyUp() TType& existingType = symbol->getWritableType(); - - if (existingType.isExplicitlySizedArray()) { - // be more lenient for input arrays to geometry shaders and tessellation control outputs, where the redeclaration is the same size - if (! (isIoResizeArray(type) && existingType.getOuterArraySize() == type.getOuterArraySize())) - error(loc, "redeclaration of array with size", identifier.c_str(), ""); + if (existingType.isSizedArray()) { + // be more lenient for input arrays to geometry shaders and tessellation control outputs, + // where the redeclaration is the same size return; } existingType.updateArraySizes(type); - - if (isIoResizeArray(type)) - checkIoArraysConsistency(loc); } -void HlslParseContext::updateImplicitArraySize(const TSourceLoc& loc, TIntermNode *node, int index) +// +// Enforce non-initializer type/qualifier rules. +// +void HlslParseContext::fixConstInit(const TSourceLoc& loc, const TString& identifier, TType& type, + TIntermTyped*& initializer) { - // maybe there is nothing to do... - TIntermTyped* typedNode = node->getAsTyped(); - if (typedNode->getType().getImplicitArraySize() > index) - return; - - // something to do... - - // Figure out what symbol to lookup, as we will use its type to edit for the size change, - // as that type will be shared through shallow copies for future references. - TSymbol* symbol = nullptr; - int blockIndex = -1; - const TString* lookupName = nullptr; - if (node->getAsSymbolNode()) - lookupName = &node->getAsSymbolNode()->getName(); - else if (node->getAsBinaryNode()) { - const TIntermBinary* deref = node->getAsBinaryNode(); - // This has to be the result of a block dereference, unless it's bad shader code - // If it's a uniform block, then an error will be issued elsewhere, but - // return early now to avoid crashing later in this function. - if (! deref->getLeft()->getAsSymbolNode() || deref->getLeft()->getBasicType() != EbtBlock || - deref->getLeft()->getType().getQualifier().storage == EvqUniform || - deref->getRight()->getAsConstantUnion() == nullptr) - return; - - blockIndex = deref->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst(); - - lookupName = &deref->getLeft()->getAsSymbolNode()->getName(); - if (IsAnonymous(*lookupName)) - lookupName = &(*deref->getLeft()->getType().getStruct())[blockIndex].type->getFieldName(); + // + // Make the qualifier make sense, given that there is an initializer. + // + if (initializer == nullptr) { + if (type.getQualifier().storage == EvqConst || + type.getQualifier().storage == EvqConstReadOnly) { + initializer = intermediate.makeAggregate(loc); + warn(loc, "variable with qualifier 'const' not initialized; zero initializing", identifier.c_str(), ""); + } } - - // Lookup the symbol, should only fail if shader code is incorrect - symbol = symbolTable.find(*lookupName); - if (symbol == nullptr) - return; - - if (symbol->getAsFunction()) { - error(loc, "array variable name expected", symbol->getName().c_str(), ""); - return; - } - - symbol->getWritableType().setImplicitArraySize(index + 1); } // @@ -2514,7 +6730,7 @@ void HlslParseContext::updateImplicitArraySize(const TSourceLoc& loc, TIntermNod // TSymbol* HlslParseContext::redeclareBuiltinVariable(const TSourceLoc& /*loc*/, const TString& identifier, const TQualifier& /*qualifier*/, - const TShaderQualifiers& /*publicType*/, bool& /*newDeclaration*/) + const TShaderQualifiers& /*publicType*/) { if (! builtInName(identifier) || symbolTable.atBuiltInLevel() || ! symbolTable.atGlobalLevel()) return nullptr; @@ -2523,130 +6739,92 @@ TSymbol* HlslParseContext::redeclareBuiltinVariable(const TSourceLoc& /*loc*/, c } // -// Either redeclare the requested block, or give an error message why it can't be done. +// Generate index to the array element in a structure buffer (SSBO) // -// TODO: functionality: explicitly sizing members of redeclared blocks is not giving them an explicit size -void HlslParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newTypeList, const TString& blockName, const TString* instanceName, TArraySizes* arraySizes) +TIntermTyped* HlslParseContext::indexStructBufferContent(const TSourceLoc& loc, TIntermTyped* buffer) const { - // Redeclaring a built-in block... + // Bail out if not a struct buffer + if (buffer == nullptr || ! isStructBufferType(buffer->getType())) + return nullptr; - // Blocks with instance names are easy to find, lookup the instance name, - // Anonymous blocks need to be found via a member. - bool builtIn; - TSymbol* block; - if (instanceName) - block = symbolTable.find(*instanceName, &builtIn); - else - block = symbolTable.find(newTypeList.front().type->getFieldName(), &builtIn); + // Runtime sized array is always the last element. + const TTypeList* bufferStruct = buffer->getType().getStruct(); + TIntermTyped* arrayPosition = intermediate.addConstantUnion(unsigned(bufferStruct->size()-1), loc); - // If the block was not found, this must be a version/profile/stage - // that doesn't have it, or the instance name is wrong. - const char* errorName = instanceName ? instanceName->c_str() : newTypeList.front().type->getFieldName().c_str(); - if (! block) { - error(loc, "no declaration found for redeclaration", errorName, ""); - return; - } - // Built-in blocks cannot be redeclared more than once, which if happened, - // we'd be finding the already redeclared one here, rather than the built in. - if (! builtIn) { - error(loc, "can only redeclare a built-in block once, and before any use", blockName.c_str(), ""); - return; - } + TIntermTyped* argArray = intermediate.addIndex(EOpIndexDirectStruct, buffer, arrayPosition, loc); + argArray->setType(*(*bufferStruct)[bufferStruct->size()-1].type); - // Copy the block to make a writable version, to insert into the block table after editing. - block = symbolTable.copyUpDeferredInsert(block); + return argArray; +} - if (block->getType().getBasicType() != EbtBlock) { - error(loc, "cannot redeclare a non block as a block", errorName, ""); - return; - } +// +// IFF type is a structuredbuffer/byteaddressbuffer type, return the content +// (template) type. E.g, StructuredBuffer -> MyType. Else return nullptr. +// +TType* HlslParseContext::getStructBufferContentType(const TType& type) const +{ + if (type.getBasicType() != EbtBlock || type.getQualifier().storage != EvqBuffer) + return nullptr; - // Edit and error check the container against the redeclaration - // - remove unused members - // - ensure remaining qualifiers/types match - TType& type = block->getWritableType(); - TTypeList::iterator member = type.getWritableStruct()->begin(); - size_t numOriginalMembersFound = 0; - while (member != type.getStruct()->end()) { - // look for match - bool found = false; - TTypeList::const_iterator newMember; - TSourceLoc memberLoc; - memberLoc.init(); - for (newMember = newTypeList.begin(); newMember != newTypeList.end(); ++newMember) { - if (member->type->getFieldName() == newMember->type->getFieldName()) { - found = true; - memberLoc = newMember->loc; - break; - } + const int memberCount = (int)type.getStruct()->size(); + assert(memberCount > 0); + + TType* contentType = (*type.getStruct())[memberCount-1].type; + + return contentType->isUnsizedArray() ? contentType : nullptr; +} + +// +// If an existing struct buffer has a sharable type, then share it. +// +void HlslParseContext::shareStructBufferType(TType& type) +{ + // PackOffset must be equivalent to share types on a per-member basis. + // Note: cannot use auto type due to recursion. Thus, this is a std::function. + const std::function + compareQualifiers = [&](TType& lhs, TType& rhs) -> bool { + if (lhs.getQualifier().layoutOffset != rhs.getQualifier().layoutOffset) + return false; + + if (lhs.isStruct() != rhs.isStruct()) + return false; + + if (lhs.isStruct() && rhs.isStruct()) { + if (lhs.getStruct()->size() != rhs.getStruct()->size()) + return false; + + for (int i = 0; i < int(lhs.getStruct()->size()); ++i) + if (!compareQualifiers(*(*lhs.getStruct())[i].type, *(*rhs.getStruct())[i].type)) + return false; } - if (found) { - ++numOriginalMembersFound; - // - ensure match between redeclared members' types - // - check for things that can't be changed - // - update things that can be changed - TType& oldType = *member->type; - const TType& newType = *newMember->type; - if (! newType.sameElementType(oldType)) - error(memberLoc, "cannot redeclare block member with a different type", member->type->getFieldName().c_str(), ""); - if (oldType.isArray() != newType.isArray()) - error(memberLoc, "cannot change arrayness of redeclared block member", member->type->getFieldName().c_str(), ""); - else if (! oldType.sameArrayness(newType) && oldType.isExplicitlySizedArray()) - error(memberLoc, "cannot change array size of redeclared block member", member->type->getFieldName().c_str(), ""); - if (newType.getQualifier().isMemory()) - error(memberLoc, "cannot add memory qualifier to redeclared block member", member->type->getFieldName().c_str(), ""); - if (newType.getQualifier().hasLayout()) - error(memberLoc, "cannot add layout to redeclared block member", member->type->getFieldName().c_str(), ""); - if (newType.getQualifier().patch) - error(memberLoc, "cannot add patch to redeclared block member", member->type->getFieldName().c_str(), ""); - oldType.getQualifier().centroid = newType.getQualifier().centroid; - oldType.getQualifier().sample = newType.getQualifier().sample; - oldType.getQualifier().invariant = newType.getQualifier().invariant; - oldType.getQualifier().noContraction = newType.getQualifier().noContraction; - oldType.getQualifier().smooth = newType.getQualifier().smooth; - oldType.getQualifier().flat = newType.getQualifier().flat; - oldType.getQualifier().nopersp = newType.getQualifier().nopersp; + return true; + }; - // go to next member - ++member; - } else { - // For missing members of anonymous blocks that have been redeclared, - // hide the original (shared) declaration. - // Instance-named blocks can just have the member removed. - if (instanceName) - member = type.getWritableStruct()->erase(member); - else { - member->type->hideMember(); - ++member; - } + // We need to compare certain qualifiers in addition to the type. + const auto typeEqual = [compareQualifiers](TType& lhs, TType& rhs) -> bool { + if (lhs.getQualifier().readonly != rhs.getQualifier().readonly) + return false; + + // If both are structures, recursively look for packOffset equality + // as well as type equality. + return compareQualifiers(lhs, rhs) && lhs == rhs; + }; + + // This is an exhaustive O(N) search, but real world shaders have + // only a small number of these. + for (int idx = 0; idx < int(structBufferTypes.size()); ++idx) { + // If the deep structure matches, modulo qualifiers, use it + if (typeEqual(*structBufferTypes[idx], type)) { + type.shallowCopy(*structBufferTypes[idx]); + return; } } - if (numOriginalMembersFound < newTypeList.size()) - error(loc, "block redeclaration has extra members", blockName.c_str(), ""); - if (type.isArray() != (arraySizes != nullptr)) - error(loc, "cannot change arrayness of redeclared block", blockName.c_str(), ""); - else if (type.isArray()) { - if (type.isExplicitlySizedArray() && arraySizes->getOuterSize() == UnsizedArraySize) - error(loc, "block already declared with size, can't redeclare as implicitly-sized", blockName.c_str(), ""); - else if (type.isExplicitlySizedArray() && type.getArraySizes() != *arraySizes) - error(loc, "cannot change array size of redeclared block", blockName.c_str(), ""); - else if (type.isImplicitlySizedArray() && arraySizes->getOuterSize() != UnsizedArraySize) - type.changeOuterArraySize(arraySizes->getOuterSize()); - } - - symbolTable.insert(*block); - - // Tracking for implicit sizing of array - if (isIoResizeArray(block->getType())) { - ioArraySymbolResizeList.push_back(block); - checkIoArraysConsistency(loc, true); - } else if (block->getType().isArray()) - fixIoArraySize(loc, block->getWritableType()); - - // Save it in the AST for linker use. - intermediate.addSymbolLinkageNode(linkage, *block); + // Otherwise, remember it: + TType* typeCopy = new TType; + typeCopy->shallowCopy(type); + structBufferTypes.push_back(typeCopy); } void HlslParseContext::paramFix(TType& type) @@ -2656,9 +6834,23 @@ void HlslParseContext::paramFix(TType& type) type.getQualifier().storage = EvqConstReadOnly; break; case EvqGlobal: + case EvqUniform: case EvqTemporary: type.getQualifier().storage = EvqIn; break; + case EvqBuffer: + { + // SSBO parameter. These do not go through the declareBlock path since they are fn parameters. + correctUniform(type.getQualifier()); + TQualifier bufferQualifier = globalBufferDefaults; + mergeObjectLayoutQualifiers(bufferQualifier, type.getQualifier(), true); + bufferQualifier.storage = type.getQualifier().storage; + bufferQualifier.readonly = type.getQualifier().readonly; + bufferQualifier.coherent = type.getQualifier().coherent; + bufferQualifier.declaredBuiltIn = type.getQualifier().declaredBuiltIn; + type.getQualifier() = bufferQualifier; + break; + } default: break; } @@ -2676,51 +6868,58 @@ void HlslParseContext::specializationCheck(const TSourceLoc& loc, const TType& t // Put the id's layout qualification into the public type, for qualifiers not having a number set. // This is before we know any type information for error checking. -void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publicType, TString& id) +void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TQualifier& qualifier, TString& id) { std::transform(id.begin(), id.end(), id.begin(), ::tolower); if (id == TQualifier::getLayoutMatrixString(ElmColumnMajor)) { - publicType.qualifier.layoutMatrix = ElmColumnMajor; + qualifier.layoutMatrix = ElmRowMajor; return; } if (id == TQualifier::getLayoutMatrixString(ElmRowMajor)) { - publicType.qualifier.layoutMatrix = ElmRowMajor; + qualifier.layoutMatrix = ElmColumnMajor; return; } if (id == "push_constant") { requireVulkan(loc, "push_constant"); - publicType.qualifier.layoutPushConstant = true; + qualifier.layoutPushConstant = true; return; } if (language == EShLangGeometry || language == EShLangTessEvaluation) { if (id == TQualifier::getGeometryString(ElgTriangles)) { - publicType.shaderQualifiers.geometry = ElgTriangles; + // publicType.shaderQualifiers.geometry = ElgTriangles; + warn(loc, "ignored", id.c_str(), ""); return; } if (language == EShLangGeometry) { if (id == TQualifier::getGeometryString(ElgPoints)) { - publicType.shaderQualifiers.geometry = ElgPoints; + // publicType.shaderQualifiers.geometry = ElgPoints; + warn(loc, "ignored", id.c_str(), ""); return; } if (id == TQualifier::getGeometryString(ElgLineStrip)) { - publicType.shaderQualifiers.geometry = ElgLineStrip; + // publicType.shaderQualifiers.geometry = ElgLineStrip; + warn(loc, "ignored", id.c_str(), ""); return; } if (id == TQualifier::getGeometryString(ElgLines)) { - publicType.shaderQualifiers.geometry = ElgLines; + // publicType.shaderQualifiers.geometry = ElgLines; + warn(loc, "ignored", id.c_str(), ""); return; } if (id == TQualifier::getGeometryString(ElgLinesAdjacency)) { - publicType.shaderQualifiers.geometry = ElgLinesAdjacency; + // publicType.shaderQualifiers.geometry = ElgLinesAdjacency; + warn(loc, "ignored", id.c_str(), ""); return; } if (id == TQualifier::getGeometryString(ElgTrianglesAdjacency)) { - publicType.shaderQualifiers.geometry = ElgTrianglesAdjacency; + // publicType.shaderQualifiers.geometry = ElgTrianglesAdjacency; + warn(loc, "ignored", id.c_str(), ""); return; } if (id == TQualifier::getGeometryString(ElgTriangleStrip)) { - publicType.shaderQualifiers.geometry = ElgTriangleStrip; + // publicType.shaderQualifiers.geometry = ElgTriangleStrip; + warn(loc, "ignored", id.c_str(), ""); return; } } else { @@ -2728,65 +6927,78 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu // input primitive if (id == TQualifier::getGeometryString(ElgTriangles)) { - publicType.shaderQualifiers.geometry = ElgTriangles; + // publicType.shaderQualifiers.geometry = ElgTriangles; + warn(loc, "ignored", id.c_str(), ""); return; } if (id == TQualifier::getGeometryString(ElgQuads)) { - publicType.shaderQualifiers.geometry = ElgQuads; + // publicType.shaderQualifiers.geometry = ElgQuads; + warn(loc, "ignored", id.c_str(), ""); return; } if (id == TQualifier::getGeometryString(ElgIsolines)) { - publicType.shaderQualifiers.geometry = ElgIsolines; + // publicType.shaderQualifiers.geometry = ElgIsolines; + warn(loc, "ignored", id.c_str(), ""); return; } // vertex spacing if (id == TQualifier::getVertexSpacingString(EvsEqual)) { - publicType.shaderQualifiers.spacing = EvsEqual; + // publicType.shaderQualifiers.spacing = EvsEqual; + warn(loc, "ignored", id.c_str(), ""); return; } if (id == TQualifier::getVertexSpacingString(EvsFractionalEven)) { - publicType.shaderQualifiers.spacing = EvsFractionalEven; + // publicType.shaderQualifiers.spacing = EvsFractionalEven; + warn(loc, "ignored", id.c_str(), ""); return; } if (id == TQualifier::getVertexSpacingString(EvsFractionalOdd)) { - publicType.shaderQualifiers.spacing = EvsFractionalOdd; + // publicType.shaderQualifiers.spacing = EvsFractionalOdd; + warn(loc, "ignored", id.c_str(), ""); return; } // triangle order if (id == TQualifier::getVertexOrderString(EvoCw)) { - publicType.shaderQualifiers.order = EvoCw; + // publicType.shaderQualifiers.order = EvoCw; + warn(loc, "ignored", id.c_str(), ""); return; } if (id == TQualifier::getVertexOrderString(EvoCcw)) { - publicType.shaderQualifiers.order = EvoCcw; + // publicType.shaderQualifiers.order = EvoCcw; + warn(loc, "ignored", id.c_str(), ""); return; } // point mode if (id == "point_mode") { - publicType.shaderQualifiers.pointMode = true; + // publicType.shaderQualifiers.pointMode = true; + warn(loc, "ignored", id.c_str(), ""); return; } } } if (language == EShLangFragment) { if (id == "origin_upper_left") { - publicType.shaderQualifiers.originUpperLeft = true; + // publicType.shaderQualifiers.originUpperLeft = true; + warn(loc, "ignored", id.c_str(), ""); return; } if (id == "pixel_center_integer") { - publicType.shaderQualifiers.pixelCenterInteger = true; + // publicType.shaderQualifiers.pixelCenterInteger = true; + warn(loc, "ignored", id.c_str(), ""); return; } if (id == "early_fragment_tests") { - publicType.shaderQualifiers.earlyFragmentTests = true; + // publicType.shaderQualifiers.earlyFragmentTests = true; + warn(loc, "ignored", id.c_str(), ""); return; } for (TLayoutDepth depth = (TLayoutDepth)(EldNone + 1); depth < EldCount; depth = (TLayoutDepth)(depth + 1)) { if (id == TQualifier::getLayoutDepthString(depth)) { - publicType.shaderQualifiers.layoutDepth = depth; + // publicType.shaderQualifiers.layoutDepth = depth; + warn(loc, "ignored", id.c_str(), ""); return; } } @@ -2796,7 +7008,8 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu if (id == TQualifier::getBlendEquationString(be)) { requireExtensions(loc, 1, &E_GL_KHR_blend_equation_advanced, "blend equation"); intermediate.addBlendEquation(be); - publicType.shaderQualifiers.blendEquation = true; + // publicType.shaderQualifiers.blendEquation = true; + warn(loc, "ignored", id.c_str(), ""); found = true; break; } @@ -2811,10 +7024,11 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu // Put the id's layout qualifier value into the public type, for qualifiers having a number set. // This is before we know any type information for error checking. -void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publicType, TString& id, const TIntermTyped* node) +void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TQualifier& qualifier, TString& id, + const TIntermTyped* node) { const char* feature = "layout-id value"; - //const char* nonLiteralFeature = "non-literal layout-id value"; + // const char* nonLiteralFeature = "non-literal layout-id value"; integerCheck(node, feature); const TIntermConstantUnion* constUnion = node->getAsConstantUnion(); @@ -2826,70 +7040,72 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu std::transform(id.begin(), id.end(), id.begin(), ::tolower); if (id == "offset") { - publicType.qualifier.layoutOffset = value; + qualifier.layoutOffset = value; return; } else if (id == "align") { // "The specified alignment must be a power of 2, or a compile-time error results." if (! IsPow2(value)) error(loc, "must be a power of 2", "align", ""); else - publicType.qualifier.layoutAlign = value; + qualifier.layoutAlign = value; return; } else if (id == "location") { if ((unsigned int)value >= TQualifier::layoutLocationEnd) error(loc, "location is too large", id.c_str(), ""); else - publicType.qualifier.layoutLocation = value; + qualifier.layoutLocation = value; return; } else if (id == "set") { if ((unsigned int)value >= TQualifier::layoutSetEnd) error(loc, "set is too large", id.c_str(), ""); else - publicType.qualifier.layoutSet = value; + qualifier.layoutSet = value; return; } else if (id == "binding") { if ((unsigned int)value >= TQualifier::layoutBindingEnd) error(loc, "binding is too large", id.c_str(), ""); else - publicType.qualifier.layoutBinding = value; + qualifier.layoutBinding = value; return; } else if (id == "component") { if ((unsigned)value >= TQualifier::layoutComponentEnd) error(loc, "component is too large", id.c_str(), ""); else - publicType.qualifier.layoutComponent = value; + qualifier.layoutComponent = value; return; } else if (id.compare(0, 4, "xfb_") == 0) { - // "Any shader making any static use (after preprocessing) of any of these - // *xfb_* qualifiers will cause the shader to be in a transform feedback - // capturing mode and hence responsible for describing the transform feedback + // "Any shader making any static use (after preprocessing) of any of these + // *xfb_* qualifiers will cause the shader to be in a transform feedback + // capturing mode and hence responsible for describing the transform feedback // setup." intermediate.setXfbMode(); if (id == "xfb_buffer") { // "It is a compile-time error to specify an *xfb_buffer* that is greater than // the implementation-dependent constant gl_MaxTransformFeedbackBuffers." if (value >= resources.maxTransformFeedbackBuffers) - error(loc, "buffer is too large:", id.c_str(), "gl_MaxTransformFeedbackBuffers is %d", resources.maxTransformFeedbackBuffers); + error(loc, "buffer is too large:", id.c_str(), "gl_MaxTransformFeedbackBuffers is %d", + resources.maxTransformFeedbackBuffers); if (value >= (int)TQualifier::layoutXfbBufferEnd) error(loc, "buffer is too large:", id.c_str(), "internal max is %d", TQualifier::layoutXfbBufferEnd - 1); else - publicType.qualifier.layoutXfbBuffer = value; + qualifier.layoutXfbBuffer = value; return; } else if (id == "xfb_offset") { if (value >= (int)TQualifier::layoutXfbOffsetEnd) error(loc, "offset is too large:", id.c_str(), "internal max is %d", TQualifier::layoutXfbOffsetEnd - 1); else - publicType.qualifier.layoutXfbOffset = value; + qualifier.layoutXfbOffset = value; return; } else if (id == "xfb_stride") { - // "The resulting stride (implicit or explicit), when divided by 4, must be less than or equal to the + // "The resulting stride (implicit or explicit), when divided by 4, must be less than or equal to the // implementation-dependent constant gl_MaxTransformFeedbackInterleavedComponents." if (value > 4 * resources.maxTransformFeedbackInterleavedComponents) - error(loc, "1/4 stride is too large:", id.c_str(), "gl_MaxTransformFeedbackInterleavedComponents is %d", resources.maxTransformFeedbackInterleavedComponents); + error(loc, "1/4 stride is too large:", id.c_str(), "gl_MaxTransformFeedbackInterleavedComponents is %d", + resources.maxTransformFeedbackInterleavedComponents); else if (value >= (int)TQualifier::layoutXfbStrideEnd) error(loc, "stride is too large:", id.c_str(), "internal max is %d", TQualifier::layoutXfbStrideEnd - 1); if (value < (int)TQualifier::layoutXfbStrideEnd) - publicType.qualifier.layoutXfbStride = value; + qualifier.layoutXfbStride = value; return; } } @@ -2899,19 +7115,11 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu if (value >= (int)TQualifier::layoutAttachmentEnd) error(loc, "attachment index is too large", id.c_str(), ""); else - publicType.qualifier.layoutAttachment = value; + qualifier.layoutAttachment = value; return; } if (id == "constant_id") { - requireSpv(loc, "constant_id"); - if (value >= (int)TQualifier::layoutSpecConstantIdEnd) { - error(loc, "specialization-constant id is too large", id.c_str(), ""); - } else { - publicType.qualifier.layoutSpecConstantId = value; - publicType.qualifier.specConstant = true; - if (! intermediate.addUsedConstantId(value)) - error(loc, "specialization-constant id already used", id.c_str(), ""); - } + setSpecConstantId(loc, qualifier, value); return; } @@ -2924,7 +7132,8 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu if (value == 0) error(loc, "must be greater than 0", "vertices", ""); else - publicType.shaderQualifiers.vertices = value; + // publicType.shaderQualifiers.vertices = value; + warn(loc, "ignored", id.c_str(), ""); return; } break; @@ -2937,24 +7146,26 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu if (value == 0) error(loc, "must be at least 1", "invocations", ""); else - publicType.shaderQualifiers.invocations = value; + // publicType.shaderQualifiers.invocations = value; + warn(loc, "ignored", id.c_str(), ""); return; } if (id == "max_vertices") { - publicType.shaderQualifiers.vertices = value; + // publicType.shaderQualifiers.vertices = value; + warn(loc, "ignored", id.c_str(), ""); if (value > resources.maxGeometryOutputVertices) error(loc, "too large, must be less than gl_MaxGeometryOutputVertices", "max_vertices", ""); return; } if (id == "stream") { - publicType.qualifier.layoutStream = value; + qualifier.layoutStream = value; return; } break; case EShLangFragment: if (id == "index") { - publicType.qualifier.layoutIndex = value; + qualifier.layoutIndex = value; return; } break; @@ -2962,28 +7173,34 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu case EShLangCompute: if (id.compare(0, 11, "local_size_") == 0) { if (id == "local_size_x") { - publicType.shaderQualifiers.localSize[0] = value; + // publicType.shaderQualifiers.localSize[0] = value; + warn(loc, "ignored", id.c_str(), ""); return; } if (id == "local_size_y") { - publicType.shaderQualifiers.localSize[1] = value; + // publicType.shaderQualifiers.localSize[1] = value; + warn(loc, "ignored", id.c_str(), ""); return; } if (id == "local_size_z") { - publicType.shaderQualifiers.localSize[2] = value; + // publicType.shaderQualifiers.localSize[2] = value; + warn(loc, "ignored", id.c_str(), ""); return; } if (spvVersion.spv != 0) { if (id == "local_size_x_id") { - publicType.shaderQualifiers.localSizeSpecId[0] = value; + // publicType.shaderQualifiers.localSizeSpecId[0] = value; + warn(loc, "ignored", id.c_str(), ""); return; } if (id == "local_size_y_id") { - publicType.shaderQualifiers.localSizeSpecId[1] = value; + // publicType.shaderQualifiers.localSizeSpecId[1] = value; + warn(loc, "ignored", id.c_str(), ""); return; } if (id == "local_size_z_id") { - publicType.shaderQualifiers.localSizeSpecId[2] = value; + // publicType.shaderQualifiers.localSizeSpecId[2] = value; + warn(loc, "ignored", id.c_str(), ""); return; } } @@ -2997,20 +7214,33 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu error(loc, "there is no such layout identifier for this stage taking an assigned value", id.c_str(), ""); } +void HlslParseContext::setSpecConstantId(const TSourceLoc& loc, TQualifier& qualifier, int value) +{ + if (value >= (int)TQualifier::layoutSpecConstantIdEnd) { + error(loc, "specialization-constant id is too large", "constant_id", ""); + } else { + qualifier.layoutSpecConstantId = value; + qualifier.specConstant = true; + if (! intermediate.addUsedConstantId(value)) + error(loc, "specialization-constant id already used", "constant_id", ""); + } + return; +} + // Merge any layout qualifier information from src into dst, leaving everything else in dst alone // // "More than one layout qualifier may appear in a single declaration. -// Additionally, the same layout-qualifier-name can occur multiple times -// within a layout qualifier or across multiple layout qualifiers in the -// same declaration. When the same layout-qualifier-name occurs -// multiple times, in a single declaration, the last occurrence overrides -// the former occurrence(s). Further, if such a layout-qualifier-name -// will effect subsequent declarations or other observable behavior, it -// is only the last occurrence that will have any effect, behaving as if -// the earlier occurrence(s) within the declaration are not present. -// This is also true for overriding layout-qualifier-names, where one -// overrides the other (e.g., row_major vs. column_major); only the last -// occurrence has any effect." +// Additionally, the same layout-qualifier-name can occur multiple times +// within a layout qualifier or across multiple layout qualifiers in the +// same declaration. When the same layout-qualifier-name occurs +// multiple times, in a single declaration, the last occurrence overrides +// the former occurrence(s). Further, if such a layout-qualifier-name +// will effect subsequent declarations or other observable behavior, it +// is only the last occurrence that will have any effect, behaving as if +// the earlier occurrence(s) within the declaration are not present. +// This is also true for overriding layout-qualifier-names, where one +// overrides the other (e.g., row_major vs. column_major); only the last +// occurrence has any effect." // void HlslParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifier& src, bool inheritOnly) { @@ -3061,99 +7291,427 @@ void HlslParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQuali } } + // // Look up a function name in the symbol table, and make sure it is a function. // +// First, look for an exact match. If there is none, use the generic selector +// TParseContextBase::selectFunction() to find one, parameterized by the +// convertible() and better() predicates defined below. +// // Return the function symbol if found, otherwise nullptr. // -const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, const TFunction& call, bool& builtIn) +const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, TFunction& call, bool& builtIn, int& thisDepth, + TIntermTyped*& args) { - // const TFunction* function = nullptr; - if (symbolTable.isFunctionNameVariable(call.getName())) { error(loc, "can't use function syntax on variable", call.getName().c_str(), ""); return nullptr; } // first, look for an exact match - TSymbol* symbol = symbolTable.find(call.getMangledName(), &builtIn); + bool dummyScope; + TSymbol* symbol = symbolTable.find(call.getMangledName(), &builtIn, &dummyScope, &thisDepth); if (symbol) return symbol->getAsFunction(); - // exact match not found, look through a list of overloaded functions of the same name + // no exact match, use the generic selector, parameterized by the GLSL rules - const TFunction* candidate = nullptr; - TVector candidateList; + // create list of candidates to send + TVector candidateList; symbolTable.findFunctionNameList(call.getMangledName(), candidateList, builtIn); - for (TVector::const_iterator it = candidateList.begin(); it != candidateList.end(); ++it) { - const TFunction& function = *(*it); + // These built-in ops can accept any type, so we bypass the argument selection + if (candidateList.size() == 1 && builtIn && + (candidateList[0]->getBuiltInOp() == EOpMethodAppend || + candidateList[0]->getBuiltInOp() == EOpMethodRestartStrip || + candidateList[0]->getBuiltInOp() == EOpMethodIncrementCounter || + candidateList[0]->getBuiltInOp() == EOpMethodDecrementCounter || + candidateList[0]->getBuiltInOp() == EOpMethodAppend || + candidateList[0]->getBuiltInOp() == EOpMethodConsume)) { + return candidateList[0]; + } - // to even be a potential match, number of arguments has to match - if (call.getParamCount() != function.getParamCount()) - continue; + bool allowOnlyUpConversions = true; - bool possibleMatch = true; - for (int i = 0; i < function.getParamCount(); ++i) { - // same types is easy - if (*function[i].type == *call[i].type) - continue; + // can 'from' convert to 'to'? + const auto convertible = [&](const TType& from, const TType& to, TOperator op, int arg) -> bool { + if (from == to) + return true; - // We have a mismatch in type, see if it is implicitly convertible + // no aggregate conversions + if (from.isArray() || to.isArray() || + from.isStruct() || to.isStruct()) + return false; - if (function[i].type->isArray() || call[i].type->isArray() || - ! function[i].type->sameElementShape(*call[i].type)) - possibleMatch = false; - else { - // do direction-specific checks for conversion of basic type - if (function[i].type->getQualifier().isParamInput()) { - if (! intermediate.canImplicitlyPromote(call[i].type->getBasicType(), function[i].type->getBasicType())) - possibleMatch = false; - } - if (function[i].type->getQualifier().isParamOutput()) { - if (! intermediate.canImplicitlyPromote(function[i].type->getBasicType(), call[i].type->getBasicType())) - possibleMatch = false; - } - } - if (! possibleMatch) - break; + switch (op) { + case EOpInterlockedAdd: + case EOpInterlockedAnd: + case EOpInterlockedCompareExchange: + case EOpInterlockedCompareStore: + case EOpInterlockedExchange: + case EOpInterlockedMax: + case EOpInterlockedMin: + case EOpInterlockedOr: + case EOpInterlockedXor: + // We do not promote the texture or image type for these ocodes. Normally that would not + // be an issue because it's a buffer, but we haven't decomposed the opcode yet, and at this + // stage it's merely e.g, a basic integer type. + // + // Instead, we want to promote other arguments, but stay within the same family. In other + // words, InterlockedAdd(RWBuffer, ...) will always use the int flavor, never the uint flavor, + // but it is allowed to promote its other arguments. + if (arg == 0) + return false; + break; + case EOpMethodSample: + case EOpMethodSampleBias: + case EOpMethodSampleCmp: + case EOpMethodSampleCmpLevelZero: + case EOpMethodSampleGrad: + case EOpMethodSampleLevel: + case EOpMethodLoad: + case EOpMethodGetDimensions: + case EOpMethodGetSamplePosition: + case EOpMethodGather: + case EOpMethodCalculateLevelOfDetail: + case EOpMethodCalculateLevelOfDetailUnclamped: + case EOpMethodGatherRed: + case EOpMethodGatherGreen: + case EOpMethodGatherBlue: + case EOpMethodGatherAlpha: + case EOpMethodGatherCmp: + case EOpMethodGatherCmpRed: + case EOpMethodGatherCmpGreen: + case EOpMethodGatherCmpBlue: + case EOpMethodGatherCmpAlpha: + case EOpMethodAppend: + case EOpMethodRestartStrip: + // those are method calls, the object type can not be changed + // they are equal if the dim and type match (is dim sufficient?) + if (arg == 0) + return from.getSampler().type == to.getSampler().type && + from.getSampler().arrayed == to.getSampler().arrayed && + from.getSampler().shadow == to.getSampler().shadow && + from.getSampler().ms == to.getSampler().ms && + from.getSampler().dim == to.getSampler().dim; + break; + default: + break; } - if (possibleMatch) { - if (candidate) { - // our second match, meaning ambiguity - error(loc, "ambiguous function signature match: multiple signatures match under implicit type conversion", call.getName().c_str(), ""); - } else - candidate = &function; + + // basic types have to be convertible + if (allowOnlyUpConversions) + if (! intermediate.canImplicitlyPromote(from.getBasicType(), to.getBasicType(), EOpFunctionCall)) + return false; + + // shapes have to be convertible + if ((from.isScalarOrVec1() && to.isScalarOrVec1()) || + (from.isScalarOrVec1() && to.isVector()) || + (from.isScalarOrVec1() && to.isMatrix()) || + (from.isVector() && to.isVector() && from.getVectorSize() >= to.getVectorSize())) + return true; + + // TODO: what are the matrix rules? they go here + + return false; + }; + + // Is 'to2' a better conversion than 'to1'? + // Ties should not be considered as better. + // Assumes 'convertible' already said true. + const auto better = [](const TType& from, const TType& to1, const TType& to2) -> bool { + // exact match is always better than mismatch + if (from == to2) + return from != to1; + if (from == to1) + return false; + + // shape changes are always worse + if (from.isScalar() || from.isVector()) { + if (from.getVectorSize() == to2.getVectorSize() && + from.getVectorSize() != to1.getVectorSize()) + return true; + if (from.getVectorSize() == to1.getVectorSize() && + from.getVectorSize() != to2.getVectorSize()) + return false; + } + + // Handle sampler betterness: An exact sampler match beats a non-exact match. + // (If we just looked at basic type, all EbtSamplers would look the same). + // If any type is not a sampler, just use the linearize function below. + if (from.getBasicType() == EbtSampler && to1.getBasicType() == EbtSampler && to2.getBasicType() == EbtSampler) { + // We can ignore the vector size in the comparison. + TSampler to1Sampler = to1.getSampler(); + TSampler to2Sampler = to2.getSampler(); + + to1Sampler.vectorSize = to2Sampler.vectorSize = from.getSampler().vectorSize; + + if (from.getSampler() == to2Sampler) + return from.getSampler() != to1Sampler; + if (from.getSampler() == to1Sampler) + return false; + } + + // Might or might not be changing shape, which means basic type might + // or might not match, so within that, the question is how big a + // basic-type conversion is being done. + // + // Use a hierarchy of domains, translated to order of magnitude + // in a linearized view: + // - floating-point vs. integer + // - 32 vs. 64 bit (or width in general) + // - bool vs. non bool + // - signed vs. not signed + const auto linearize = [](const TBasicType& basicType) -> int { + switch (basicType) { + case EbtBool: return 1; + case EbtInt: return 10; + case EbtUint: return 11; + case EbtInt64: return 20; + case EbtUint64: return 21; + case EbtFloat: return 100; + case EbtDouble: return 110; + default: return 0; + } + }; + + return abs(linearize(to2.getBasicType()) - linearize(from.getBasicType())) < + abs(linearize(to1.getBasicType()) - linearize(from.getBasicType())); + }; + + // for ambiguity reporting + bool tie = false; + + // send to the generic selector + const TFunction* bestMatch = selectFunction(candidateList, call, convertible, better, tie); + + if (bestMatch == nullptr) { + // If there is nothing selected by allowing only up-conversions (to a larger linearize() value), + // we instead try down-conversions, which are valid in HLSL, but not preferred if there are any + // upconversions possible. + allowOnlyUpConversions = false; + bestMatch = selectFunction(candidateList, call, convertible, better, tie); + } + + if (bestMatch == nullptr) { + error(loc, "no matching overloaded function found", call.getName().c_str(), ""); + return nullptr; + } + + // For built-ins, we can convert across the arguments. This will happen in several steps: + // Step 1: If there's an exact match, use it. + // Step 2a: Otherwise, get the operator from the best match and promote arguments: + // Step 2b: reconstruct the TFunction based on the new arg types + // Step 3: Re-select after type promotion is applied, to find proper candidate. + if (builtIn) { + // Step 1: If there's an exact match, use it. + if (call.getMangledName() == bestMatch->getMangledName()) + return bestMatch; + + // Step 2a: Otherwise, get the operator from the best match and promote arguments as if we + // are that kind of operator. + if (args != nullptr) { + // The arg list can be a unary node, or an aggregate. We have to handle both. + // We will use the normal promote() facilities, which require an interm node. + TIntermOperator* promote = nullptr; + + if (call.getParamCount() == 1) { + promote = new TIntermUnary(bestMatch->getBuiltInOp()); + promote->getAsUnaryNode()->setOperand(args->getAsTyped()); + } else { + promote = new TIntermAggregate(bestMatch->getBuiltInOp()); + promote->getAsAggregate()->getSequence().swap(args->getAsAggregate()->getSequence()); + } + + if (! intermediate.promote(promote)) + return nullptr; + + // Obtain the promoted arg list. + if (call.getParamCount() == 1) { + args = promote->getAsUnaryNode()->getOperand(); + } else { + promote->getAsAggregate()->getSequence().swap(args->getAsAggregate()->getSequence()); + } + } + + // Step 2b: reconstruct the TFunction based on the new arg types + TFunction convertedCall(&call.getName(), call.getType(), call.getBuiltInOp()); + + if (args->getAsAggregate()) { + // Handle aggregates: put all args into the new function call + for (int arg=0; arggetAsAggregate()->getSequence().size()); ++arg) { + // TODO: But for constness, we could avoid the new & shallowCopy, and use the pointer directly. + TParameter param = { 0, new TType, nullptr }; + param.type->shallowCopy(args->getAsAggregate()->getSequence()[arg]->getAsTyped()->getType()); + convertedCall.addParameter(param); + } + } else if (args->getAsUnaryNode()) { + // Handle unaries: put all args into the new function call + TParameter param = { 0, new TType, nullptr }; + param.type->shallowCopy(args->getAsUnaryNode()->getOperand()->getAsTyped()->getType()); + convertedCall.addParameter(param); + } else if (args->getAsTyped()) { + // Handle bare e.g, floats, not in an aggregate. + TParameter param = { 0, new TType, nullptr }; + param.type->shallowCopy(args->getAsTyped()->getType()); + convertedCall.addParameter(param); + } else { + assert(0); // unknown argument list. + return nullptr; + } + + // Step 3: Re-select after type promotion, to find proper candidate + // send to the generic selector + bestMatch = selectFunction(candidateList, convertedCall, convertible, better, tie); + + // At this point, there should be no tie. + } + + if (tie) + error(loc, "ambiguous best function under implicit type conversion", call.getName().c_str(), ""); + + // Append default parameter values if needed + if (!tie && bestMatch != nullptr) { + for (int defParam = call.getParamCount(); defParam < bestMatch->getParamCount(); ++defParam) { + handleFunctionArgument(&call, args, (*bestMatch)[defParam].defaultValue); } } - if (candidate == nullptr) - error(loc, "no matching overloaded function found", call.getName().c_str(), ""); - - return candidate; + return bestMatch; } // // Do everything necessary to handle a typedef declaration, for a single symbol. -// +// // 'parseType' is the type part of the declaration (to the left) // 'arraySizes' is the arrayness tagged on the identifier (to the right) // -void HlslParseContext::declareTypedef(const TSourceLoc& loc, TString& identifier, const TType& parseType, TArraySizes* arraySizes) +void HlslParseContext::declareTypedef(const TSourceLoc& loc, const TString& identifier, const TType& parseType) { - TType type; - type.deepCopy(parseType); - - // Arrayness is potentially coming both from the type and from the - // variable: "int[] a[];" or just one or the other. - // Merge it all to the type, so all arrayness is part of the type. - arrayDimMerge(type, arraySizes); - - TVariable* typeSymbol = new TVariable(&identifier, type, true); + TVariable* typeSymbol = new TVariable(&identifier, parseType, true); if (! symbolTable.insert(*typeSymbol)) error(loc, "name already defined", "typedef", identifier.c_str()); } +// Do everything necessary to handle a struct declaration, including +// making IO aliases because HLSL allows mixed IO in a struct that specializes +// based on the usage (input, output, uniform, none). +void HlslParseContext::declareStruct(const TSourceLoc& loc, TString& structName, TType& type) +{ + // If it was named, which means the type can be reused later, add + // it to the symbol table. (Unless it's a block, in which + // case the name is not a type.) + if (type.getBasicType() == EbtBlock || structName.size() == 0) + return; + + TVariable* userTypeDef = new TVariable(&structName, type, true); + if (! symbolTable.insert(*userTypeDef)) { + error(loc, "redefinition", structName.c_str(), "struct"); + return; + } + + // See if we need IO aliases for the structure typeList + + const auto condAlloc = [](bool pred, TTypeList*& list) { + if (pred && list == nullptr) + list = new TTypeList; + }; + + tIoKinds newLists = { nullptr, nullptr, nullptr }; // allocate for each kind found + for (auto member = type.getStruct()->begin(); member != type.getStruct()->end(); ++member) { + condAlloc(hasUniform(member->type->getQualifier()), newLists.uniform); + condAlloc( hasInput(member->type->getQualifier()), newLists.input); + condAlloc( hasOutput(member->type->getQualifier()), newLists.output); + + if (member->type->isStruct()) { + auto it = ioTypeMap.find(member->type->getStruct()); + if (it != ioTypeMap.end()) { + condAlloc(it->second.uniform != nullptr, newLists.uniform); + condAlloc(it->second.input != nullptr, newLists.input); + condAlloc(it->second.output != nullptr, newLists.output); + } + } + } + if (newLists.uniform == nullptr && + newLists.input == nullptr && + newLists.output == nullptr) { + // Won't do any IO caching, clear up the type and get out now. + for (auto member = type.getStruct()->begin(); member != type.getStruct()->end(); ++member) + clearUniformInputOutput(member->type->getQualifier()); + return; + } + + // We have IO involved. + + // Make a pure typeList for the symbol table, and cache side copies of IO versions. + for (auto member = type.getStruct()->begin(); member != type.getStruct()->end(); ++member) { + const auto inheritStruct = [&](TTypeList* s, TTypeLoc& ioMember) { + if (s != nullptr) { + ioMember.type = new TType; + ioMember.type->shallowCopy(*member->type); + ioMember.type->setStruct(s); + } + }; + const auto newMember = [&](TTypeLoc& m) { + if (m.type == nullptr) { + m.type = new TType; + m.type->shallowCopy(*member->type); + } + }; + + TTypeLoc newUniformMember = { nullptr, member->loc }; + TTypeLoc newInputMember = { nullptr, member->loc }; + TTypeLoc newOutputMember = { nullptr, member->loc }; + if (member->type->isStruct()) { + // swap in an IO child if there is one + auto it = ioTypeMap.find(member->type->getStruct()); + if (it != ioTypeMap.end()) { + inheritStruct(it->second.uniform, newUniformMember); + inheritStruct(it->second.input, newInputMember); + inheritStruct(it->second.output, newOutputMember); + } + } + if (newLists.uniform) { + newMember(newUniformMember); + + // inherit default matrix layout (changeable via #pragma pack_matrix), if none given. + if (member->type->isMatrix() && member->type->getQualifier().layoutMatrix == ElmNone) + newUniformMember.type->getQualifier().layoutMatrix = globalUniformDefaults.layoutMatrix; + + correctUniform(newUniformMember.type->getQualifier()); + newLists.uniform->push_back(newUniformMember); + } + if (newLists.input) { + newMember(newInputMember); + correctInput(newInputMember.type->getQualifier()); + newLists.input->push_back(newInputMember); + } + if (newLists.output) { + newMember(newOutputMember); + correctOutput(newOutputMember.type->getQualifier()); + newLists.output->push_back(newOutputMember); + } + + // make original pure + clearUniformInputOutput(member->type->getQualifier()); + } + ioTypeMap[type.getStruct()] = newLists; +} + +// Lookup a user-type by name. +// If found, fill in the type and return the defining symbol. +// If not found, return nullptr. +TSymbol* HlslParseContext::lookupUserType(const TString& typeName, TType& type) +{ + TSymbol* symbol = symbolTable.find(typeName); + if (symbol && symbol->getAsVariable() && symbol->getAsVariable()->isUserType()) { + type.shallowCopy(symbol->getType()); + return symbol; + } else + return nullptr; +} + // // Do everything necessary to handle a variable (non-block) declaration. // Either redeclaring a variable, or making a new one, updating the symbol @@ -3165,60 +7723,85 @@ void HlslParseContext::declareTypedef(const TSourceLoc& loc, TString& identifier // 'parseType' is the type part of the declaration (to the left) // 'arraySizes' is the arrayness tagged on the identifier (to the right) // -TIntermNode* HlslParseContext::declareVariable(const TSourceLoc& loc, TString& identifier, const TType& parseType, TArraySizes* arraySizes, TIntermTyped* initializer) +TIntermNode* HlslParseContext::declareVariable(const TSourceLoc& loc, const TString& identifier, TType& type, + TIntermTyped* initializer) { - TType type; - type.shallowCopy(parseType); - if (type.isImplicitlySizedArray()) { - // Because "int[] a = int[2](...), b = int[3](...)" makes two arrays a and b - // of different sizes, for this case sharing the shallow copy of arrayness - // with the parseType oversubscribes it, so get a deep copy of the arrayness. - type.newArraySizes(*parseType.getArraySizes()); - } - if (voidErrorCheck(loc, identifier, type.getBasicType())) return nullptr; + // Global consts with initializers that are non-const act like EvqGlobal in HLSL. + // This test is implicitly recursive, because initializers propagate constness + // up the aggregate node tree during creation. E.g, for: + // { { 1, 2 }, { 3, 4 } } + // the initializer list is marked EvqConst at the top node, and remains so here. However: + // { 1, { myvar, 2 }, 3 } + // is not a const intializer, and still becomes EvqGlobal here. + + const bool nonConstInitializer = (initializer != nullptr && initializer->getQualifier().storage != EvqConst); + + if (type.getQualifier().storage == EvqConst && symbolTable.atGlobalLevel() && nonConstInitializer) { + // Force to global + type.getQualifier().storage = EvqGlobal; + } + + // make const and initialization consistent + fixConstInit(loc, identifier, type, initializer); + // Check for redeclaration of built-ins and/or attempting to declare a reserved name - bool newDeclaration = false; // true if a new entry gets added to the symbol table - TSymbol* symbol = nullptr; // = redeclareBuiltinVariable(loc, identifier, type.getQualifier(), parseType.shaderQualifiers, newDeclaration); + TSymbol* symbol = nullptr; inheritGlobalDefaults(type.getQualifier()); + const bool flattenVar = shouldFlatten(type, type.getQualifier().storage, true); + + // correct IO in the type + switch (type.getQualifier().storage) { + case EvqGlobal: + case EvqTemporary: + clearUniformInputOutput(type.getQualifier()); + break; + case EvqUniform: + case EvqBuffer: + correctUniform(type.getQualifier()); + if (type.isStruct()) { + auto it = ioTypeMap.find(type.getStruct()); + if (it != ioTypeMap.end()) + type.setStruct(it->second.uniform); + } + + break; + default: + break; + } + // Declare the variable - if (arraySizes || type.isArray()) { - // Arrayness is potentially coming both from the type and from the - // variable: "int[] a[];" or just one or the other. - // Merge it all to the type, so all arrayness is part of the type. - arrayDimMerge(type, arraySizes); - declareArray(loc, identifier, type, symbol, newDeclaration); + if (type.isArray()) { + // array case + declareArray(loc, identifier, type, symbol, !flattenVar); } else { // non-array case - if (! symbol) - symbol = declareNonArray(loc, identifier, type, newDeclaration); + if (symbol == nullptr) + symbol = declareNonArray(loc, identifier, type, !flattenVar); else if (type != symbol->getType()) error(loc, "cannot change the type of", "redeclaration", symbol->getName().c_str()); } - if (! symbol) + if (symbol == nullptr) + return nullptr; + + if (flattenVar) + flatten(*symbol->getAsVariable(), symbolTable.atGlobalLevel()); + + if (initializer == nullptr) return nullptr; // Deal with initializer - TIntermNode* initNode = nullptr; - if (symbol && initializer) { - TVariable* variable = symbol->getAsVariable(); - if (! variable) { - error(loc, "initializer requires a variable, not a member", identifier.c_str(), ""); - return nullptr; - } - initNode = executeInitializer(loc, initializer, variable); + TVariable* variable = symbol->getAsVariable(); + if (variable == nullptr) { + error(loc, "initializer requires a variable, not a member", identifier.c_str(), ""); + return nullptr; } - - // see if it's a linker-level object to track - if (newDeclaration && symbolTable.atGlobalLevel()) - intermediate.addSymbolLinkageNode(linkage, *symbol); - - return initNode; + return executeInitializer(loc, initializer, variable); } // Pick up global defaults from the provide global defaults into dst. @@ -3240,32 +7823,44 @@ void HlslParseContext::inheritGlobalDefaults(TQualifier& dst) const // TVariable* HlslParseContext::makeInternalVariable(const char* name, const TType& type) const { - TString* nameString = new TString(name); + TString* nameString = NewPoolTString(name); TVariable* variable = new TVariable(nameString, type); symbolTable.makeInternalVariable(*variable); return variable; } +// Make a symbol node holding a new internal temporary variable. +TIntermSymbol* HlslParseContext::makeInternalVariableNode(const TSourceLoc& loc, const char* name, + const TType& type) const +{ + TVariable* tmpVar = makeInternalVariable(name, type); + tmpVar->getWritableType().getQualifier().makeTemporary(); + + return intermediate.addSymbol(*tmpVar, loc); +} + // // Declare a non-array variable, the main point being there is no redeclaration // for resizing allowed. // // Return the successfully declared variable. // -TVariable* HlslParseContext::declareNonArray(const TSourceLoc& loc, TString& identifier, TType& type, bool& newDeclaration) +TVariable* HlslParseContext::declareNonArray(const TSourceLoc& loc, const TString& identifier, const TType& type, + bool track) { // make a new variable TVariable* variable = new TVariable(&identifier, type); // add variable to symbol table - if (! symbolTable.insert(*variable)) { - error(loc, "redefinition", variable->getName().c_str(), ""); - return nullptr; - } else { - newDeclaration = true; + if (symbolTable.insert(*variable)) { + if (track && symbolTable.atGlobalLevel()) + trackLinkage(*variable); return variable; } + + error(loc, "redefinition", variable->getName().c_str(), ""); + return nullptr; } // @@ -3287,8 +7882,17 @@ TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TInterm // constructor-style subtree, allowing the rest of the code to operate // identically for both kinds of initializers. // - initializer = convertInitializerList(loc, variable->getType(), initializer); - if (! initializer) { + // + // Type can't be deduced from the initializer list, so a skeletal type to + // follow has to be passed in. Constness and specialization-constness + // should be deduced bottom up, not dictated by the skeletal type. + // + TType skeletalType; + skeletalType.shallowCopy(variable->getType()); + skeletalType.getQualifier().makeTemporary(); + if (initializer->getAsAggregate() && initializer->getAsAggregate()->getOp() == EOpNull) + initializer = convertInitializerList(loc, skeletalType, initializer, nullptr); + if (initializer == nullptr) { // error recovery; don't leave const without constant values if (qualifier == EvqConst) variable->getWritableType().getQualifier().storage = EvqTemporary; @@ -3296,8 +7900,7 @@ TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TInterm } // Fix outer arrayness if variable is unsized, getting size from the initializer - if (initializer->getType().isExplicitlySizedArray() && - variable->getType().isImplicitlySizedArray()) + if (initializer->getType().isSizedArray() && variable->getType().isUnsizedArray()) variable->getWritableType().changeOuterArraySize(initializer->getType().getOuterArraySize()); // Inner arrayness can also get set by an initializer @@ -3306,8 +7909,10 @@ TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TInterm variable->getType().getArraySizes()->getNumDims()) { // adopt unsized sizes from the initializer's sizes for (int d = 1; d < variable->getType().getArraySizes()->getNumDims(); ++d) { - if (variable->getType().getArraySizes()->getDimSize(d) == UnsizedArraySize) - variable->getWritableType().getArraySizes().setDimSize(d, initializer->getType().getArraySizes()->getDimSize(d)); + if (variable->getType().getArraySizes()->getDimSize(d) == UnsizedArraySize) { + variable->getWritableType().getArraySizes()->setDimSize(d, + initializer->getType().getArraySizes()->getDimSize(d)); + } } } @@ -3317,13 +7922,8 @@ TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TInterm variable->getWritableType().getQualifier().storage = EvqTemporary; return nullptr; } - if (qualifier == EvqConst && symbolTable.atGlobalLevel() && initializer->getType().getQualifier().storage != EvqConst) { - error(loc, "global const initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str()); - variable->getWritableType().getQualifier().storage = EvqTemporary; - return nullptr; - } - // Const variables require a constant initializer, depending on version + // Const variables require a constant initializer if (qualifier == EvqConst) { if (initializer->getType().getQualifier().storage != EvqConst) { variable->getWritableType().getQualifier().storage = EvqConstReadOnly; @@ -3335,7 +7935,10 @@ TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TInterm // Compile-time tagging of the variable with its constant value... initializer = intermediate.addConversion(EOpAssign, variable->getType(), initializer); - if (! initializer || ! initializer->getAsConstantUnion() || variable->getType() != initializer->getType()) { + if (initializer != nullptr && variable->getType() != initializer->getType()) + initializer = intermediate.addUniShapeConversion(EOpAssign, variable->getType(), initializer); + if (initializer == nullptr || !initializer->getAsConstantUnion() || + variable->getType() != initializer->getType()) { error(loc, "non-matching or non-convertible constant type for const initializer", variable->getType().getStorageQualifierString(), ""); variable->getWritableType().getQualifier().storage = EvqTemporary; @@ -3347,10 +7950,9 @@ TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TInterm // normal assigning of a value to a variable... specializationCheck(loc, initializer->getType(), "initializer"); TIntermSymbol* intermSymbol = intermediate.addSymbol(*variable, loc); - TIntermNode* initNode = intermediate.addAssign(EOpAssign, intermSymbol, initializer, loc); - if (! initNode) + TIntermNode* initNode = handleAssign(loc, EOpAssign, intermSymbol, initializer); + if (initNode == nullptr) assignError(loc, "=", intermSymbol->getCompleteString(), initializer->getCompleteString()); - return initNode; } @@ -3364,7 +7966,13 @@ TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TInterm // creating a constructor-style initializer, ensuring we get the // same form. // -TIntermTyped* HlslParseContext::convertInitializerList(const TSourceLoc& loc, const TType& type, TIntermTyped* initializer) +// Returns a node representing an expression for the initializer list expressed +// as the correct type. +// +// Returns nullptr if there is an error. +// +TIntermTyped* HlslParseContext::convertInitializerList(const TSourceLoc& loc, const TType& type, + TIntermTyped* initializer, TIntermTyped* scalarInit) { // Will operate recursively. Once a subtree is found that is constructor style, // everything below it is already good: Only the "top part" of the initializer @@ -3372,8 +7980,15 @@ TIntermTyped* HlslParseContext::convertInitializerList(const TSourceLoc& loc, co // see if we have bottomed out in the tree within the initializer-list part TIntermAggregate* initList = initializer->getAsAggregate(); - if (! initList || initList->getOp() != EOpNull) - return initializer; + if (initList == nullptr || initList->getOp() != EOpNull) { + // We don't have a list, but if it's a scalar and the 'type' is a + // composite, we need to lengthen below to make it useful. + // Otherwise, this is an already formed object to initialize with. + if (type.isScalar() || !initializer->getType().isScalar()) + return initializer; + else + initList = intermediate.makeAggregate(initializer); + } // Of the initializer-list set of nodes, need to process bottom up, // so recurse deep, then process on the way up. @@ -3384,51 +7999,96 @@ TIntermTyped* HlslParseContext::convertInitializerList(const TSourceLoc& loc, co // Later on, initializer execution code will deal with array size logic. TType arrayType; arrayType.shallowCopy(type); // sharing struct stuff is fine - arrayType.newArraySizes(*type.getArraySizes()); // but get a fresh copy of the array information, to edit below + arrayType.copyArraySizes(*type.getArraySizes()); // but get a fresh copy of the array information, to edit below // edit array sizes to fill in unsized dimensions - arrayType.changeOuterArraySize((int)initList->getSequence().size()); - TIntermTyped* firstInit = initList->getSequence()[0]->getAsTyped(); - if (arrayType.isArrayOfArrays() && firstInit->getType().isArray() && - arrayType.getArraySizes().getNumDims() == firstInit->getType().getArraySizes()->getNumDims() + 1) { - for (int d = 1; d < arrayType.getArraySizes().getNumDims(); ++d) { - if (arrayType.getArraySizes().getDimSize(d) == UnsizedArraySize) - arrayType.getArraySizes().setDimSize(d, firstInit->getType().getArraySizes()->getDimSize(d - 1)); + if (type.isUnsizedArray()) + arrayType.changeOuterArraySize((int)initList->getSequence().size()); + + // set unsized array dimensions that can be derived from the initializer's first element + if (arrayType.isArrayOfArrays() && initList->getSequence().size() > 0) { + TIntermTyped* firstInit = initList->getSequence()[0]->getAsTyped(); + if (firstInit->getType().isArray() && + arrayType.getArraySizes()->getNumDims() == firstInit->getType().getArraySizes()->getNumDims() + 1) { + for (int d = 1; d < arrayType.getArraySizes()->getNumDims(); ++d) { + if (arrayType.getArraySizes()->getDimSize(d) == UnsizedArraySize) + arrayType.getArraySizes()->setDimSize(d, firstInit->getType().getArraySizes()->getDimSize(d - 1)); + } } } + // lengthen list to be long enough + lengthenList(loc, initList->getSequence(), arrayType.getOuterArraySize(), scalarInit); + + // recursively process each element TType elementType(arrayType, 0); // dereferenced type - for (size_t i = 0; i < initList->getSequence().size(); ++i) { - initList->getSequence()[i] = convertInitializerList(loc, elementType, initList->getSequence()[i]->getAsTyped()); + for (int i = 0; i < arrayType.getOuterArraySize(); ++i) { + initList->getSequence()[i] = convertInitializerList(loc, elementType, + initList->getSequence()[i]->getAsTyped(), scalarInit); if (initList->getSequence()[i] == nullptr) return nullptr; } - return addConstructor(loc, initList, arrayType, mapTypeToConstructorOp(arrayType)); + return addConstructor(loc, initList, arrayType); } else if (type.isStruct()) { + // do we have implicit assignments to opaques? + for (size_t i = initList->getSequence().size(); i < type.getStruct()->size(); ++i) { + if ((*type.getStruct())[i].type->containsOpaque()) { + error(loc, "cannot implicitly initialize opaque members", "initializer list", ""); + return nullptr; + } + } + + // lengthen list to be long enough + lengthenList(loc, initList->getSequence(), static_cast(type.getStruct()->size()), scalarInit); + if (type.getStruct()->size() != initList->getSequence().size()) { error(loc, "wrong number of structure members", "initializer list", ""); return nullptr; } for (size_t i = 0; i < type.getStruct()->size(); ++i) { - initList->getSequence()[i] = convertInitializerList(loc, *(*type.getStruct())[i].type, initList->getSequence()[i]->getAsTyped()); + initList->getSequence()[i] = convertInitializerList(loc, *(*type.getStruct())[i].type, + initList->getSequence()[i]->getAsTyped(), scalarInit); if (initList->getSequence()[i] == nullptr) return nullptr; } } else if (type.isMatrix()) { - if (type.getMatrixCols() != (int)initList->getSequence().size()) { - error(loc, "wrong number of matrix columns:", "initializer list", type.getCompleteString().c_str()); - return nullptr; - } - TType vectorType(type, 0); // dereferenced type - for (int i = 0; i < type.getMatrixCols(); ++i) { - initList->getSequence()[i] = convertInitializerList(loc, vectorType, initList->getSequence()[i]->getAsTyped()); - if (initList->getSequence()[i] == nullptr) + if (type.computeNumComponents() == (int)initList->getSequence().size()) { + // This means the matrix is initialized component-wise, rather than as + // a series of rows and columns. We can just use the list directly as + // a constructor; no further processing needed. + } else { + // lengthen list to be long enough + lengthenList(loc, initList->getSequence(), type.getMatrixCols(), scalarInit); + + if (type.getMatrixCols() != (int)initList->getSequence().size()) { + error(loc, "wrong number of matrix columns:", "initializer list", type.getCompleteString().c_str()); return nullptr; + } + TType vectorType(type, 0); // dereferenced type + for (int i = 0; i < type.getMatrixCols(); ++i) { + initList->getSequence()[i] = convertInitializerList(loc, vectorType, + initList->getSequence()[i]->getAsTyped(), scalarInit); + if (initList->getSequence()[i] == nullptr) + return nullptr; + } } } else if (type.isVector()) { + // lengthen list to be long enough + lengthenList(loc, initList->getSequence(), type.getVectorSize(), scalarInit); + + // error check; we're at bottom, so work is finished below if (type.getVectorSize() != (int)initList->getSequence().size()) { - error(loc, "wrong vector size (or rows in a matrix column):", "initializer list", type.getCompleteString().c_str()); + error(loc, "wrong vector size (or rows in a matrix column):", "initializer list", + type.getCompleteString().c_str()); + return nullptr; + } + } else if (type.isScalar()) { + // lengthen list to be long enough + lengthenList(loc, initList->getSequence(), 1, scalarInit); + + if ((int)initList->getSequence().size() != 1) { + error(loc, "scalar expected one element:", "initializer list", type.getCompleteString().c_str()); return nullptr; } } else { @@ -3436,8 +8096,35 @@ TIntermTyped* HlslParseContext::convertInitializerList(const TSourceLoc& loc, co return nullptr; } - // now that the subtree is processed, process this node - return addConstructor(loc, initList, type, mapTypeToConstructorOp(type)); + // Now that the subtree is processed, process this node as if the + // initializer list is a set of arguments to a constructor. + TIntermTyped* emulatedConstructorArguments; + if (initList->getSequence().size() == 1) + emulatedConstructorArguments = initList->getSequence()[0]->getAsTyped(); + else + emulatedConstructorArguments = initList; + + return addConstructor(loc, emulatedConstructorArguments, type); +} + +// Lengthen list to be long enough to cover any gap from the current list size +// to 'size'. If the list is longer, do nothing. +// The value to lengthen with is the default for short lists. +// +// By default, lists that are too short due to lack of initializers initialize to zero. +// Alternatively, it could be a scalar initializer for a structure. Both cases are handled, +// based on whether something is passed in as 'scalarInit'. +// +// 'scalarInit' must be safe to use each time this is called (no side effects replication). +// +void HlslParseContext::lengthenList(const TSourceLoc& loc, TIntermSequence& list, int size, TIntermTyped* scalarInit) +{ + for (int c = (int)list.size(); c < size; ++c) { + if (scalarInit == nullptr) + list.push_back(intermediate.addConstantUnion(0, loc)); + else + list.push_back(scalarInit); + } } // @@ -3446,12 +8133,48 @@ TIntermTyped* HlslParseContext::convertInitializerList(const TSourceLoc& loc, co // // Returns nullptr for an error or the constructed node (aggregate or typed) for no error. // -TIntermTyped* HlslParseContext::addConstructor(const TSourceLoc& loc, TIntermNode* node, const TType& type, TOperator op) +TIntermTyped* HlslParseContext::handleConstructor(const TSourceLoc& loc, TIntermTyped* node, const TType& type) { - if (node == nullptr || node->getAsTyped() == nullptr) + if (node == nullptr) return nullptr; + // Construct identical type + if (type == node->getType()) + return node; + + // Handle the idiom "(struct type)" + if (type.isStruct() && isScalarConstructor(node)) { + // 'node' will almost always get used multiple times, so should not be used directly, + // it would create a DAG instead of a tree, which might be okay (would + // like to formalize that for constants and symbols), but if it has + // side effects, they would get executed multiple times, which is not okay. + if (node->getAsConstantUnion() == nullptr && node->getAsSymbolNode() == nullptr) { + TIntermAggregate* seq = intermediate.makeAggregate(loc); + TIntermSymbol* copy = makeInternalVariableNode(loc, "scalarCopy", node->getType()); + seq = intermediate.growAggregate(seq, intermediate.addBinaryNode(EOpAssign, copy, node, loc)); + seq = intermediate.growAggregate(seq, convertInitializerList(loc, type, intermediate.makeAggregate(loc), copy)); + seq->setOp(EOpComma); + seq->setType(type); + return seq; + } else + return convertInitializerList(loc, type, intermediate.makeAggregate(loc), node); + } + + return addConstructor(loc, node, type); +} + +// Add a constructor, either from the grammar, or other programmatic reasons. +// +// 'node' is what to construct from. +// 'type' is what type to construct. +// +// Returns the constructed object. +// Return nullptr if it can't be done. +// +TIntermTyped* HlslParseContext::addConstructor(const TSourceLoc& loc, TIntermTyped* node, const TType& type) +{ TIntermAggregate* aggrNode = node->getAsAggregate(); + TOperator op = intermediate.mapTypeToConstructorOp(type); // Combined texture-sampler constructors are completely semantic checked // in constructorTextureSamplerError() @@ -3470,8 +8193,8 @@ TIntermTyped* HlslParseContext::addConstructor(const TSourceLoc& loc, TIntermNod elementType.shallowCopy(type); bool singleArg; - if (aggrNode) { - if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1) + if (aggrNode != nullptr) { + if (aggrNode->getOp() != EOpNull) singleArg = true; else singleArg = false; @@ -3480,14 +8203,27 @@ TIntermTyped* HlslParseContext::addConstructor(const TSourceLoc& loc, TIntermNod TIntermTyped *newNode; if (singleArg) { + // Handle array -> array conversion + // Constructing an array of one type from an array of another type is allowed, + // assuming there are enough components available (semantic-checked earlier). + if (type.isArray() && node->isArray()) + newNode = convertArray(node, type); + // If structure constructor or array constructor is being called - // for only one parameter inside the structure, we need to call constructAggregate function once. - if (type.isArray()) + // for only one parameter inside the aggregate, we need to call constructAggregate function once. + else if (type.isArray()) newNode = constructAggregate(node, elementType, 1, node->getLoc()); else if (op == EOpConstructStruct) newNode = constructAggregate(node, *(*memberTypes).type, 1, node->getLoc()); - else - newNode = constructBuiltIn(type, op, node->getAsTyped(), node->getLoc(), false); + else { + // shape conversion for matrix constructor from scalar. HLSL semantics are: scalar + // is replicated into every element of the matrix (not just the diagnonal), so + // that is handled specially here. + if (type.isMatrix() && node->getType().isScalarOrVec1()) + node = intermediate.addShapeConversion(type, node); + + newNode = constructBuiltIn(type, op, node, node->getLoc(), false); + } if (newNode && (type.isArray() || op == EOpConstructStruct)) newNode = intermediate.setAggregateOperator(newNode, EOpConstructStruct, type, loc); @@ -3498,7 +8234,7 @@ TIntermTyped* HlslParseContext::addConstructor(const TSourceLoc& loc, TIntermNod // // Handle list of arguments. // - TIntermSequence &sequenceVector = aggrNode->getSequence(); // Stores the information about the parameter to the constructor + TIntermSequence& sequenceVector = aggrNode->getSequence(); // Stores the information about the parameter to the constructor // if the structure constructor contains more than one parameter, then construct // each parameter @@ -3535,7 +8271,8 @@ TIntermTyped* HlslParseContext::addConstructor(const TSourceLoc& loc, TIntermNod // // Returns nullptr for an error or the constructed node. // -TIntermTyped* HlslParseContext::constructBuiltIn(const TType& type, TOperator op, TIntermTyped* node, const TSourceLoc& loc, bool subset) +TIntermTyped* HlslParseContext::constructBuiltIn(const TType& type, TOperator op, TIntermTyped* node, + const TSourceLoc& loc, bool subset) { TIntermTyped* newNode; TOperator basicOp; @@ -3544,6 +8281,22 @@ TIntermTyped* HlslParseContext::constructBuiltIn(const TType& type, TOperator op // First, convert types as needed. // switch (op) { + case EOpConstructF16Vec2: + case EOpConstructF16Vec3: + case EOpConstructF16Vec4: + case EOpConstructF16Mat2x2: + case EOpConstructF16Mat2x3: + case EOpConstructF16Mat2x4: + case EOpConstructF16Mat3x2: + case EOpConstructF16Mat3x3: + case EOpConstructF16Mat3x4: + case EOpConstructF16Mat4x2: + case EOpConstructF16Mat4x3: + case EOpConstructF16Mat4x4: + case EOpConstructFloat16: + basicOp = EOpConstructFloat16; + break; + case EOpConstructVec2: case EOpConstructVec3: case EOpConstructVec4: @@ -3576,16 +8329,48 @@ TIntermTyped* HlslParseContext::constructBuiltIn(const TType& type, TOperator op basicOp = EOpConstructDouble; break; + case EOpConstructI16Vec2: + case EOpConstructI16Vec3: + case EOpConstructI16Vec4: + case EOpConstructInt16: + basicOp = EOpConstructInt16; + break; + case EOpConstructIVec2: case EOpConstructIVec3: case EOpConstructIVec4: + case EOpConstructIMat2x2: + case EOpConstructIMat2x3: + case EOpConstructIMat2x4: + case EOpConstructIMat3x2: + case EOpConstructIMat3x3: + case EOpConstructIMat3x4: + case EOpConstructIMat4x2: + case EOpConstructIMat4x3: + case EOpConstructIMat4x4: case EOpConstructInt: basicOp = EOpConstructInt; break; + case EOpConstructU16Vec2: + case EOpConstructU16Vec3: + case EOpConstructU16Vec4: + case EOpConstructUint16: + basicOp = EOpConstructUint16; + break; + case EOpConstructUVec2: case EOpConstructUVec3: case EOpConstructUVec4: + case EOpConstructUMat2x2: + case EOpConstructUMat2x3: + case EOpConstructUMat2x4: + case EOpConstructUMat3x2: + case EOpConstructUMat3x3: + case EOpConstructUMat3x4: + case EOpConstructUMat4x2: + case EOpConstructUMat4x3: + case EOpConstructUMat4x4: case EOpConstructUint: basicOp = EOpConstructUint; break; @@ -3593,6 +8378,15 @@ TIntermTyped* HlslParseContext::constructBuiltIn(const TType& type, TOperator op case EOpConstructBVec2: case EOpConstructBVec3: case EOpConstructBVec4: + case EOpConstructBMat2x2: + case EOpConstructBMat2x3: + case EOpConstructBMat2x4: + case EOpConstructBMat3x2: + case EOpConstructBMat3x3: + case EOpConstructBMat3x4: + case EOpConstructBMat4x2: + case EOpConstructBMat4x3: + case EOpConstructBMat4x4: case EOpConstructBool: basicOp = EOpConstructBool; break; @@ -3620,15 +8414,88 @@ TIntermTyped* HlslParseContext::constructBuiltIn(const TType& type, TOperator op return intermediate.setAggregateOperator(newNode, op, type, loc); } +// Convert the array in node to the requested type, which is also an array. +// Returns nullptr on failure, otherwise returns aggregate holding the list of +// elements needed to construct the array. +TIntermTyped* HlslParseContext::convertArray(TIntermTyped* node, const TType& type) +{ + assert(node->isArray() && type.isArray()); + if (node->getType().computeNumComponents() < type.computeNumComponents()) + return nullptr; + + // TODO: write an argument replicator, for the case the argument should not be + // executed multiple times, yet multiple copies are needed. + + TIntermTyped* constructee = node->getAsTyped(); + // track where we are in consuming the argument + int constructeeElement = 0; + int constructeeComponent = 0; + + // bump up to the next component to consume + const auto getNextComponent = [&]() { + TIntermTyped* component; + component = handleBracketDereference(node->getLoc(), constructee, + intermediate.addConstantUnion(constructeeElement, node->getLoc())); + if (component->isVector()) + component = handleBracketDereference(node->getLoc(), component, + intermediate.addConstantUnion(constructeeComponent, node->getLoc())); + // bump component pointer up + ++constructeeComponent; + if (constructeeComponent == constructee->getVectorSize()) { + constructeeComponent = 0; + ++constructeeElement; + } + return component; + }; + + // make one subnode per constructed array element + TIntermAggregate* constructor = nullptr; + TType derefType(type, 0); + TType speculativeComponentType(derefType, 0); + TType* componentType = derefType.isVector() ? &speculativeComponentType : &derefType; + TOperator componentOp = intermediate.mapTypeToConstructorOp(*componentType); + TType crossType(node->getBasicType(), EvqTemporary, type.getVectorSize()); + for (int e = 0; e < type.getOuterArraySize(); ++e) { + // construct an element + TIntermTyped* elementArg; + if (type.getVectorSize() == constructee->getVectorSize()) { + // same element shape + elementArg = handleBracketDereference(node->getLoc(), constructee, + intermediate.addConstantUnion(e, node->getLoc())); + } else { + // mismatched element shapes + if (type.getVectorSize() == 1) + elementArg = getNextComponent(); + else { + // make a vector + TIntermAggregate* elementConstructee = nullptr; + for (int c = 0; c < type.getVectorSize(); ++c) + elementConstructee = intermediate.growAggregate(elementConstructee, getNextComponent()); + elementArg = addConstructor(node->getLoc(), elementConstructee, crossType); + } + } + // convert basic types + elementArg = intermediate.addConversion(componentOp, derefType, elementArg); + if (elementArg == nullptr) + return nullptr; + // combine with top-level constructor + constructor = intermediate.growAggregate(constructor, elementArg); + } + + return constructor; +} + // This function tests for the type of the parameters to the structure or array constructor. Raises // an error message if the expected type does not match the parameter passed to the constructor. // // Returns nullptr for an error or the input node itself if the expected and the given parameter types match. // -TIntermTyped* HlslParseContext::constructAggregate(TIntermNode* node, const TType& type, int paramCount, const TSourceLoc& loc) +TIntermTyped* HlslParseContext::constructAggregate(TIntermNode* node, const TType& type, int paramCount, + const TSourceLoc& loc) { + // Handle cases that map more 1:1 between constructor arguments and constructed. TIntermTyped* converted = intermediate.addConversion(EOpConstructStruct, type, node->getAsTyped()); - if (! converted || converted->getType() != type) { + if (converted == nullptr || converted->getType() != type) { error(loc, "", "constructor", "cannot convert parameter %d from '%s' to '%s'", paramCount, node->getAsTyped()->getType().getCompleteString().c_str(), type.getCompleteString().c_str()); @@ -3641,28 +8508,65 @@ TIntermTyped* HlslParseContext::constructAggregate(TIntermNode* node, const TTyp // // Do everything needed to add an interface block. // -void HlslParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, const TString* instanceName, TArraySizes* arraySizes) +void HlslParseContext::declareBlock(const TSourceLoc& loc, TType& type, const TString* instanceName) { + assert(type.getWritableStruct() != nullptr); + + // Clean up top-level decorations that don't belong. + switch (type.getQualifier().storage) { + case EvqUniform: + case EvqBuffer: + correctUniform(type.getQualifier()); + break; + case EvqVaryingIn: + correctInput(type.getQualifier()); + break; + case EvqVaryingOut: + correctOutput(type.getQualifier()); + break; + default: + break; + } + + TTypeList& typeList = *type.getWritableStruct(); // fix and check for member storage qualifiers and types that don't belong within a block for (unsigned int member = 0; member < typeList.size(); ++member) { TType& memberType = *typeList[member].type; TQualifier& memberQualifier = memberType.getQualifier(); const TSourceLoc& memberLoc = typeList[member].loc; globalQualifierFix(memberLoc, memberQualifier); - memberQualifier.storage = currentBlockQualifier.storage; - } + memberQualifier.storage = type.getQualifier().storage; - // This might be a redeclaration of a built-in block. If so, redeclareBuiltinBlock() will - // do all the rest. - if (! symbolTable.atBuiltInLevel() && builtInName(*blockName)) { - redeclareBuiltinBlock(loc, typeList, *blockName, instanceName, arraySizes); - return; + if (memberType.isStruct()) { + // clean up and pick up the right set of decorations + auto it = ioTypeMap.find(memberType.getStruct()); + switch (type.getQualifier().storage) { + case EvqUniform: + case EvqBuffer: + correctUniform(type.getQualifier()); + if (it != ioTypeMap.end() && it->second.uniform) + memberType.setStruct(it->second.uniform); + break; + case EvqVaryingIn: + correctInput(type.getQualifier()); + if (it != ioTypeMap.end() && it->second.input) + memberType.setStruct(it->second.input); + break; + case EvqVaryingOut: + correctOutput(type.getQualifier()); + if (it != ioTypeMap.end() && it->second.output) + memberType.setStruct(it->second.output); + break; + default: + break; + } + } } // Make default block qualification, and adjust the member qualifications TQualifier defaultQualification; - switch (currentBlockQualifier.storage) { + switch (type.getQualifier().storage) { case EvqUniform: defaultQualification = globalUniformDefaults; break; case EvqBuffer: defaultQualification = globalBufferDefaults; break; case EvqVaryingIn: defaultQualification = globalInputDefaults; break; @@ -3672,12 +8576,12 @@ void HlslParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, // Special case for "push_constant uniform", which has a default of std430, // contrary to normal uniform defaults, and can't have a default tracked for it. - if (currentBlockQualifier.layoutPushConstant && ! currentBlockQualifier.hasPacking()) - currentBlockQualifier.layoutPacking = ElpStd430; + if (type.getQualifier().layoutPushConstant && ! type.getQualifier().hasPacking()) + type.getQualifier().layoutPacking = ElpStd430; // fix and check for member layout qualifiers - mergeObjectLayoutQualifiers(defaultQualification, currentBlockQualifier, true); + mergeObjectLayoutQualifiers(defaultQualification, type.getQualifier(), true); bool memberWithLocation = false; bool memberWithoutLocation = false; @@ -3689,19 +8593,17 @@ void HlslParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, error(memberLoc, "member cannot contradict block", "stream", ""); } - // "This includes a block's inheritance of the - // current global default buffer, a block member's inheritance of the block's - // buffer, and the requirement that any *xfb_buffer* declared on a block + // "This includes a block's inheritance of the + // current global default buffer, a block member's inheritance of the block's + // buffer, and the requirement that any *xfb_buffer* declared on a block // member must match the buffer inherited from the block." if (memberQualifier.hasXfbBuffer()) { if (defaultQualification.layoutXfbBuffer != memberQualifier.layoutXfbBuffer) error(memberLoc, "member cannot contradict block (or what block inherited from global)", "xfb_buffer", ""); } - if (memberQualifier.hasPacking()) - error(memberLoc, "member of block cannot have a packing layout qualifier", typeList[member].type->getFieldName().c_str(), ""); if (memberQualifier.hasLocation()) { - switch (currentBlockQualifier.storage) { + switch (type.getQualifier().storage) { case EvqVaryingIn: case EvqVaryingOut: memberWithLocation = true; @@ -3711,96 +8613,63 @@ void HlslParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, } } else memberWithoutLocation = true; - if (memberQualifier.hasAlign()) { - if (defaultQualification.layoutPacking != ElpStd140 && defaultQualification.layoutPacking != ElpStd430) - error(memberLoc, "can only be used with std140 or std430 layout packing", "align", ""); - } TQualifier newMemberQualification = defaultQualification; - mergeQualifiers(memberLoc, newMemberQualification, memberQualifier, false); + mergeQualifiers(newMemberQualification, memberQualifier); memberQualifier = newMemberQualification; } // Process the members - fixBlockLocations(loc, currentBlockQualifier, typeList, memberWithLocation, memberWithoutLocation); - fixBlockXfbOffsets(currentBlockQualifier, typeList); - fixBlockUniformOffsets(currentBlockQualifier, typeList); + fixBlockLocations(loc, type.getQualifier(), typeList, memberWithLocation, memberWithoutLocation); + fixBlockXfbOffsets(type.getQualifier(), typeList); + fixBlockUniformOffsets(type.getQualifier(), typeList); // reverse merge, so that currentBlockQualifier now has all layout information // (can't use defaultQualification directly, it's missing other non-layout-default-class qualifiers) - mergeObjectLayoutQualifiers(currentBlockQualifier, defaultQualification, true); + mergeObjectLayoutQualifiers(type.getQualifier(), defaultQualification, true); // // Build and add the interface block as a new type named 'blockName' // - TType blockType(&typeList, *blockName, currentBlockQualifier); - if (arraySizes) - blockType.newArraySizes(*arraySizes); + // Use the instance name as the interface name if one exists, else the block name. + const TString& interfaceName = (instanceName && !instanceName->empty()) ? *instanceName : type.getTypeName(); - // - // Don't make a user-defined type out of block name; that will cause an error - // if the same block name gets reused in a different interface. - // - // "Block names have no other use within a shader - // beyond interface matching; it is a compile-time error to use a block name at global scope for anything - // other than as a block name (e.g., use of a block name for a global variable name or function name is - // currently reserved)." - // - // Use the symbol table to prevent normal reuse of the block's name, as a variable entry, - // whose type is EbtBlock, but without all the structure; that will come from the type - // the instances point to. - // - TType blockNameType(EbtBlock, blockType.getQualifier().storage); - TVariable* blockNameVar = new TVariable(blockName, blockNameType); - if (! symbolTable.insert(*blockNameVar)) { - TSymbol* existingName = symbolTable.find(*blockName); - if (existingName->getType().getBasicType() == EbtBlock) { - if (existingName->getType().getQualifier().storage == blockType.getQualifier().storage) { - error(loc, "Cannot reuse block name within the same interface:", blockName->c_str(), blockType.getStorageQualifierString()); - return; - } - } else { - error(loc, "block name cannot redefine a non-block name", blockName->c_str(), ""); - return; - } - } + TType blockType(&typeList, interfaceName, type.getQualifier()); + if (type.isArray()) + blockType.transferArraySizes(type.getArraySizes()); // Add the variable, as anonymous or named instanceName. // Make an anonymous variable if no name was provided. - if (! instanceName) + if (instanceName == nullptr) instanceName = NewPoolTString(""); TVariable& variable = *new TVariable(instanceName, blockType); if (! symbolTable.insert(variable)) { if (*instanceName == "") - error(loc, "nameless block contains a member that already has a name at global scope", blockName->c_str(), ""); + error(loc, "nameless block contains a member that already has a name at global scope", + "" /* blockName->c_str() */, ""); else error(loc, "block instance name redefinition", variable.getName().c_str(), ""); return; } - if (isIoResizeArray(blockType)) { - ioArraySymbolResizeList.push_back(&variable); - checkIoArraysConsistency(loc, true); - } else - fixIoArraySize(loc, variable.getWritableType()); - // Save it in the AST for linker use. - intermediate.addSymbolLinkageNode(linkage, variable); + if (symbolTable.atGlobalLevel()) + trackLinkage(variable); } // -// "For a block, this process applies to the entire block, or until the first member -// is reached that has a location layout qualifier. When a block member is declared with a location +// "For a block, this process applies to the entire block, or until the first member +// is reached that has a location layout qualifier. When a block member is declared with a location // qualifier, its location comes from that qualifier: The member's location qualifier overrides the block-level -// declaration. Subsequent members are again assigned consecutive locations, based on the newest location, -// until the next member declared with a location qualifier. The values used for locations do not have to be +// declaration. Subsequent members are again assigned consecutive locations, based on the newest location, +// until the next member declared with a location qualifier. The values used for locations do not have to be // declared in increasing order." void HlslParseContext::fixBlockLocations(const TSourceLoc& loc, TQualifier& qualifier, TTypeList& typeList, bool memberWithLocation, bool memberWithoutLocation) { - // "If a block has no block-level location layout qualifier, it is required that either all or none of its members + // "If a block has no block-level location layout qualifier, it is required that either all or none of its members // have a location layout qualifier, or a compile-time error results." if (! qualifier.hasLocation() && memberWithLocation && memberWithoutLocation) error(loc, "either the block needs a location, or all members need a location, or no members have a location", "location", ""); @@ -3828,7 +8697,8 @@ void HlslParseContext::fixBlockLocations(const TSourceLoc& loc, TQualifier& qual memberQualifier.layoutLocation = nextLocation; memberQualifier.layoutComponent = 0; } - nextLocation = memberQualifier.layoutLocation + intermediate.computeTypeLocationSize(*typeList[member].type); + nextLocation = memberQualifier.layoutLocation + + intermediate.computeTypeLocationSize(*typeList[member].type, language); } } } @@ -3836,9 +8706,9 @@ void HlslParseContext::fixBlockLocations(const TSourceLoc& loc, TQualifier& qual void HlslParseContext::fixBlockXfbOffsets(TQualifier& qualifier, TTypeList& typeList) { - // "If a block is qualified with xfb_offset, all its - // members are assigned transform feedback buffer offsets. If a block is not qualified with xfb_offset, any - // members of that block not qualified with an xfb_offset will not be assigned transform feedback buffer + // "If a block is qualified with xfb_offset, all its + // members are assigned transform feedback buffer offsets. If a block is not qualified with xfb_offset, any + // members of that block not qualified with an xfb_offset will not be assigned transform feedback buffer // offsets." if (! qualifier.hasXfbBuffer() || ! qualifier.hasXfbOffset()) @@ -3865,13 +8735,13 @@ void HlslParseContext::fixBlockXfbOffsets(TQualifier& qualifier, TTypeList& type qualifier.layoutXfbOffset = TQualifier::layoutXfbOffsetEnd; } -// Calculate and save the offset of each block member, using the recursively +// Calculate and save the offset of each block member, using the recursively // defined block offset rules and the user-provided offset and align. // -// Also, compute and save the total size of the block. For the block's size, arrayness +// Also, compute and save the total size of the block. For the block's size, arrayness // is not taken into account, as each element is backed by a separate buffer. // -void HlslParseContext::fixBlockUniformOffsets(TQualifier& qualifier, TTypeList& typeList) +void HlslParseContext::fixBlockUniformOffsets(const TQualifier& qualifier, TTypeList& typeList) { if (! qualifier.isUniformOrBuffer()) return; @@ -3889,33 +8759,31 @@ void HlslParseContext::fixBlockUniformOffsets(TQualifier& qualifier, TTypeList& // modify just the children's view of matrix layout, if there is one for this member TLayoutMatrix subMatrixLayout = typeList[member].type->getQualifier().layoutMatrix; int dummyStride; - int memberAlignment = intermediate.getBaseAlignment(*typeList[member].type, memberSize, dummyStride, qualifier.layoutPacking == ElpStd140, - subMatrixLayout != ElmNone ? subMatrixLayout == ElmRowMajor : qualifier.layoutMatrix == ElmRowMajor); + int memberAlignment = intermediate.getBaseAlignment(*typeList[member].type, memberSize, dummyStride, + qualifier.layoutPacking == ElpStd140, + subMatrixLayout != ElmNone + ? subMatrixLayout == ElmRowMajor + : qualifier.layoutMatrix == ElmRowMajor); if (memberQualifier.hasOffset()) { - // "The specified offset must be a multiple + // "The specified offset must be a multiple // of the base alignment of the type of the block member it qualifies, or a compile-time error results." if (! IsMultipleOfPow2(memberQualifier.layoutOffset, memberAlignment)) error(memberLoc, "must be a multiple of the member's alignment", "offset", ""); - // "It is a compile-time error to specify an offset that is smaller than the offset of the previous - // member in the block or that lies within the previous member of the block" - if (memberQualifier.layoutOffset < offset) - error(memberLoc, "cannot lie in previous members", "offset", ""); - - // "The offset qualifier forces the qualified member to start at or after the specified - // integral-constant expression, which will be its byte offset from the beginning of the buffer. - // "The actual offset of a member is computed as + // "The offset qualifier forces the qualified member to start at or after the specified + // integral-constant expression, which will be its byte offset from the beginning of the buffer. + // "The actual offset of a member is computed as // follows: If offset was declared, start with that offset, otherwise start with the next available offset." offset = std::max(offset, memberQualifier.layoutOffset); } - // "The actual alignment of a member will be the greater of the specified align alignment and the standard + // "The actual alignment of a member will be the greater of the specified align alignment and the standard // (e.g., std140) base alignment for the member's type." if (memberQualifier.hasAlign()) memberAlignment = std::max(memberAlignment, memberQualifier.layoutAlign); // "If the resulting offset is not a multiple of the actual alignment, - // increase it to the first offset that is a multiple of + // increase it to the first offset that is a multiple of // the actual alignment." RoundToPow2(offset, memberAlignment); typeList[member].type->getQualifier().layoutOffset = offset; @@ -3927,7 +8795,7 @@ void HlslParseContext::fixBlockUniformOffsets(TQualifier& qualifier, TTypeList& void HlslParseContext::addQualifierToExisting(const TSourceLoc& loc, TQualifier qualifier, const TString& identifier) { TSymbol* symbol = symbolTable.find(identifier); - if (! symbol) { + if (symbol == nullptr) { error(loc, "identifier not previously declared", identifier.c_str(), ""); return; } @@ -3973,6 +8841,130 @@ void HlslParseContext::addQualifierToExisting(const TSourceLoc& loc, TQualifier addQualifierToExisting(loc, qualifier, *identifiers[i]); } +// +// Update the intermediate for the given input geometry +// +bool HlslParseContext::handleInputGeometry(const TSourceLoc& loc, const TLayoutGeometry& geometry) +{ + switch (geometry) { + case ElgPoints: // fall through + case ElgLines: // ... + case ElgTriangles: // ... + case ElgLinesAdjacency: // ... + case ElgTrianglesAdjacency: // ... + if (! intermediate.setInputPrimitive(geometry)) { + error(loc, "input primitive geometry redefinition", TQualifier::getGeometryString(geometry), ""); + return false; + } + break; + + default: + error(loc, "cannot apply to 'in'", TQualifier::getGeometryString(geometry), ""); + return false; + } + + return true; +} + +// +// Update the intermediate for the given output geometry +// +bool HlslParseContext::handleOutputGeometry(const TSourceLoc& loc, const TLayoutGeometry& geometry) +{ + // If this is not a geometry shader, ignore. It might be a mixed shader including several stages. + // Since that's an OK situation, return true for success. + if (language != EShLangGeometry) + return true; + + switch (geometry) { + case ElgPoints: + case ElgLineStrip: + case ElgTriangleStrip: + if (! intermediate.setOutputPrimitive(geometry)) { + error(loc, "output primitive geometry redefinition", TQualifier::getGeometryString(geometry), ""); + return false; + } + break; + default: + error(loc, "cannot apply to 'out'", TQualifier::getGeometryString(geometry), ""); + return false; + } + + return true; +} + +// +// Selection attributes +// +void HlslParseContext::handleSelectionAttributes(const TSourceLoc& loc, TIntermSelection* selection, + const TAttributes& attributes) +{ + if (selection == nullptr) + return; + + for (auto it = attributes.begin(); it != attributes.end(); ++it) { + switch (it->name) { + case EatFlatten: + selection->setFlatten(); + break; + case EatBranch: + selection->setDontFlatten(); + break; + default: + warn(loc, "attribute does not apply to a selection", "", ""); + break; + } + } +} + +// +// Switch attributes +// +void HlslParseContext::handleSwitchAttributes(const TSourceLoc& loc, TIntermSwitch* selection, + const TAttributes& attributes) +{ + if (selection == nullptr) + return; + + for (auto it = attributes.begin(); it != attributes.end(); ++it) { + switch (it->name) { + case EatFlatten: + selection->setFlatten(); + break; + case EatBranch: + selection->setDontFlatten(); + break; + default: + warn(loc, "attribute does not apply to a switch", "", ""); + break; + } + } +} + +// +// Loop attributes +// +void HlslParseContext::handleLoopAttributes(const TSourceLoc& loc, TIntermLoop* loop, + const TAttributes& attributes) +{ + if (loop == nullptr) + return; + + for (auto it = attributes.begin(); it != attributes.end(); ++it) { + switch (it->name) { + case EatUnroll: + loop->setUnroll(); + break; + case EatLoop: + loop->setDontUnroll(); + break; + default: + warn(loc, "attribute does not apply to a loop", "", ""); + break; + } + } +} + // // Updating default qualifier for the case of a declaration with just a qualifier, // no type, block, or identifier. @@ -3982,9 +8974,6 @@ void HlslParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, if (publicType.shaderQualifiers.vertices != TQualifier::layoutNotSet) { assert(language == EShLangTessControl || language == EShLangGeometry); // const char* id = (language == EShLangTessControl) ? "vertices" : "max_vertices"; - - if (language == EShLangTessControl) - checkIoArraysConsistency(loc); } if (publicType.shaderQualifiers.invocations != TQualifier::layoutNotSet) { if (! intermediate.setInvocations(publicType.shaderQualifiers.invocations)) @@ -4000,28 +8989,16 @@ void HlslParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, case ElgTrianglesAdjacency: case ElgQuads: case ElgIsolines: - if (intermediate.setInputPrimitive(publicType.shaderQualifiers.geometry)) { - if (language == EShLangGeometry) - checkIoArraysConsistency(loc); - } else - error(loc, "cannot change previously set input primitive", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), ""); break; default: - error(loc, "cannot apply to input", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), ""); + error(loc, "cannot apply to input", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), + ""); } } else if (publicType.qualifier.storage == EvqVaryingOut) { - switch (publicType.shaderQualifiers.geometry) { - case ElgPoints: - case ElgLineStrip: - case ElgTriangleStrip: - if (! intermediate.setOutputPrimitive(publicType.shaderQualifiers.geometry)) - error(loc, "cannot change previously set output primitive", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), ""); - break; - default: - error(loc, "cannot apply to 'out'", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), ""); - } + handleOutputGeometry(loc, publicType.shaderQualifiers.geometry); } else - error(loc, "cannot apply to:", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), GetStorageQualifierString(publicType.qualifier.storage)); + error(loc, "cannot apply to:", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), + GetStorageQualifierString(publicType.qualifier.storage)); } if (publicType.shaderQualifiers.spacing != EvsNone) intermediate.setVertexSpacing(publicType.shaderQualifiers.spacing); @@ -4079,7 +9056,8 @@ void HlslParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, globalOutputDefaults.layoutXfbBuffer = qualifier.layoutXfbBuffer; if (globalOutputDefaults.hasXfbBuffer() && qualifier.hasXfbStride()) { if (! intermediate.setXfbBufferStride(globalOutputDefaults.layoutXfbBuffer, qualifier.layoutXfbStride)) - error(loc, "all stride settings must match for xfb buffer", "xfb_stride", "%d", qualifier.layoutXfbBuffer); + error(loc, "all stride settings must match for xfb buffer", "xfb_stride", "%d", + qualifier.layoutXfbBuffer); } break; default: @@ -4128,7 +9106,8 @@ void HlslParseContext::wrapupSwitchSubsequence(TIntermAggregate* statements, TIn // Turn the top-level node sequence built up of wrapupSwitchSubsequence // into a switch node. // -TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* expression, TIntermAggregate* lastStatements) +TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* expression, + TIntermAggregate* lastStatements, const TAttributes& attributes) { wrapupSwitchSubsequence(lastStatements, nullptr); @@ -4155,8 +9134,861 @@ TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* ex TIntermSwitch* switchNode = new TIntermSwitch(expression, body); switchNode->setLoc(loc); + handleSwitchAttributes(loc, switchNode, attributes); return switchNode; } +// Make a new symbol-table level that is made out of the members of a structure. +// This should be done as an anonymous struct (name is "") so that the symbol table +// finds the members with no explicit reference to a 'this' variable. +void HlslParseContext::pushThisScope(const TType& thisStruct, const TVector& functionDeclarators) +{ + // member variables + TVariable& thisVariable = *new TVariable(NewPoolTString(""), thisStruct); + symbolTable.pushThis(thisVariable); + + // member functions + for (auto it = functionDeclarators.begin(); it != functionDeclarators.end(); ++it) { + // member should have a prefix matching currentTypePrefix.back() + // but, symbol lookup within the class scope will just use the + // unprefixed name. Hence, there are two: one fully prefixed and + // one with no prefix. + TFunction& member = *it->function->clone(); + member.removePrefix(currentTypePrefix.back()); + symbolTable.insert(member); + } +} + +// Track levels of class/struct/namespace nesting with a prefix string using +// the type names separated by the scoping operator. E.g., two levels +// would look like: +// +// outer::inner +// +// The string is empty when at normal global level. +// +void HlslParseContext::pushNamespace(const TString& typeName) +{ + // make new type prefix + TString newPrefix; + if (currentTypePrefix.size() > 0) + newPrefix = currentTypePrefix.back(); + newPrefix.append(typeName); + newPrefix.append(scopeMangler); + currentTypePrefix.push_back(newPrefix); +} + +// Opposite of pushNamespace(), see above +void HlslParseContext::popNamespace() +{ + currentTypePrefix.pop_back(); +} + +// Use the class/struct nesting string to create a global name for +// a member of a class/struct. +void HlslParseContext::getFullNamespaceName(TString*& name) const +{ + if (currentTypePrefix.size() == 0) + return; + + TString* fullName = NewPoolTString(currentTypePrefix.back().c_str()); + fullName->append(*name); + name = fullName; +} + +// Helper function to add the namespace scope mangling syntax to a string. +void HlslParseContext::addScopeMangler(TString& name) +{ + name.append(scopeMangler); +} + +// Return true if this has uniform-interface like decorations. +bool HlslParseContext::hasUniform(const TQualifier& qualifier) const +{ + return qualifier.hasUniformLayout() || + qualifier.layoutPushConstant; +} + +// Potentially not the opposite of hasUniform(), as if some characteristic is +// ever used for more than one thing (e.g., uniform or input), hasUniform() should +// say it exists, but clearUniform() should leave it in place. +void HlslParseContext::clearUniform(TQualifier& qualifier) +{ + qualifier.clearUniformLayout(); + qualifier.layoutPushConstant = false; +} + +// Return false if builtIn by itself doesn't force this qualifier to be an input qualifier. +bool HlslParseContext::isInputBuiltIn(const TQualifier& qualifier) const +{ + switch (qualifier.builtIn) { + case EbvPosition: + case EbvPointSize: + return language != EShLangVertex && language != EShLangCompute && language != EShLangFragment; + case EbvClipDistance: + case EbvCullDistance: + return language != EShLangVertex && language != EShLangCompute; + case EbvFragCoord: + case EbvFace: + case EbvHelperInvocation: + case EbvLayer: + case EbvPointCoord: + case EbvSampleId: + case EbvSampleMask: + case EbvSamplePosition: + case EbvViewportIndex: + return language == EShLangFragment; + case EbvGlobalInvocationId: + case EbvLocalInvocationIndex: + case EbvLocalInvocationId: + case EbvNumWorkGroups: + case EbvWorkGroupId: + case EbvWorkGroupSize: + return language == EShLangCompute; + case EbvInvocationId: + return language == EShLangTessControl || language == EShLangTessEvaluation || language == EShLangGeometry; + case EbvPatchVertices: + return language == EShLangTessControl || language == EShLangTessEvaluation; + case EbvInstanceId: + case EbvInstanceIndex: + case EbvVertexId: + case EbvVertexIndex: + return language == EShLangVertex; + case EbvPrimitiveId: + return language == EShLangGeometry || language == EShLangFragment || language == EShLangTessControl; + case EbvTessLevelInner: + case EbvTessLevelOuter: + return language == EShLangTessEvaluation; + case EbvTessCoord: + return language == EShLangTessEvaluation; + default: + return false; + } +} + +// Return true if there are decorations to preserve for input-like storage. +bool HlslParseContext::hasInput(const TQualifier& qualifier) const +{ + if (qualifier.hasAnyLocation()) + return true; + + if (language == EShLangFragment && (qualifier.isInterpolation() || qualifier.centroid || qualifier.sample)) + return true; + + if (language == EShLangTessEvaluation && qualifier.patch) + return true; + + if (isInputBuiltIn(qualifier)) + return true; + + return false; +} + +// Return false if builtIn by itself doesn't force this qualifier to be an output qualifier. +bool HlslParseContext::isOutputBuiltIn(const TQualifier& qualifier) const +{ + switch (qualifier.builtIn) { + case EbvPosition: + case EbvPointSize: + case EbvClipVertex: + case EbvClipDistance: + case EbvCullDistance: + return language != EShLangFragment && language != EShLangCompute; + case EbvFragDepth: + case EbvFragDepthGreater: + case EbvFragDepthLesser: + case EbvSampleMask: + return language == EShLangFragment; + case EbvLayer: + case EbvViewportIndex: + return language == EShLangGeometry || language == EShLangVertex; + case EbvPrimitiveId: + return language == EShLangGeometry; + case EbvTessLevelInner: + case EbvTessLevelOuter: + return language == EShLangTessControl; + default: + return false; + } +} + +// Return true if there are decorations to preserve for output-like storage. +bool HlslParseContext::hasOutput(const TQualifier& qualifier) const +{ + if (qualifier.hasAnyLocation()) + return true; + + if (language != EShLangFragment && language != EShLangCompute && qualifier.hasXfb()) + return true; + + if (language == EShLangTessControl && qualifier.patch) + return true; + + if (language == EShLangGeometry && qualifier.hasStream()) + return true; + + if (isOutputBuiltIn(qualifier)) + return true; + + return false; +} + +// Make the IO decorations etc. be appropriate only for an input interface. +void HlslParseContext::correctInput(TQualifier& qualifier) +{ + clearUniform(qualifier); + if (language == EShLangVertex) + qualifier.clearInterstage(); + if (language != EShLangTessEvaluation) + qualifier.patch = false; + if (language != EShLangFragment) { + qualifier.clearInterpolation(); + qualifier.sample = false; + } + + qualifier.clearStreamLayout(); + qualifier.clearXfbLayout(); + + if (! isInputBuiltIn(qualifier)) + qualifier.builtIn = EbvNone; +} + +// Make the IO decorations etc. be appropriate only for an output interface. +void HlslParseContext::correctOutput(TQualifier& qualifier) +{ + clearUniform(qualifier); + if (language == EShLangFragment) + qualifier.clearInterstage(); + if (language != EShLangGeometry) + qualifier.clearStreamLayout(); + if (language == EShLangFragment) + qualifier.clearXfbLayout(); + if (language != EShLangTessControl) + qualifier.patch = false; + + switch (qualifier.builtIn) { + case EbvFragDepth: + intermediate.setDepthReplacing(); + intermediate.setDepth(EldAny); + break; + case EbvFragDepthGreater: + intermediate.setDepthReplacing(); + intermediate.setDepth(EldGreater); + qualifier.builtIn = EbvFragDepth; + break; + case EbvFragDepthLesser: + intermediate.setDepthReplacing(); + intermediate.setDepth(EldLess); + qualifier.builtIn = EbvFragDepth; + break; + default: + break; + } + + if (! isOutputBuiltIn(qualifier)) + qualifier.builtIn = EbvNone; +} + +// Make the IO decorations etc. be appropriate only for uniform type interfaces. +void HlslParseContext::correctUniform(TQualifier& qualifier) +{ + if (qualifier.declaredBuiltIn == EbvNone) + qualifier.declaredBuiltIn = qualifier.builtIn; + + qualifier.builtIn = EbvNone; + qualifier.clearInterstage(); + qualifier.clearInterstageLayout(); +} + +// Clear out all IO/Uniform stuff, so this has nothing to do with being an IO interface. +void HlslParseContext::clearUniformInputOutput(TQualifier& qualifier) +{ + clearUniform(qualifier); + correctUniform(qualifier); +} + + +// Set texture return type. Returns success (not all types are valid). +bool HlslParseContext::setTextureReturnType(TSampler& sampler, const TType& retType, const TSourceLoc& loc) +{ + // Seed the output with an invalid index. We will set it to a valid one if we can. + sampler.structReturnIndex = TSampler::noReturnStruct; + + // Arrays aren't supported. + if (retType.isArray()) { + error(loc, "Arrays not supported in texture template types", "", ""); + return false; + } + + // If return type is a vector, remember the vector size in the sampler, and return. + if (retType.isVector() || retType.isScalar()) { + sampler.vectorSize = retType.getVectorSize(); + return true; + } + + // If it wasn't a vector, it must be a struct meeting certain requirements. The requirements + // are checked below: just check for struct-ness here. + if (!retType.isStruct()) { + error(loc, "Invalid texture template type", "", ""); + return false; + } + + // TODO: Subpass doesn't handle struct returns, due to some oddities with fn overloading. + if (sampler.isSubpass()) { + error(loc, "Unimplemented: structure template type in subpass input", "", ""); + return false; + } + + TTypeList* members = retType.getWritableStruct(); + + // Check for too many or not enough structure members. + if (members->size() > 4 || members->size() == 0) { + error(loc, "Invalid member count in texture template structure", "", ""); + return false; + } + + // Error checking: We must have <= 4 total components, all of the same basic type. + unsigned totalComponents = 0; + for (unsigned m = 0; m < members->size(); ++m) { + // Check for bad member types + if (!(*members)[m].type->isScalar() && !(*members)[m].type->isVector()) { + error(loc, "Invalid texture template struct member type", "", ""); + return false; + } + + const unsigned memberVectorSize = (*members)[m].type->getVectorSize(); + totalComponents += memberVectorSize; + + // too many total member components + if (totalComponents > 4) { + error(loc, "Too many components in texture template structure type", "", ""); + return false; + } + + // All members must be of a common basic type + if ((*members)[m].type->getBasicType() != (*members)[0].type->getBasicType()) { + error(loc, "Texture template structure members must same basic type", "", ""); + return false; + } + } + + // If the structure in the return type already exists in the table, we'll use it. Otherwise, we'll make + // a new entry. This is a linear search, but it hardly ever happens, and the list cannot be very large. + for (unsigned int idx = 0; idx < textureReturnStruct.size(); ++idx) { + if (textureReturnStruct[idx] == members) { + sampler.structReturnIndex = idx; + return true; + } + } + + // It wasn't found as an existing entry. See if we have room for a new one. + if (textureReturnStruct.size() >= TSampler::structReturnSlots) { + error(loc, "Texture template struct return slots exceeded", "", ""); + return false; + } + + // Insert it in the vector that tracks struct return types. + sampler.structReturnIndex = unsigned(textureReturnStruct.size()); + textureReturnStruct.push_back(members); + + // Success! + return true; +} + +// Return the sampler return type in retType. +void HlslParseContext::getTextureReturnType(const TSampler& sampler, TType& retType) const +{ + if (sampler.hasReturnStruct()) { + assert(textureReturnStruct.size() >= sampler.structReturnIndex); + + // We land here if the texture return is a structure. + TTypeList* blockStruct = textureReturnStruct[sampler.structReturnIndex]; + + const TType resultType(blockStruct, ""); + retType.shallowCopy(resultType); + } else { + // We land here if the texture return is a vector or scalar. + const TType resultType(sampler.type, EvqTemporary, sampler.getVectorSize()); + retType.shallowCopy(resultType); + } +} + + +// Return a symbol for the tessellation linkage variable of the given TBuiltInVariable type +TIntermSymbol* HlslParseContext::findTessLinkageSymbol(TBuiltInVariable biType) const +{ + const auto it = builtInTessLinkageSymbols.find(biType); + if (it == builtInTessLinkageSymbols.end()) // if it wasn't declared by the user, return nullptr + return nullptr; + + return intermediate.addSymbol(*it->second->getAsVariable()); +} + +// Find the patch constant function (issues error, returns nullptr if not found) +const TFunction* HlslParseContext::findPatchConstantFunction(const TSourceLoc& loc) +{ + if (symbolTable.isFunctionNameVariable(patchConstantFunctionName)) { + error(loc, "can't use variable in patch constant function", patchConstantFunctionName.c_str(), ""); + return nullptr; + } + + const TString mangledName = patchConstantFunctionName + "("; + + // create list of PCF candidates + TVector candidateList; + bool builtIn; + symbolTable.findFunctionNameList(mangledName, candidateList, builtIn); + + // We have to have one and only one, or we don't know which to pick: the patchconstantfunc does not + // allow any disambiguation of overloads. + if (candidateList.empty()) { + error(loc, "patch constant function not found", patchConstantFunctionName.c_str(), ""); + return nullptr; + } + + // Based on directed experiments, it appears that if there are overloaded patchconstantfunctions, + // HLSL picks the last one in shader source order. Since that isn't yet implemented here, error + // out if there is more than one candidate. + if (candidateList.size() > 1) { + error(loc, "ambiguous patch constant function", patchConstantFunctionName.c_str(), ""); + return nullptr; + } + + return candidateList[0]; +} + +// Finalization step: Add patch constant function invocation +void HlslParseContext::addPatchConstantInvocation() +{ + TSourceLoc loc; + loc.init(); + + // If there's no patch constant function, or we're not a HS, do nothing. + if (patchConstantFunctionName.empty() || language != EShLangTessControl) + return; + + // Look for built-in variables in a function's parameter list. + const auto findBuiltIns = [&](const TFunction& function, std::set& builtIns) { + for (int p=0; pgetQualifier().storage; + + if (storage == EvqConstReadOnly) // treated identically to input + storage = EvqIn; + + if (function[p].getDeclaredBuiltIn() != EbvNone) + builtIns.insert(HlslParseContext::tInterstageIoData(function[p].getDeclaredBuiltIn(), storage)); + else + builtIns.insert(HlslParseContext::tInterstageIoData(function[p].type->getQualifier().builtIn, storage)); + } + }; + + // If we synthesize a built-in interface variable, we must add it to the linkage. + const auto addToLinkage = [&](const TType& type, const TString* name, TIntermSymbol** symbolNode) { + if (name == nullptr) { + error(loc, "unable to locate patch function parameter name", "", ""); + return; + } else { + TVariable& variable = *new TVariable(name, type); + if (! symbolTable.insert(variable)) { + error(loc, "unable to declare patch constant function interface variable", name->c_str(), ""); + return; + } + + globalQualifierFix(loc, variable.getWritableType().getQualifier()); + + if (symbolNode != nullptr) + *symbolNode = intermediate.addSymbol(variable); + + trackLinkage(variable); + } + }; + + const auto isOutputPatch = [](TFunction& patchConstantFunction, int param) { + const TType& type = *patchConstantFunction[param].type; + const TBuiltInVariable biType = patchConstantFunction[param].getDeclaredBuiltIn(); + + return type.isSizedArray() && biType == EbvOutputPatch; + }; + + // We will perform these steps. Each is in a scoped block for separation: they could + // become separate functions to make addPatchConstantInvocation shorter. + // + // 1. Union the interfaces, and create built-ins for anything present in the PCF and + // declared as a built-in variable that isn't present in the entry point's signature. + // + // 2. Synthesizes a call to the patchconstfunction using built-in variables from either main, + // or the ones we created. Matching is based on built-in type. We may use synthesized + // variables from (1) above. + // + // 2B: Synthesize per control point invocations of wrapped entry point if the PCF requires them. + // + // 3. Create a return sequence: copy the return value (if any) from the PCF to a + // (non-sanitized) output variable. In case this may involve multiple copies, such as for + // an arrayed variable, a temporary copy of the PCF output is created to avoid multiple + // indirections into a complex R-value coming from the call to the PCF. + // + // 4. Create a barrier. + // + // 5/5B. Call the PCF inside an if test for (invocation id == 0). + + TFunction* patchConstantFunctionPtr = const_cast(findPatchConstantFunction(loc)); + + if (patchConstantFunctionPtr == nullptr) + return; + + TFunction& patchConstantFunction = *patchConstantFunctionPtr; + + const int pcfParamCount = patchConstantFunction.getParamCount(); + TIntermSymbol* invocationIdSym = findTessLinkageSymbol(EbvInvocationId); + TIntermSequence& epBodySeq = entryPointFunctionBody->getAsAggregate()->getSequence(); + + int outPatchParam = -1; // -1 means there isn't one. + + // ================ Step 1A: Union Interfaces ================ + // Our patch constant function. + { + std::set pcfBuiltIns; // patch constant function built-ins + std::set epfBuiltIns; // entry point function built-ins + + assert(entryPointFunction); + assert(entryPointFunctionBody); + + findBuiltIns(patchConstantFunction, pcfBuiltIns); + findBuiltIns(*entryPointFunction, epfBuiltIns); + + // Find the set of built-ins in the PCF that are not present in the entry point. + std::set notInEntryPoint; + + notInEntryPoint = pcfBuiltIns; + + // std::set_difference not usable on unordered containers + for (auto bi = epfBuiltIns.begin(); bi != epfBuiltIns.end(); ++bi) + notInEntryPoint.erase(*bi); + + // Now we'll add those to the entry and to the linkage. + for (int p=0; pgetQualifier().storage; + + // Track whether there is an output patch param + if (isOutputPatch(patchConstantFunction, p)) { + if (outPatchParam >= 0) { + // Presently we only support one per ctrl pt input. + error(loc, "unimplemented: multiple output patches in patch constant function", "", ""); + return; + } + outPatchParam = p; + } + + if (biType != EbvNone) { + TType* paramType = patchConstantFunction[p].type->clone(); + + if (storage == EvqConstReadOnly) // treated identically to input + storage = EvqIn; + + // Presently, the only non-built-in we support is InputPatch, which is treated as + // a pseudo-built-in. + if (biType == EbvInputPatch) { + builtInTessLinkageSymbols[biType] = inputPatch; + } else if (biType == EbvOutputPatch) { + // Nothing... + } else { + // Use the original declaration type for the linkage + paramType->getQualifier().builtIn = biType; + + if (notInEntryPoint.count(tInterstageIoData(biType, storage)) == 1) + addToLinkage(*paramType, patchConstantFunction[p].name, nullptr); + } + } + } + + // If we didn't find it because the shader made one, add our own. + if (invocationIdSym == nullptr) { + TType invocationIdType(EbtUint, EvqIn, 1); + TString* invocationIdName = NewPoolTString("InvocationId"); + invocationIdType.getQualifier().builtIn = EbvInvocationId; + addToLinkage(invocationIdType, invocationIdName, &invocationIdSym); + } + + assert(invocationIdSym); + } + + TIntermTyped* pcfArguments = nullptr; + TVariable* perCtrlPtVar = nullptr; + + // ================ Step 1B: Argument synthesis ================ + // Create pcfArguments for synthesis of patchconstantfunction invocation + { + for (int p=0; pgetWritableType().getQualifier().makeTemporary(); + } + inputArg = intermediate.addSymbol(*perCtrlPtVar, loc); + } else { + // find which built-in it is + const TBuiltInVariable biType = patchConstantFunction[p].getDeclaredBuiltIn(); + + if (biType == EbvInputPatch && inputPatch == nullptr) { + error(loc, "unimplemented: PCF input patch without entry point input patch parameter", "", ""); + return; + } + + inputArg = findTessLinkageSymbol(biType); + + if (inputArg == nullptr) { + error(loc, "unable to find patch constant function built-in variable", "", ""); + return; + } + } + + if (pcfParamCount == 1) + pcfArguments = inputArg; + else + pcfArguments = intermediate.growAggregate(pcfArguments, inputArg); + } + } + + // ================ Step 2: Synthesize call to PCF ================ + TIntermAggregate* pcfCallSequence = nullptr; + TIntermTyped* pcfCall = nullptr; + + { + // Create a function call to the patchconstantfunction + if (pcfArguments) + addInputArgumentConversions(patchConstantFunction, pcfArguments); + + // Synthetic call. + pcfCall = intermediate.setAggregateOperator(pcfArguments, EOpFunctionCall, patchConstantFunction.getType(), loc); + pcfCall->getAsAggregate()->setUserDefined(); + pcfCall->getAsAggregate()->setName(patchConstantFunction.getMangledName()); + intermediate.addToCallGraph(infoSink, intermediate.getEntryPointMangledName().c_str(), + patchConstantFunction.getMangledName()); + + if (pcfCall->getAsAggregate()) { + TQualifierList& qualifierList = pcfCall->getAsAggregate()->getQualifierList(); + for (int i = 0; i < patchConstantFunction.getParamCount(); ++i) { + TStorageQualifier qual = patchConstantFunction[i].type->getQualifier().storage; + qualifierList.push_back(qual); + } + pcfCall = addOutputArgumentConversions(patchConstantFunction, *pcfCall->getAsOperator()); + } + } + + // ================ Step 2B: Per Control Point synthesis ================ + // If there is per control point data, we must either emulate that with multiple + // invocations of the entry point to build up an array, or (TODO:) use a yet + // unavailable extension to look across the SIMD lanes. This is the former + // as a placeholder for the latter. + if (outPatchParam >= 0) { + // We must introduce a local temp variable of the type wanted by the PCF input. + const int arraySize = patchConstantFunction[outPatchParam].type->getOuterArraySize(); + + if (entryPointFunction->getType().getBasicType() == EbtVoid) { + error(loc, "entry point must return a value for use with patch constant function", "", ""); + return; + } + + // Create calls to wrapped main to fill in the array. We will substitute fixed values + // of invocation ID when calling the wrapped main. + + // This is the type of the each member of the per ctrl point array. + const TType derefType(perCtrlPtVar->getType(), 0); + + for (int cpt = 0; cpt < arraySize; ++cpt) { + // TODO: improve. substr(1) here is to avoid the '@' that was grafted on but isn't in the symtab + // for this function. + const TString origName = entryPointFunction->getName().substr(1); + TFunction callee(&origName, TType(EbtVoid)); + TIntermTyped* callingArgs = nullptr; + + for (int i = 0; i < entryPointFunction->getParamCount(); i++) { + TParameter& param = (*entryPointFunction)[i]; + TType& paramType = *param.type; + + if (paramType.getQualifier().isParamOutput()) { + error(loc, "unimplemented: entry point outputs in patch constant function invocation", "", ""); + return; + } + + if (paramType.getQualifier().isParamInput()) { + TIntermTyped* arg = nullptr; + if ((*entryPointFunction)[i].getDeclaredBuiltIn() == EbvInvocationId) { + // substitute invocation ID with the array element ID + arg = intermediate.addConstantUnion(cpt, loc); + } else { + TVariable* argVar = makeInternalVariable(*param.name, *param.type); + argVar->getWritableType().getQualifier().makeTemporary(); + arg = intermediate.addSymbol(*argVar); + } + + handleFunctionArgument(&callee, callingArgs, arg); + } + } + + // Call and assign to per ctrl point variable + currentCaller = intermediate.getEntryPointMangledName().c_str(); + TIntermTyped* callReturn = handleFunctionCall(loc, &callee, callingArgs); + TIntermTyped* index = intermediate.addConstantUnion(cpt, loc); + TIntermSymbol* perCtrlPtSym = intermediate.addSymbol(*perCtrlPtVar, loc); + TIntermTyped* element = intermediate.addIndex(EOpIndexDirect, perCtrlPtSym, index, loc); + element->setType(derefType); + element->setLoc(loc); + + pcfCallSequence = intermediate.growAggregate(pcfCallSequence, + handleAssign(loc, EOpAssign, element, callReturn)); + } + } + + // ================ Step 3: Create return Sequence ================ + // Return sequence: copy PCF result to a temporary, then to shader output variable. + if (pcfCall->getBasicType() != EbtVoid) { + const TType* retType = &patchConstantFunction.getType(); // return type from the PCF + TType outType; // output type that goes with the return type. + outType.shallowCopy(*retType); + + // substitute the output type + const auto newLists = ioTypeMap.find(retType->getStruct()); + if (newLists != ioTypeMap.end()) + outType.setStruct(newLists->second.output); + + // Substitute the top level type's built-in type + if (patchConstantFunction.getDeclaredBuiltInType() != EbvNone) + outType.getQualifier().builtIn = patchConstantFunction.getDeclaredBuiltInType(); + + outType.getQualifier().patch = true; // make it a per-patch variable + + TVariable* pcfOutput = makeInternalVariable("@patchConstantOutput", outType); + pcfOutput->getWritableType().getQualifier().storage = EvqVaryingOut; + + if (pcfOutput->getType().containsBuiltIn()) + split(*pcfOutput); + + assignToInterface(*pcfOutput); + + TIntermSymbol* pcfOutputSym = intermediate.addSymbol(*pcfOutput, loc); + + // The call to the PCF is a complex R-value: we want to store it in a temp to avoid + // repeated calls to the PCF: + TVariable* pcfCallResult = makeInternalVariable("@patchConstantResult", *retType); + pcfCallResult->getWritableType().getQualifier().makeTemporary(); + + TIntermSymbol* pcfResultVar = intermediate.addSymbol(*pcfCallResult, loc); + TIntermNode* pcfResultAssign = handleAssign(loc, EOpAssign, pcfResultVar, pcfCall); + TIntermNode* pcfResultToOut = handleAssign(loc, EOpAssign, pcfOutputSym, + intermediate.addSymbol(*pcfCallResult, loc)); + + pcfCallSequence = intermediate.growAggregate(pcfCallSequence, pcfResultAssign); + pcfCallSequence = intermediate.growAggregate(pcfCallSequence, pcfResultToOut); + } else { + pcfCallSequence = intermediate.growAggregate(pcfCallSequence, pcfCall); + } + + // ================ Step 4: Barrier ================ + TIntermTyped* barrier = new TIntermAggregate(EOpBarrier); + barrier->setLoc(loc); + barrier->setType(TType(EbtVoid)); + epBodySeq.insert(epBodySeq.end(), barrier); + + // ================ Step 5: Test on invocation ID ================ + TIntermTyped* zero = intermediate.addConstantUnion(0, loc, true); + TIntermTyped* cmp = intermediate.addBinaryNode(EOpEqual, invocationIdSym, zero, loc, TType(EbtBool)); + + + // ================ Step 5B: Create if statement on Invocation ID == 0 ================ + intermediate.setAggregateOperator(pcfCallSequence, EOpSequence, TType(EbtVoid), loc); + TIntermTyped* invocationIdTest = new TIntermSelection(cmp, pcfCallSequence, nullptr); + invocationIdTest->setLoc(loc); + + // add our test sequence before the return. + epBodySeq.insert(epBodySeq.end(), invocationIdTest); +} + +// Finalization step: remove unused buffer blocks from linkage (we don't know until the +// shader is entirely compiled). +// Preserve order of remaining symbols. +void HlslParseContext::removeUnusedStructBufferCounters() +{ + const auto endIt = std::remove_if(linkageSymbols.begin(), linkageSymbols.end(), + [this](const TSymbol* sym) { + const auto sbcIt = structBufferCounter.find(sym->getName()); + return sbcIt != structBufferCounter.end() && !sbcIt->second; + }); + + linkageSymbols.erase(endIt, linkageSymbols.end()); +} + +// Finalization step: patch texture shadow modes to match samplers they were combined with +void HlslParseContext::fixTextureShadowModes() +{ + for (auto symbol = linkageSymbols.begin(); symbol != linkageSymbols.end(); ++symbol) { + TSampler& sampler = (*symbol)->getWritableType().getSampler(); + + if (sampler.isTexture()) { + const auto shadowMode = textureShadowVariant.find((*symbol)->getUniqueId()); + if (shadowMode != textureShadowVariant.end()) { + + if (shadowMode->second->overloaded()) + // Texture needs legalization if it's been seen with both shadow and non-shadow modes. + intermediate.setNeedsLegalization(); + + sampler.shadow = shadowMode->second->isShadowId((*symbol)->getUniqueId()); + } + } + } +} + +// Finalization step: patch append methods to use proper stream output, which isn't known until +// main is parsed, which could happen after the append method is parsed. +void HlslParseContext::finalizeAppendMethods() +{ + TSourceLoc loc; + loc.init(); + + // Nothing to do: bypass test for valid stream output. + if (gsAppends.empty()) + return; + + if (gsStreamOutput == nullptr) { + error(loc, "unable to find output symbol for Append()", "", ""); + return; + } + + // Patch append sequences, now that we know the stream output symbol. + for (auto append = gsAppends.begin(); append != gsAppends.end(); ++append) { + append->node->getSequence()[0] = + handleAssign(append->loc, EOpAssign, + intermediate.addSymbol(*gsStreamOutput, append->loc), + append->node->getSequence()[0]->getAsTyped()); + } +} + +// post-processing +void HlslParseContext::finish() +{ + // Error check: There was a dangling .mips operator. These are not nested constructs in the grammar, so + // cannot be detected there. This is not strictly needed in a non-validating parser; it's just helpful. + if (! mipsOperatorMipArg.empty()) { + error(mipsOperatorMipArg.back().loc, "unterminated mips operator:", "", ""); + } + + removeUnusedStructBufferCounters(); + addPatchConstantInvocation(); + fixTextureShadowModes(); + finalizeAppendMethods(); + + // Communicate out (esp. for command line) that we formed AST that will make + // illegal AST SPIR-V and it needs transforms to legalize it. + if (intermediate.needsLegalization() && (messages & EShMsgHlslLegalization)) + infoSink.info << "WARNING: AST will form illegal SPIR-V; need to transform to legalize"; + + TParseContextBase::finish(); +} + } // end namespace glslang diff --git a/Externals/glslang/hlsl/hlslParseHelper.h b/Externals/glslang/hlsl/hlslParseHelper.h index f12813194a..32a1923940 100755 --- a/Externals/glslang/hlsl/hlslParseHelper.h +++ b/Externals/glslang/hlsl/hlslParseHelper.h @@ -1,12 +1,12 @@ // -//Copyright (C) 2016 Google, Inc. -//Copyright (C) 2016 LunarG, Inc. +// Copyright (C) 2016 Google, Inc. +// Copyright (C) 2016 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,84 +20,100 @@ // 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. +// 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 HLSL_PARSE_INCLUDED_ #define HLSL_PARSE_INCLUDED_ #include "../glslang/MachineIndependent/parseVersions.h" #include "../glslang/MachineIndependent/ParseHelper.h" +#include "../glslang/MachineIndependent/attribute.h" + +#include namespace glslang { +class TFunctionDeclarator; + class HlslParseContext : public TParseContextBase { public: HlslParseContext(TSymbolTable&, TIntermediate&, bool parsingBuiltins, int version, EProfile, const SpvVersion& spvVersion, EShLanguage, TInfoSink&, + const TString sourceEntryPointName, bool forwardCompatible = false, EShMessages messages = EShMsgDefault); virtual ~HlslParseContext(); - void setLimits(const TBuiltInResource&); - bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false); - void getPreamble(std::string&); + void initializeExtensionBehavior() override; - void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...); - void C_DECL warn(const TSourceLoc&, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...); - void C_DECL ppError(const TSourceLoc&, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...); - void C_DECL ppWarn(const TSourceLoc&, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...); + void setLimits(const TBuiltInResource&) override; + bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false) override; + virtual const char* getGlobalUniformBlockName() const override { return "$Global"; } + virtual void setUniformBlockDefaults(TType& block) const override + { + block.getQualifier().layoutPacking = ElpStd140; + block.getQualifier().layoutMatrix = ElmRowMajor; + } - void reservedPpErrorCheck(const TSourceLoc&, const char* /*name*/, const char* /*op*/) { } - bool lineContinuationCheck(const TSourceLoc&, bool /*endOfComment*/) { return true; } - bool lineDirectiveShouldSetNextLine() const { return true; } + void reservedPpErrorCheck(const TSourceLoc&, const char* /*name*/, const char* /*op*/) override { } + bool lineContinuationCheck(const TSourceLoc&, bool /*endOfComment*/) override { return true; } + bool lineDirectiveShouldSetNextLine() const override { return true; } bool builtInName(const TString&); - void handlePragma(const TSourceLoc&, const TVector&); - TIntermTyped* handleVariable(const TSourceLoc&, TSymbol* symbol, const TString* string); + void handlePragma(const TSourceLoc&, const TVector&) override; + TIntermTyped* handleVariable(const TSourceLoc&, const TString* string); TIntermTyped* handleBracketDereference(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index); - void checkIndex(const TSourceLoc&, const TType&, int& index); - - void makeEditable(TSymbol*&); - TVariable* getEditableVariable(const char* name); - bool isIoResizeArray(const TType&) const; - void fixIoArraySize(const TSourceLoc&, TType&); - void handleIoResizeArrayAccess(const TSourceLoc&, TIntermTyped* base); - void checkIoArraysConsistency(const TSourceLoc&, bool tailOnly = false); - int getIoArrayImplicitSize() const; - void checkIoArrayConsistency(const TSourceLoc&, int requiredSize, const char* feature, TType&, const TString&); + TIntermTyped* handleBracketOperator(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index); TIntermTyped* handleBinaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right); TIntermTyped* handleUnaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* childNode); TIntermTyped* handleDotDereference(const TSourceLoc&, TIntermTyped* base, const TString& field); - TFunction* handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype); - TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&); + bool isBuiltInMethod(const TSourceLoc&, TIntermTyped* base, const TString& field); + void assignToInterface(TVariable& variable); + void handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype); + TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&, const TAttributes&, TIntermNode*& entryPointTree); + TIntermNode* transformEntryPoint(const TSourceLoc&, TFunction&, const TAttributes&); + void handleEntryPointAttributes(const TSourceLoc&, const TAttributes&); + void transferTypeAttributes(const TSourceLoc&, const TAttributes&, TType&, bool allowEntry = false); + void handleFunctionBody(const TSourceLoc&, TFunction&, TIntermNode* functionBody, TIntermNode*& node); + void remapEntryPointIO(TFunction& function, TVariable*& returnValue, TVector& inputs, TVector& outputs); + void remapNonEntryPointIO(TFunction& function); + TIntermNode* handleReturnValue(const TSourceLoc&, TIntermTyped*); void handleFunctionArgument(TFunction*, TIntermTyped*& arguments, TIntermTyped* newArg); - TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*); + TIntermTyped* handleAssign(const TSourceLoc&, TOperator, TIntermTyped* left, TIntermTyped* right); + TIntermTyped* handleAssignToMatrixSwizzle(const TSourceLoc&, TOperator, TIntermTyped* left, TIntermTyped* right); + TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermTyped*); + TIntermAggregate* assignClipCullDistance(const TSourceLoc&, TOperator, int semanticId, TIntermTyped* left, TIntermTyped* right); + TIntermTyped* assignPosition(const TSourceLoc&, TOperator, TIntermTyped* left, TIntermTyped* right); void decomposeIntrinsic(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments); void decomposeSampleMethods(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments); - TIntermTyped* handleLengthMethod(const TSourceLoc&, TFunction*, TIntermNode*); - void addInputArgumentConversions(const TFunction&, TIntermNode*&) const; - TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermAggregate&) const; + void decomposeStructBufferMethods(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments); + void decomposeGeometryMethods(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments); + void pushFrontArguments(TIntermTyped* front, TIntermTyped*& arguments); + void addInputArgumentConversions(const TFunction&, TIntermTyped*&); + void expandArguments(const TSourceLoc&, const TFunction&, TIntermTyped*&); + TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermOperator&); void builtInOpCheck(const TSourceLoc&, const TFunction&, TIntermOperator&); - TFunction* handleConstructorCall(const TSourceLoc&, const TType&); - void handleSemantic(TType& type, const TString& semantic); - + TFunction* makeConstructorCall(const TSourceLoc&, const TType&); + void handleSemantic(TSourceLoc, TQualifier&, TBuiltInVariable, const TString& upperCase); + void handlePackOffset(const TSourceLoc&, TQualifier&, const glslang::TString& location, + const glslang::TString* component); + void handleRegister(const TSourceLoc&, TQualifier&, const glslang::TString* profile, const glslang::TString& desc, + int subComponent, const glslang::TString*); + TIntermTyped* convertConditionalExpression(const TSourceLoc&, TIntermTyped*, bool mustBeScalar = true); TIntermAggregate* handleSamplerTextureCombine(const TSourceLoc& loc, TIntermTyped* argTex, TIntermTyped* argSampler); - bool parseVectorFields(const TSourceLoc&, const TString&, int vecSize, TVectorFields&); + bool parseMatrixSwizzleSelector(const TSourceLoc&, const TString&, int cols, int rows, TSwizzleSelectors&); + int getMatrixComponentsColumn(int rows, const TSwizzleSelectors&); void assignError(const TSourceLoc&, const char* op, TString left, TString right); void unaryOpError(const TSourceLoc&, const char* op, TString operand); void binaryOpError(const TSourceLoc&, const char* op, TString left, TString right); @@ -110,83 +126,219 @@ public: void arraySizeCheck(const TSourceLoc&, TIntermTyped* expr, TArraySize&); void arraySizeRequiredCheck(const TSourceLoc&, const TArraySizes&); void structArrayCheck(const TSourceLoc&, const TType& structure); - void arrayDimMerge(TType& type, const TArraySizes* sizes); bool voidErrorCheck(const TSourceLoc&, const TString&, TBasicType); - void boolCheck(const TSourceLoc&, const TIntermTyped*); void globalQualifierFix(const TSourceLoc&, TQualifier&); bool structQualifierErrorCheck(const TSourceLoc&, const TPublicType& pType); - void mergeQualifiers(const TSourceLoc&, TQualifier& dst, const TQualifier& src, bool force); + void mergeQualifiers(TQualifier& dst, const TQualifier& src); int computeSamplerTypeIndex(TSampler&); - TSymbol* redeclareBuiltinVariable(const TSourceLoc&, const TString&, const TQualifier&, const TShaderQualifiers&, bool& newDeclaration); - void redeclareBuiltinBlock(const TSourceLoc&, TTypeList& typeList, const TString& blockName, const TString* instanceName, TArraySizes* arraySizes); + TSymbol* redeclareBuiltinVariable(const TSourceLoc&, const TString&, const TQualifier&, const TShaderQualifiers&); void paramFix(TType& type); void specializationCheck(const TSourceLoc&, const TType&, const char* op); - void setLayoutQualifier(const TSourceLoc&, TPublicType&, TString&); - void setLayoutQualifier(const TSourceLoc&, TPublicType&, TString&, const TIntermTyped*); + void setLayoutQualifier(const TSourceLoc&, TQualifier&, TString&); + void setLayoutQualifier(const TSourceLoc&, TQualifier&, TString&, const TIntermTyped*); + void setSpecConstantId(const TSourceLoc&, TQualifier&, int value); void mergeObjectLayoutQualifiers(TQualifier& dest, const TQualifier& src, bool inheritOnly); void checkNoShaderLayouts(const TSourceLoc&, const TShaderQualifiers&); - const TFunction* findFunction(const TSourceLoc& loc, const TFunction& call, bool& builtIn); - void declareTypedef(const TSourceLoc&, TString& identifier, const TType&, TArraySizes* typeArray = 0); - TIntermNode* declareVariable(const TSourceLoc&, TString& identifier, const TType&, TArraySizes* typeArray = 0, TIntermTyped* initializer = 0); - TIntermTyped* addConstructor(const TSourceLoc&, TIntermNode*, const TType&, TOperator); + const TFunction* findFunction(const TSourceLoc& loc, TFunction& call, bool& builtIn, int& thisDepth, TIntermTyped*& args); + void addGenMulArgumentConversion(const TSourceLoc& loc, TFunction& call, TIntermTyped*& args); + void declareTypedef(const TSourceLoc&, const TString& identifier, const TType&); + void declareStruct(const TSourceLoc&, TString& structName, TType&); + TSymbol* lookupUserType(const TString&, TType&); + TIntermNode* declareVariable(const TSourceLoc&, const TString& identifier, TType&, TIntermTyped* initializer = 0); + void lengthenList(const TSourceLoc&, TIntermSequence& list, int size, TIntermTyped* scalarInit); + TIntermTyped* handleConstructor(const TSourceLoc&, TIntermTyped*, const TType&); + TIntermTyped* addConstructor(const TSourceLoc&, TIntermTyped*, const TType&); + TIntermTyped* convertArray(TIntermTyped*, const TType&); TIntermTyped* constructAggregate(TIntermNode*, const TType&, int, const TSourceLoc&); TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermTyped*, const TSourceLoc&, bool subset); - void declareBlock(const TSourceLoc&, TTypeList& typeList, const TString* instanceName = 0, TArraySizes* arraySizes = 0); + void declareBlock(const TSourceLoc&, TType&, const TString* instanceName = 0); + void declareStructBufferCounter(const TSourceLoc& loc, const TType& bufferType, const TString& name); void fixBlockLocations(const TSourceLoc&, TQualifier&, TTypeList&, bool memberWithLocation, bool memberWithoutLocation); void fixBlockXfbOffsets(TQualifier&, TTypeList&); - void fixBlockUniformOffsets(TQualifier&, TTypeList&); + void fixBlockUniformOffsets(const TQualifier&, TTypeList&); void addQualifierToExisting(const TSourceLoc&, TQualifier, const TString& identifier); void addQualifierToExisting(const TSourceLoc&, TQualifier, TIdentifierList&); void updateStandaloneQualifierDefaults(const TSourceLoc&, const TPublicType&); void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode); - TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body); + TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body, const TAttributes&); - void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index); + void nestLooping() { ++loopNestingLevel; } + void unnestLooping() { --loopNestingLevel; } + void nestAnnotations() { ++annotationNestingLevel; } + void unnestAnnotations() { --annotationNestingLevel; } + int getAnnotationNestingLevel() { return annotationNestingLevel; } + void pushScope() { symbolTable.push(); } + void popScope() { symbolTable.pop(0); } - void nestLooping() { ++loopNestingLevel; } - void unnestLooping() { --loopNestingLevel; } - void pushScope() { symbolTable.push(); } - void popScope() { symbolTable.pop(0); } + void pushThisScope(const TType&, const TVector&); + void popThisScope() { symbolTable.pop(0); } + + void pushImplicitThis(TVariable* thisParameter) { implicitThisStack.push_back(thisParameter); } + void popImplicitThis() { implicitThisStack.pop_back(); } + TVariable* getImplicitThis(int thisDepth) const { return implicitThisStack[implicitThisStack.size() - thisDepth]; } + + void pushNamespace(const TString& name); + void popNamespace(); + void getFullNamespaceName(TString*&) const; + void addScopeMangler(TString&); void pushSwitchSequence(TIntermSequence* sequence) { switchSequenceStack.push_back(sequence); } void popSwitchSequence() { switchSequenceStack.pop_back(); } + virtual void growGlobalUniformBlock(const TSourceLoc&, TType&, const TString& memberName, + TTypeList* typeList = nullptr) override; + + // Apply L-value conversions. E.g, turning a write to a RWTexture into an ImageStore. + TIntermTyped* handleLvalue(const TSourceLoc&, const char* op, TIntermTyped*& node); + bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*) override; + + TLayoutFormat getLayoutFromTxType(const TSourceLoc&, const TType&); + + bool handleOutputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry); + bool handleInputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry); + + // Determine selection control from attributes + void handleSelectionAttributes(const TSourceLoc& loc, TIntermSelection*, const TAttributes& attributes); + void handleSwitchAttributes(const TSourceLoc& loc, TIntermSwitch*, const TAttributes& attributes); + + // Determine loop control from attributes + void handleLoopAttributes(const TSourceLoc& loc, TIntermLoop*, const TAttributes& attributes); + + // Share struct buffer deep types + void shareStructBufferType(TType&); + + // Set texture return type of the given sampler. Returns success (not all types are valid). + bool setTextureReturnType(TSampler& sampler, const TType& retType, const TSourceLoc& loc); + + // Obtain the sampler return type of the given sampler in retType. + void getTextureReturnType(const TSampler& sampler, TType& retType) const; + + TAttributeType attributeFromName(const TString& nameSpace, const TString& name) const; + protected: + struct TFlattenData { + TFlattenData() : nextBinding(TQualifier::layoutBindingEnd), + nextLocation(TQualifier::layoutLocationEnd) { } + TFlattenData(int nb, int nl) : nextBinding(nb), nextLocation(nl) { } + + TVector members; // individual flattened variables + TVector offsets; // offset to next tree level + unsigned int nextBinding; // next binding to use. + unsigned int nextLocation; // next location to use + }; + + void fixConstInit(const TSourceLoc&, const TString& identifier, TType& type, TIntermTyped*& initializer); void inheritGlobalDefaults(TQualifier& dst) const; TVariable* makeInternalVariable(const char* name, const TType&) const; - TVariable* declareNonArray(const TSourceLoc&, TString& identifier, TType&, bool& newDeclaration); - void declareArray(const TSourceLoc&, TString& identifier, const TType&, TSymbol*&, bool& newDeclaration); + TVariable* makeInternalVariable(const TString& name, const TType& type) const { + return makeInternalVariable(name.c_str(), type); + } + TIntermSymbol* makeInternalVariableNode(const TSourceLoc&, const char* name, const TType&) const; + TVariable* declareNonArray(const TSourceLoc&, const TString& identifier, const TType&, bool track); + void declareArray(const TSourceLoc&, const TString& identifier, const TType&, TSymbol*&, bool track); TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable); - TIntermTyped* convertInitializerList(const TSourceLoc&, const TType&, TIntermTyped* initializer); - TOperator mapTypeToConstructorOp(const TType&) const; + TIntermTyped* convertInitializerList(const TSourceLoc&, const TType&, TIntermTyped* initializer, TIntermTyped* scalarInit); + bool isScalarConstructor(const TIntermNode*); TOperator mapAtomicOp(const TSourceLoc& loc, TOperator op, bool isImage); - void outputMessage(const TSourceLoc&, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, TPrefixType prefix, - va_list args); + + // Return true if this node requires L-value conversion (e.g, to an imageStore). + bool shouldConvertLValue(const TIntermNode*) const; + + // Array and struct flattening + TIntermTyped* flattenAccess(TIntermTyped* base, int member); + TIntermTyped* flattenAccess(int uniqueId, int member, TStorageQualifier outerStorage, const TType&, int subset = -1); + int findSubtreeOffset(const TIntermNode&) const; + int findSubtreeOffset(const TType&, int subset, const TVector& offsets) const; + bool shouldFlatten(const TType&, TStorageQualifier, bool topLevel) const; + bool wasFlattened(const TIntermTyped* node) const; + bool wasFlattened(int id) const { return flattenMap.find(id) != flattenMap.end(); } + int addFlattenedMember(const TVariable&, const TType&, TFlattenData&, const TString& name, bool linkage, + const TQualifier& outerQualifier, const TArraySizes* builtInArraySizes); + + // Structure splitting (splits interstage built-in types into its own struct) + void split(const TVariable&); + void splitBuiltIn(const TString& baseName, const TType& memberType, const TArraySizes*, const TQualifier&); + const TType& split(const TType& type, const TString& name, const TQualifier&); + bool wasSplit(const TIntermTyped* node) const; + bool wasSplit(int id) const { return splitNonIoVars.find(id) != splitNonIoVars.end(); } + TVariable* getSplitNonIoVar(int id) const; + void addPatchConstantInvocation(); + void fixTextureShadowModes(); + void finalizeAppendMethods(); + TIntermTyped* makeIntegerIndex(TIntermTyped*); + + void fixBuiltInIoType(TType&); + + void flatten(const TVariable& variable, bool linkage); + int flatten(const TVariable& variable, const TType&, TFlattenData&, TString name, bool linkage, + const TQualifier& outerQualifier, const TArraySizes* builtInArraySizes); + int flattenStruct(const TVariable& variable, const TType&, TFlattenData&, TString name, bool linkage, + const TQualifier& outerQualifier, const TArraySizes* builtInArraySizes); + int flattenArray(const TVariable& variable, const TType&, TFlattenData&, TString name, bool linkage, + const TQualifier& outerQualifier); + + bool hasUniform(const TQualifier& qualifier) const; + void clearUniform(TQualifier& qualifier); + bool isInputBuiltIn(const TQualifier& qualifier) const; + bool hasInput(const TQualifier& qualifier) const; + void correctOutput(TQualifier& qualifier); + bool isOutputBuiltIn(const TQualifier& qualifier) const; + bool hasOutput(const TQualifier& qualifier) const; + void correctInput(TQualifier& qualifier); + void correctUniform(TQualifier& qualifier); + void clearUniformInputOutput(TQualifier& qualifier); + + // Test method names + bool isStructBufferMethod(const TString& name) const; + void counterBufferType(const TSourceLoc& loc, TType& type); + + // Return standard sample position array + TIntermConstantUnion* getSamplePosArray(int count); + + TType* getStructBufferContentType(const TType& type) const; + bool isStructBufferType(const TType& type) const { return getStructBufferContentType(type) != nullptr; } + TIntermTyped* indexStructBufferContent(const TSourceLoc& loc, TIntermTyped* buffer) const; + TIntermTyped* getStructBufferCounter(const TSourceLoc& loc, TIntermTyped* buffer); + TString getStructBuffCounterName(const TString&) const; + void addStructBuffArguments(const TSourceLoc& loc, TIntermAggregate*&); + void addStructBufferHiddenCounterParam(const TSourceLoc& loc, TParameter&, TIntermAggregate*&); + + // Return true if this type is a reference. This is not currently a type method in case that's + // a language specific answer. + bool isReference(const TType& type) const { return isStructBufferType(type); } + + // Return true if this a buffer type that has an associated counter buffer. + bool hasStructBuffCounter(const TType&) const; + + // Finalization step: remove unused buffer blocks from linkage (we don't know until the + // shader is entirely compiled) + void removeUnusedStructBufferCounters(); + + static bool isClipOrCullDistance(TBuiltInVariable); + static bool isClipOrCullDistance(const TQualifier& qual) { return isClipOrCullDistance(qual.builtIn); } + static bool isClipOrCullDistance(const TType& type) { return isClipOrCullDistance(type.getQualifier()); } + + // Find the patch constant function (issues error, returns nullptr if not found) + const TFunction* findPatchConstantFunction(const TSourceLoc& loc); + + // Pass through to base class after remembering built-in mappings. + using TParseContextBase::trackLinkage; + void trackLinkage(TSymbol& variable) override; + + void finish() override; // post-processing + + // Linkage symbol helpers + TIntermSymbol* findTessLinkageSymbol(TBuiltInVariable biType) const; // Current state of parsing - struct TPragma contextPragma; - int loopNestingLevel; // 0 if outside all loops - int structNestingLevel; // 0 if outside blocks and structures - int controlFlowNestingLevel; // 0 if outside all flow control - TList switchSequenceStack; // case, node, case, case, node, ...; ensure only one node between cases; stack of them for nesting - bool inEntrypoint; // if inside a function, true if the function is the entry point - bool postMainReturn; // if inside a function, true if the function is the entry point and this is after a return statement - const TType* currentFunctionType; // the return type of the function that's currently being parsed - bool functionReturnsValue; // true if a non-void function has a return - const TString* blockName; - TQualifier currentBlockQualifier; - TBuiltInResource resources; - TLimits& limits; + int annotationNestingLevel; // 0 if outside all annotations HlslParseContext(HlslParseContext&); HlslParseContext& operator=(HlslParseContext&); - TMap extensionBehavior; // for each extension string, what its current behavior is set to static const int maxSamplerIndex = EsdNumDims * (EbtNumTypes * (2 * 2 * 2)); // see computeSamplerTypeIndex() - bool afterEOF; TQualifier globalBufferDefaults; TQualifier globalUniformDefaults; TQualifier globalInputDefaults; @@ -221,15 +373,136 @@ protected: // * note, that appropriately gives an error if redeclaring a block that // was already used and hence already copied-up // - // - on seeing a layout declaration that sizes the array, fix everything in the + // - on seeing a layout declaration that sizes the array, fix everything in the // resize-list, giving errors for mismatch // // - on seeing an array size declaration, give errors on mismatch between it and previous // array-sizing declarations // TVector ioArraySymbolResizeList; + + TMap flattenMap; + + // IO-type map. Maps a pure symbol-table form of a structure-member list into + // each of the (up to) three kinds of IO, as each as different allowed decorations, + // but HLSL allows mixing all in the same structure. + struct tIoKinds { + TTypeList* input; + TTypeList* output; + TTypeList* uniform; + }; + TMap ioTypeMap; + + // Structure splitting data: + TMap splitNonIoVars; // variables with the built-in interstage IO removed, indexed by unique ID. + + // Structuredbuffer shared types. Typically there are only a few. + TVector structBufferTypes; + + // This tracks texture sample user structure return types. Only a limited number are supported, as + // may fit in TSampler::structReturnIndex. + TVector textureReturnStruct; + + TMap structBufferCounter; // true if counter buffer is in use + + // The built-in interstage IO map considers e.g, EvqPosition on input and output separately, so that we + // can build the linkage correctly if position appears on both sides. Otherwise, multiple positions + // are considered identical. + struct tInterstageIoData { + tInterstageIoData(TBuiltInVariable bi, TStorageQualifier q) : + builtIn(bi), storage(q) { } + + TBuiltInVariable builtIn; + TStorageQualifier storage; + + // ordering for maps + bool operator<(const tInterstageIoData d) const { + return (builtIn != d.builtIn) ? (builtIn < d.builtIn) : (storage < d.storage); + } + }; + + TMap splitBuiltIns; // split built-ins, indexed by built-in type. + TVariable* inputPatch; // input patch is special for PCF: it's the only non-builtin PCF input, + // and is handled as a pseudo-builtin. + + unsigned int nextInLocation; + unsigned int nextOutLocation; + + TFunction* entryPointFunction; + TIntermNode* entryPointFunctionBody; + + TString patchConstantFunctionName; // hull shader patch constant function name, from function level attribute. + TMap builtInTessLinkageSymbols; // used for tessellation, finding declared built-ins + + TVector currentTypePrefix; // current scoping prefix for nested structures + TVector implicitThisStack; // currently active 'this' variables for nested structures + + TVariable* gsStreamOutput; // geometry shader stream outputs, for emit (Append method) + + TVariable* clipDistanceOutput; // synthesized clip distance out variable (shader might have >1) + TVariable* cullDistanceOutput; // synthesized cull distance out variable (shader might have >1) + TVariable* clipDistanceInput; // synthesized clip distance in variable (shader might have >1) + TVariable* cullDistanceInput; // synthesized cull distance in variable (shader might have >1) + + static const int maxClipCullRegs = 2; + std::array clipSemanticNSizeIn; // vector, indexed by clip semantic ID + std::array cullSemanticNSizeIn; // vector, indexed by cull semantic ID + std::array clipSemanticNSizeOut; // vector, indexed by clip semantic ID + std::array cullSemanticNSizeOut; // vector, indexed by cull semantic ID + + // This tracks the first (mip level) argument to the .mips[][] operator. Since this can be nested as + // in tx.mips[tx.mips[0][1].x][2], we need a stack. We also track the TSourceLoc for error reporting + // purposes. + struct tMipsOperatorData { + tMipsOperatorData(TSourceLoc l, TIntermTyped* m) : loc(l), mipLevel(m) { } + TSourceLoc loc; + TIntermTyped* mipLevel; + }; + + TVector mipsOperatorMipArg; + + // The geometry output stream is not copied out from the entry point as a typical output variable + // is. It's written via EmitVertex (hlsl=Append), which may happen in arbitrary control flow. + // For this we need the real output symbol. Since it may not be known at the time and Append() + // method is parsed, the sequence will be patched during finalization. + struct tGsAppendData { + TIntermAggregate* node; + TSourceLoc loc; + }; + + TVector gsAppends; + + // A texture object may be used with shadow and non-shadow samplers, but both may not be + // alive post-DCE in the same shader. We do not know at compilation time which are alive: that's + // only known post-DCE. If a texture is used both ways, we create two textures, and + // leave the elimiation of one to the optimizer. This maps the shader variant to + // the shadow variant. + // + // This can be removed if and when the texture shadow code in + // HlslParseContext::handleSamplerTextureCombine is removed. + struct tShadowTextureSymbols { + tShadowTextureSymbols() { symId.fill(-1); } + + void set(bool shadow, int id) { symId[int(shadow)] = id; } + int get(bool shadow) const { return symId[int(shadow)]; } + + // True if this texture has been seen with both shadow and non-shadow modes + bool overloaded() const { return symId[0] != -1 && symId[1] != -1; } + bool isShadowId(int id) const { return symId[1] == id; } + + private: + std::array symId; + }; + + TMap textureShadowVariant; }; +// This is the prefix we use for built-in methods to avoid namespace collisions with +// global scope user functions. +// TODO: this would be better as a nonparseable character, but that would +// require changing the scanner. +#define BUILTIN_PREFIX "__BI_" + } // end namespace glslang #endif // HLSL_PARSE_INCLUDED_ diff --git a/Externals/glslang/hlsl/hlslParseables.cpp b/Externals/glslang/hlsl/hlslParseables.cpp index 61b176b809..cc847ae22f 100755 --- a/Externals/glslang/hlsl/hlslParseables.cpp +++ b/Externals/glslang/hlsl/hlslParseables.cpp @@ -1,11 +1,11 @@ // -//Copyright (C) 2016 LunarG, Inc. +// Copyright (C) 2016 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,22 +19,22 @@ // 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. +// 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. // // -// Create strings that declare built-in definitions, add built-ins programmatically +// Create strings that declare built-in definitions, add built-ins programmatically // that cannot be expressed in the strings, and establish mappings between // built-in functions and operators. // @@ -49,13 +49,14 @@ // #include "hlslParseables.h" +#include "hlslParseHelper.h" #include #include #include namespace { // anonymous namespace functions -const bool UseHlslTypes = false; +const bool UseHlslTypes = true; const char* BaseTypeName(const char argOrder, const char* scalarName, const char* vecName, const char* matName) { @@ -67,44 +68,154 @@ const char* BaseTypeName(const char argOrder, const char* scalarName, const char } } -bool IsTextureType(const char argOrder) { return argOrder == '%' || argOrder == '@'; } -bool IsTextureArrayed(const char argOrder) { return argOrder == '@'; } -bool IsTextureMS(const char /*argOrder*/) { return false; } // TODO: ... +// arg order queries +bool IsSamplerType(const char argType) { return argType == 'S' || argType == 's'; } +bool IsArrayed(const char argOrder) { return argOrder == '@' || argOrder == '&' || argOrder == '#'; } +bool IsTextureNonMS(const char argOrder) { return argOrder == '%'; } +bool IsSubpassInput(const char argOrder) { return argOrder == '[' || argOrder == ']'; } +bool IsArrayedTexture(const char argOrder) { return argOrder == '@'; } +bool IsTextureMS(const char argOrder) { return argOrder == '$' || argOrder == '&'; } +bool IsMS(const char argOrder) { return IsTextureMS(argOrder) || argOrder == ']'; } +bool IsBuffer(const char argOrder) { return argOrder == '*' || argOrder == '~'; } +bool IsImage(const char argOrder) { return argOrder == '!' || argOrder == '#' || argOrder == '~'; } + +bool IsTextureType(const char argOrder) +{ + return IsTextureNonMS(argOrder) || IsArrayedTexture(argOrder) || + IsTextureMS(argOrder) || IsBuffer(argOrder) || IsImage(argOrder); +} // Reject certain combinations that are illegal sample methods. For example, // 3D arrays. bool IsIllegalSample(const glslang::TString& name, const char* argOrder, int dim0) { - const bool isArrayed = IsTextureArrayed(*argOrder); + const bool isArrayed = IsArrayed(*argOrder); const bool isMS = IsTextureMS(*argOrder); + const bool isBuffer = IsBuffer(*argOrder); - // there are no 3D arrayed textures, or 3D SampleCmp - if (dim0 == 3 && (isArrayed || name == "SampleCmp")) + // there are no 3D arrayed textures, or 3D SampleCmp(LevelZero) + if (dim0 == 3 && (isArrayed || name == "SampleCmp" || name == "SampleCmpLevelZero")) return true; const int numArgs = int(std::count(argOrder, argOrder + strlen(argOrder), ',')) + 1; - // Reject invalid offset arrayed forms with cubemaps - if (isArrayed && dim0 == 4) { + // Reject invalid offset forms with cubemaps + if (dim0 == 4) { if ((name == "Sample" && numArgs >= 4) || (name == "SampleBias" && numArgs >= 5) || (name == "SampleCmp" && numArgs >= 5) || - (name == "SampleCmpLevelZero" && numArgs >= 4) || + (name == "SampleCmpLevelZero" && numArgs >= 5) || (name == "SampleGrad" && numArgs >= 6) || (name == "SampleLevel" && numArgs >= 5)) return true; } - // Reject invalid Loads - if (name == "Load") { - if ((numArgs >= 3 && !isMS) || // Load with sampleindex requires multisample - (dim0 == 4)) // Load does not support any cubemaps, arrayed or not. + const bool isGather = + (name == "Gather" || + name == "GatherRed" || + name == "GatherGreen" || + name == "GatherBlue" || + name == "GatherAlpha"); + + const bool isGatherCmp = + (name == "GatherCmp" || + name == "GatherCmpRed" || + name == "GatherCmpGreen" || + name == "GatherCmpBlue" || + name == "GatherCmpAlpha"); + + // Reject invalid Gathers + if (isGather || isGatherCmp) { + if (dim0 == 1 || dim0 == 3) // there are no 1D or 3D gathers return true; + + // no offset on cube or cube array gathers + if (dim0 == 4) { + if ((isGather && numArgs > 3) || (isGatherCmp && numArgs > 4)) + return true; + } } + // Reject invalid Loads + if (name == "Load" && dim0 == 4) + return true; // Load does not support any cubemaps, arrayed or not. + + // Multisample formats are only 2D and 2Darray + if (isMS && dim0 != 2) + return true; + + // Buffer are only 1D + if (isBuffer && dim0 != 1) + return true; + return false; } - + +// Return the number of the coordinate arg, if any +int CoordinateArgPos(const glslang::TString& name, bool isTexture) +{ + if (!isTexture || (name == "GetDimensions")) + return -1; // has none + else if (name == "Load") + return 1; + else + return 2; // other texture methods are 2 +} + +// Some texture methods use an addition coordinate dimension for the mip +bool HasMipInCoord(const glslang::TString& name, bool isMS, bool isBuffer, bool isImage) +{ + return name == "Load" && !isMS && !isBuffer && !isImage; +} + +// LOD calculations don't pass the array level in the coordinate. +bool NoArrayCoord(const glslang::TString& name) +{ + return name == "CalculateLevelOfDetail" || name == "CalculateLevelOfDetailUnclamped"; +} + +// Handle IO params marked with > or < +const char* IoParam(glslang::TString& s, const char* nthArgOrder) +{ + if (*nthArgOrder == '>') { // output params + ++nthArgOrder; + s.append("out "); + } else if (*nthArgOrder == '<') { // input params + ++nthArgOrder; + s.append("in "); + } + + return nthArgOrder; +} + +// Handle repeated args +void HandleRepeatArg(const char*& arg, const char*& prev, const char* current) +{ + if (*arg == ',' || *arg == '\0') + arg = prev; + else + prev = current; +} + +// Return true for the end of a single argument key, which can be the end of the string, or +// the comma separator. +inline bool IsEndOfArg(const char* arg) +{ + return arg == nullptr || *arg == '\0' || *arg == ','; +} + +// If this is a fixed vector size, such as V3, return the size. Else return 0. +int FixedVecSize(const char* arg) +{ + while (!IsEndOfArg(arg)) { + if (isdigit(*arg)) + return *arg - '0'; + ++arg; + } + + return 0; // none found. +} + // Create and return a type name. This is done in GLSL, not HLSL conventions, until such // time as builtins are parsed using the HLSL parser. // @@ -115,22 +226,19 @@ bool IsIllegalSample(const glslang::TString& name, const char* argOrder, int dim glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, const char* argType, int dim0, int dim1) { const bool isTranspose = (argOrder[0] == '^'); - const bool isMatMul = (argOrder[0] == '#'); const bool isTexture = IsTextureType(argOrder[0]); - const bool isArrayed = IsTextureArrayed(argOrder[0]); - //const bool isMS = IsTextureMS(argOrder[0]); + const bool isArrayed = IsArrayed(argOrder[0]); + const bool isSampler = IsSamplerType(argType[0]); + const bool isMS = IsMS(argOrder[0]); + const bool isBuffer = IsBuffer(argOrder[0]); + const bool isImage = IsImage(argOrder[0]); + const bool isSubpass = IsSubpassInput(argOrder[0]); - char order = *argOrder; char type = *argType; if (isTranspose) { // Take transpose of matrix dimensions - order = *++argOrder; - std::swap(dim0, dim1); - } else if (isMatMul) { - order = *++argOrder; - dim0 = dim1; // set vector dimension to mat col - } else if (isTexture) { - order = *++argOrder; + std::swap(dim0, dim1); + } else if (isTexture || isSubpass) { if (type == 'F') // map base type to texture of that type. type = 'T'; // e.g, int -> itexture, uint -> utexture, etc. else if (type == 'I') @@ -139,36 +247,62 @@ glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, cons type = 'u'; } + if (isTranspose) + ++argOrder; + + char order = *argOrder; + if (UseHlslTypes) { switch (type) { - case '-': s += "void"; break; - case 'F': s += "float"; break; - case 'D': s += "double"; break; - case 'I': s += "int"; break; - case 'U': s += "uint"; break; - case 'B': s += "bool"; break; - case 'S': s += "sampler"; break; - case 'T': s += "Texture"; break; - case 'i': s += "Texture "; break; - case 'u': s += "Texture "; break; - default: s += "UNKNOWN_TYPE"; break; + case '-': s += "void"; break; + case 'F': s += "float"; break; + case 'D': s += "double"; break; + case 'I': s += "int"; break; + case 'U': s += "uint"; break; + case 'L': s += "int64_t"; break; + case 'M': s += "uint64_t"; break; + case 'B': s += "bool"; break; + case 'S': s += "sampler"; break; + case 's': s += "SamplerComparisonState"; break; + case 'T': s += ((isBuffer && isImage) ? "RWBuffer" : + isSubpass ? "SubpassInput" : + isBuffer ? "Buffer" : + isImage ? "RWTexture" : "Texture"); break; + case 'i': s += ((isBuffer && isImage) ? "RWBuffer" : + isSubpass ? "SubpassInput" : + isBuffer ? "Buffer" : + isImage ? "RWTexture" : "Texture"); break; + case 'u': s += ((isBuffer && isImage) ? "RWBuffer" : + isSubpass ? "SubpassInput" : + isBuffer ? "Buffer" : + isImage ? "RWTexture" : "Texture"); break; + default: s += "UNKNOWN_TYPE"; break; } + + if (isSubpass && isMS) + s += "MS"; + } else { switch (type) { case '-': s += "void"; break; - case 'F': s += BaseTypeName(order, "float", "vec", "mat"); break; - case 'D': s += BaseTypeName(order, "double", "dvec", "dmat"); break; - case 'I': s += BaseTypeName(order, "int", "ivec", "imat"); break; - case 'U': s += BaseTypeName(order, "uint", "uvec", "umat"); break; - case 'B': s += BaseTypeName(order, "bool", "bvec", "bmat"); break; - case 'S': s += "sampler"; break; + case 'F': s += BaseTypeName(order, "float", "vec", "mat"); break; + case 'D': s += BaseTypeName(order, "double", "dvec", "dmat"); break; + case 'I': s += BaseTypeName(order, "int", "ivec", "imat"); break; + case 'U': s += BaseTypeName(order, "uint", "uvec", "umat"); break; + case 'B': s += BaseTypeName(order, "bool", "bvec", "bmat"); break; + case 'S': s += "sampler"; break; + case 's': s += "samplerShadow"; break; case 'T': // fall through case 'i': // ... case 'u': // ... - if (type != 'T') + if (type != 'T') // create itexture, utexture, etc s += type; - s += "texture"; + s += ((isImage && isBuffer) ? "imageBuffer" : + isSubpass ? "subpassInput" : + isImage ? "image" : + isBuffer ? "samplerBuffer" : + "texture"); break; default: s += "UNKNOWN_TYPE"; break; @@ -176,19 +310,22 @@ glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, cons } // handle fixed vector sizes, such as float3, and only ever 3. - const int fixedVecSize = isdigit(argOrder[1]) ? (argOrder[1] - '0') : 0; + const int fixedVecSize = FixedVecSize(argOrder); if (fixedVecSize != 0) dim0 = dim1 = fixedVecSize; + const char dim0Char = ('0' + char(dim0)); + const char dim1Char = ('0' + char(dim1)); + // Add sampler dimensions - if (type == 'S' || isTexture) { - if (order == 'V') { + if (isSampler || isTexture) { + if ((order == 'V' || isTexture) && !isBuffer) { switch (dim0) { - case 1: s += "1D"; break; - case 2: s += "2D"; break; - case 3: s += "3D"; break; - case 4: s += "Cube"; break; - default: s += "UNKNOWN_SAMPLER"; break; + case 1: s += "1D"; break; + case 2: s += (isMS ? "2DMS" : "2D"); break; + case 3: s += "3D"; break; + case 4: s += "Cube"; break; + default: s += "UNKNOWN_SAMPLER"; break; } } } else { @@ -203,16 +340,16 @@ glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, cons switch (order) { case '-': break; // no dimensions for voids case 'S': break; // no dimensions on scalars - case 'V': s += ('0' + char(dim0)); break; - case 'M': - { - if (!UseHlslTypes) // GLSL has column first for mat types - std::swap(dim0, dim1); - s += ('0' + char(dim0)); - s += 'x'; - s += ('0' + char(dim1)); - break; - } + case 'V': + s += dim0Char; + break; + case 'M': + s += dim0Char; + s += 'x'; + s += dim1Char; + break; + default: + break; } } @@ -220,49 +357,59 @@ glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, cons if (isArrayed) s += "Array"; + // For HLSL, append return type for texture types + if (UseHlslTypes) { + switch (type) { + case 'i': s += " 1 || argType == 'V'; - const bool isMat = dim1Max > 1 || argType == 'M'; + const bool isVec = (argOrder == 'V'); + const bool isMat = (argOrder == 'M'); - if (!IsTextureType(argOrder) && - ((isVec && dim0 == 1) || // avoid vec1 - (isMat && dim0 == 1 && dim1 == 1))) // avoid mat1x1 + const std::string name(cname); + + // these do not have vec1 versions + if (dim0 == 1 && (name == "normalize" || name == "reflect" || name == "refract")) return false; - const std::string name(cname); // for ease of comparison. slow, but temporary, until HLSL parser is online. - - if (isMat && dim1 == 1) // TODO: avoid mat Nx1 until we find the right GLSL profile + if (!IsTextureType(argOrder) && (isVec && dim0 == 1)) // avoid vec1 return false; - if ((isMat && (argType == 'I' || argType == 'U' || argType == 'B')) || - (retOrder == 'M' && (retType == 'I' || retType == 'U' || retType == 'B'))) - return false; + if (UseHlslTypes) { + // NO further restrictions for HLSL + } else { + // GLSL parser restrictions + if ((isMat && (argType == 'I' || argType == 'U' || argType == 'B')) || + (retOrder == 'M' && (retType == 'I' || retType == 'U' || retType == 'B'))) + return false; - if (name == "GetRenderTargetSamplePosition" || - name == "tex1D" || - name == "tex1Dgrad") - return false; + if (isMat && dim0 == 1 && dim1 == 1) // avoid mat1x1 + return false; + + if (isMat && dim1 == 1) // TODO: avoid mat Nx1 until we find the right GLSL profile + return false; + + if (name == "GetRenderTargetSamplePosition" || + name == "tex1D" || + name == "tex1Dgrad") + return false; + } return true; } - -// Return true for the end of a single argument key, which can be the end of the string, or -// the comma separator. -inline bool IsEndOfArg(const char* arg) -{ - return arg == nullptr || *arg == '\0' || *arg == ','; -} - - // return position of end of argument specifier inline const char* FindEndOfArg(const char* arg) { @@ -272,7 +419,6 @@ inline const char* FindEndOfArg(const char* arg) return *arg == '\0' ? nullptr : arg; } - // Return pointer to beginning of Nth argument specifier in the string. inline const char* NthArg(const char* arg, int n) { @@ -289,7 +435,7 @@ inline void FindVectorMatrixBounds(const char* argOrder, int fixedVecSize, int& const char* nthArgOrder(NthArg(argOrder, arg)); if (nthArgOrder == nullptr) break; - else if (*nthArgOrder == 'V') + else if (*nthArgOrder == 'V' || IsSubpassInput(*nthArgOrder)) dim0Max = 4; else if (*nthArgOrder == 'M') dim0Max = dim1Max = 4; @@ -298,7 +444,7 @@ inline void FindVectorMatrixBounds(const char* argOrder, int fixedVecSize, int& if (fixedVecSize > 0) // handle fixed sized vectors dim0Min = dim0Max = fixedVecSize; } - + } // end anonymous namespace namespace glslang { @@ -307,7 +453,6 @@ TBuiltInParseablesHlsl::TBuiltInParseablesHlsl() { } - // // Handle creation of mat*mat specially, since it doesn't fall conveniently out of // the generic prototype creation code below. @@ -325,6 +470,7 @@ void TBuiltInParseablesHlsl::createMatTimesMat() const int retRows = xRows; const int retCols = yCols; + // Create a mat * mat of the appropriate dimensions AppendTypeName(s, "M", "F", retRows, retCols); // add return type s.append(" "); // space between type and name s.append("mul"); // intrinsic name @@ -336,6 +482,30 @@ void TBuiltInParseablesHlsl::createMatTimesMat() s.append(");\n"); // close paren } + + // Create M*V + AppendTypeName(s, "V", "F", xRows, 1); // add return type + s.append(" "); // space between type and name + s.append("mul"); // intrinsic name + s.append("("); // open paren + + AppendTypeName(s, "M", "F", xRows, xCols); // add X input + s.append(", "); + AppendTypeName(s, "V", "F", xCols, 1); // add Y input + + s.append(");\n"); // close paren + + // Create V*M + AppendTypeName(s, "V", "F", xCols, 1); // add return type + s.append(" "); // space between type and name + s.append("mul"); // intrinsic name + s.append("("); // open paren + + AppendTypeName(s, "V", "F", xRows, 1); // add Y input + s.append(", "); + AppendTypeName(s, "M", "F", xRows, xCols); // add X input + + s.append(");\n"); // close paren } } } @@ -350,21 +520,45 @@ void TBuiltInParseablesHlsl::createMatTimesMat() // void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, const SpvVersion& /*spvVersion*/) { - static const EShLanguageMask EShLangAll = EShLanguageMask(EShLangCount - 1); + static const EShLanguageMask EShLangAll = EShLanguageMask(EShLangCount - 1); + + // These are the actual stage masks defined in the documentation, in case they are + // needed for future validation. For now, they are commented out, and set below + // to EShLangAll, to allow any intrinsic to be used in any shader, which is legal + // if it is not called. + // + // static const EShLanguageMask EShLangPSCS = EShLanguageMask(EShLangFragmentMask | EShLangComputeMask); + // static const EShLanguageMask EShLangVSPSGS = EShLanguageMask(EShLangVertexMask | EShLangFragmentMask | EShLangGeometryMask); + // static const EShLanguageMask EShLangCS = EShLangComputeMask; + // static const EShLanguageMask EShLangPS = EShLangFragmentMask; + // static const EShLanguageMask EShLangHS = EShLangTessControlMask; + + // This set uses EShLangAll for everything. + static const EShLanguageMask EShLangPSCS = EShLangAll; + static const EShLanguageMask EShLangVSPSGS = EShLangAll; + static const EShLanguageMask EShLangCS = EShLangAll; + static const EShLanguageMask EShLangPS = EShLangAll; + static const EShLanguageMask EShLangHS = EShLangAll; + static const EShLanguageMask EShLangGS = EShLangAll; // This structure encodes the prototype information for each HLSL intrinsic. // Because explicit enumeration would be cumbersome, it's procedurally generated. // orderKey can be: // S = scalar, V = vector, M = matrix, - = void // typekey can be: - // D = double, F = float, U = uint, I = int, B = bool, S = sampler + // D = double, F = float, U = uint, I = int, B = bool, S = sampler, s = shadowSampler, M = uint64_t, L = int64_t // An empty order or type key repeats the first one. E.g: SVM,, means 3 args each of SVM. // '>' as first letter of order creates an output parameter // '<' as first letter of order creates an input parameter // '^' as first letter of order takes transpose dimensions - // '#' as first letter of order sets rows=cols for mats // '%' as first letter of order creates texture of given F/I/U type (texture, itexture, etc) // '@' as first letter of order creates arrayed texture of given type + // '$' / '&' as first letter of order creates 2DMS / 2DMSArray textures + // '*' as first letter of order creates buffer object + // '!' as first letter of order creates image object + // '#' as first letter of order creates arrayed image object + // '~' as first letter of order creates an image buffer object + // '[' / ']' as first letter of order creates a SubpassInput/SubpassInputMS object static const struct { const char* name; // intrinsic name @@ -373,212 +567,380 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c const char* argOrder; // argument order key const char* argType; // argument type key unsigned int stage; // stage mask + bool method; // true if it's a method. } hlslIntrinsics[] = { - // name retOrd retType argOrder argType stage mask - // ----------------------------------------------------------------------------------------------- - { "abort", nullptr, nullptr, "-", "-", EShLangAll }, - { "abs", nullptr, nullptr, "SVM", "DFUI", EShLangAll }, - { "acos", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "all", "S", "B", "SVM", "BFI", EShLangAll }, - { "AllMemoryBarrier", nullptr, nullptr, "-", "-", EShLangComputeMask }, - { "AllMemoryBarrierWithGroupSync", nullptr, nullptr, "-", "-", EShLangComputeMask }, - { "any", "S", "B", "SVM", "BFI", EShLangAll }, - { "asdouble", "S", "D", "S,", "U,", EShLangAll }, - { "asdouble", "V2", "D", "V2,", "U,", EShLangAll }, - { "asfloat", nullptr, "F", "SVM", "BFIU", EShLangAll }, - { "asin", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "asint", nullptr, "I", "SVM", "FU", EShLangAll }, - { "asuint", nullptr, "U", "SVM", "FU", EShLangAll }, - { "atan", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "atan2", nullptr, nullptr, "SVM,", "F,", EShLangAll }, - { "ceil", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "CheckAccessFullyMapped", "S", "B" , "S", "U", EShLangFragmentMask | EShLangComputeMask }, - { "clamp", nullptr, nullptr, "SVM,,", "FUI,,", EShLangAll }, - { "clip", "-", "-", "SVM", "F", EShLangFragmentMask }, - { "cos", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "cosh", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "countbits", nullptr, nullptr, "SV", "U", EShLangAll }, - { "cross", nullptr, nullptr, "V3,", "F,", EShLangAll }, - { "D3DCOLORtoUBYTE4", "V4", "I", "V4", "F", EShLangAll }, - { "ddx", nullptr, nullptr, "SVM", "F", EShLangFragmentMask }, - { "ddx_coarse", nullptr, nullptr, "SVM", "F", EShLangFragmentMask }, - { "ddx_fine", nullptr, nullptr, "SVM", "F", EShLangFragmentMask }, - { "ddy", nullptr, nullptr, "SVM", "F", EShLangFragmentMask }, - { "ddy_coarse", nullptr, nullptr, "SVM", "F", EShLangFragmentMask }, - { "ddy_fine", nullptr, nullptr, "SVM", "F", EShLangFragmentMask }, - { "degrees", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "determinant", "S", "F", "M", "F", EShLangAll }, - { "DeviceMemoryBarrier", nullptr, nullptr, "-", "-", EShLangFragmentMask | EShLangComputeMask }, - { "DeviceMemoryBarrierWithGroupSync", nullptr, nullptr, "-", "-", EShLangComputeMask }, - { "distance", "S", "F", "V,", "F,", EShLangAll }, - { "dot", "S", nullptr, "V,", "FI,", EShLangAll }, - { "dst", nullptr, nullptr, "V4,V4", "F,", EShLangAll }, - // { "errorf", "-", "-", "", "", EShLangAll }, TODO: varargs - { "EvaluateAttributeAtCentroid", nullptr, nullptr, "SVM", "F", EShLangFragmentMask }, - { "EvaluateAttributeAtSample", nullptr, nullptr, "SVM,S", "F,U", EShLangFragmentMask }, - { "EvaluateAttributeSnapped", nullptr, nullptr, "SVM,V2", "F,I", EShLangFragmentMask }, - { "exp", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "exp2", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "f16tof32", nullptr, "F", "SV", "U", EShLangAll }, - { "f32tof16", nullptr, "U", "SV", "F", EShLangAll }, - { "faceforward", nullptr, nullptr, "V,,", "F,,", EShLangAll }, - { "firstbithigh", nullptr, nullptr, "SV", "UI", EShLangAll }, - { "firstbitlow", nullptr, nullptr, "SV", "UI", EShLangAll }, - { "floor", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "fma", nullptr, nullptr, "SVM,,", "D,,", EShLangAll }, - { "fmod", nullptr, nullptr, "SVM,", "F,", EShLangAll }, - { "frac", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "frexp", nullptr, nullptr, "SVM,", "F,", EShLangAll }, - { "fwidth", nullptr, nullptr, "SVM", "F", EShLangFragmentMask }, - { "GetRenderTargetSampleCount", "S", "U", "-", "-", EShLangAll }, - { "GetRenderTargetSamplePosition", "V2", "F", "V1", "I", EShLangAll }, - { "GroupMemoryBarrier", nullptr, nullptr, "-", "-", EShLangComputeMask }, - { "GroupMemoryBarrierWithGroupSync", nullptr, nullptr, "-", "-", EShLangComputeMask }, - { "InterlockedAdd", "-", "-", "SVM,,>", "UI,,", EShLangFragmentMask | EShLangComputeMask }, - { "InterlockedAdd", "-", "-", "SVM,", "UI,", EShLangFragmentMask | EShLangComputeMask }, - { "InterlockedAnd", "-", "-", "SVM,,>", "UI,,", EShLangFragmentMask | EShLangComputeMask }, - { "InterlockedAnd", "-", "-", "SVM,", "UI,", EShLangFragmentMask | EShLangComputeMask }, - { "InterlockedCompareExchange", "-", "-", "SVM,,,>", "UI,,,", EShLangFragmentMask | EShLangComputeMask }, - { "InterlockedCompareStore", "-", "-", "SVM,,", "UI,,", EShLangFragmentMask | EShLangComputeMask }, - { "InterlockedExchange", "-", "-", "SVM,,>", "UI,,", EShLangFragmentMask | EShLangComputeMask }, - { "InterlockedMax", "-", "-", "SVM,,>", "UI,,", EShLangFragmentMask | EShLangComputeMask }, - { "InterlockedMax", "-", "-", "SVM,", "UI,", EShLangFragmentMask | EShLangComputeMask }, - { "InterlockedMin", "-", "-", "SVM,,>", "UI,,", EShLangFragmentMask | EShLangComputeMask }, - { "InterlockedMin", "-", "-", "SVM,", "UI,", EShLangFragmentMask | EShLangComputeMask }, - { "InterlockedOr", "-", "-", "SVM,,>", "UI,,", EShLangFragmentMask | EShLangComputeMask }, - { "InterlockedOr", "-", "-", "SVM,", "UI,", EShLangFragmentMask | EShLangComputeMask }, - { "InterlockedXor", "-", "-", "SVM,,>", "UI,,", EShLangFragmentMask | EShLangComputeMask }, - { "InterlockedXor", "-", "-", "SVM,", "UI,", EShLangFragmentMask | EShLangComputeMask }, - { "isfinite", nullptr, "B" , "SVM", "F", EShLangAll }, - { "isinf", nullptr, "B" , "SVM", "F", EShLangAll }, - { "isnan", nullptr, "B" , "SVM", "F", EShLangAll }, - { "ldexp", nullptr, nullptr, "SVM,", "F,", EShLangAll }, - { "length", "S", "F", "V", "F", EShLangAll }, - { "lerp", nullptr, nullptr, "SVM,,", "F,,", EShLangAll }, - { "lit", "V4", "F", "S,,", "F,,", EShLangAll }, - { "log", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "log10", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "log2", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "mad", nullptr, nullptr, "SVM,,", "DFUI,,", EShLangAll }, - { "max", nullptr, nullptr, "SVM,", "FI,", EShLangAll }, - { "min", nullptr, nullptr, "SVM,", "FI,", EShLangAll }, - { "modf", nullptr, nullptr, "SVM,>", "FI,", EShLangAll }, - { "msad4", "V4", "U", "S,V2,V4", "U,,", EShLangAll }, - { "mul", "S", nullptr, "S,S", "FI,", EShLangAll }, - { "mul", "V", nullptr, "S,V", "FI,", EShLangAll }, - { "mul", "M", nullptr, "S,M", "FI,", EShLangAll }, - { "mul", "V", nullptr, "V,S", "FI,", EShLangAll }, - { "mul", "S", nullptr, "V,V", "FI,", EShLangAll }, - { "mul", "#V", nullptr, "V,M", "FI,", EShLangAll }, - { "mul", "M", nullptr, "M,S", "FI,", EShLangAll }, - { "mul", "V", nullptr, "M,#V", "FI,", EShLangAll }, + // name retOrd retType argOrder argType stage mask method + // ---------------------------------------------------------------------------------------------------------------- + { "abort", nullptr, nullptr, "-", "-", EShLangAll, false }, + { "abs", nullptr, nullptr, "SVM", "DFUI", EShLangAll, false }, + { "acos", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "all", "S", "B", "SVM", "BFIU", EShLangAll, false }, + { "AllMemoryBarrier", nullptr, nullptr, "-", "-", EShLangCS, false }, + { "AllMemoryBarrierWithGroupSync", nullptr, nullptr, "-", "-", EShLangCS, false }, + { "any", "S", "B", "SVM", "BFIU", EShLangAll, false }, + { "asdouble", "S", "D", "S,", "UI,", EShLangAll, false }, + { "asdouble", "V2", "D", "V2,", "UI,", EShLangAll, false }, + { "asfloat", nullptr, "F", "SVM", "BFIU", EShLangAll, false }, + { "asin", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "asint", nullptr, "I", "SVM", "FIU", EShLangAll, false }, + { "asuint", nullptr, "U", "SVM", "FIU", EShLangAll, false }, + { "atan", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "atan2", nullptr, nullptr, "SVM,", "F,", EShLangAll, false }, + { "ceil", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "CheckAccessFullyMapped", "S", "B" , "S", "U", EShLangPSCS, false }, + { "clamp", nullptr, nullptr, "SVM,,", "FUI,,", EShLangAll, false }, + { "clip", "-", "-", "SVM", "FUI", EShLangPS, false }, + { "cos", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "cosh", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "countbits", nullptr, nullptr, "SV", "UI", EShLangAll, false }, + { "cross", nullptr, nullptr, "V3,", "F,", EShLangAll, false }, + { "D3DCOLORtoUBYTE4", "V4", "I", "V4", "F", EShLangAll, false }, + { "ddx", nullptr, nullptr, "SVM", "F", EShLangPS, false }, + { "ddx_coarse", nullptr, nullptr, "SVM", "F", EShLangPS, false }, + { "ddx_fine", nullptr, nullptr, "SVM", "F", EShLangPS, false }, + { "ddy", nullptr, nullptr, "SVM", "F", EShLangPS, false }, + { "ddy_coarse", nullptr, nullptr, "SVM", "F", EShLangPS, false }, + { "ddy_fine", nullptr, nullptr, "SVM", "F", EShLangPS, false }, + { "degrees", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "determinant", "S", "F", "M", "F", EShLangAll, false }, + { "DeviceMemoryBarrier", nullptr, nullptr, "-", "-", EShLangPSCS, false }, + { "DeviceMemoryBarrierWithGroupSync", nullptr, nullptr, "-", "-", EShLangCS, false }, + { "distance", "S", "F", "V,", "F,", EShLangAll, false }, + { "dot", "S", nullptr, "SV,", "FI,", EShLangAll, false }, + { "dst", nullptr, nullptr, "V4,", "F,", EShLangAll, false }, + // { "errorf", "-", "-", "", "", EShLangAll, false }, TODO: varargs + { "EvaluateAttributeAtCentroid", nullptr, nullptr, "SVM", "F", EShLangPS, false }, + { "EvaluateAttributeAtSample", nullptr, nullptr, "SVM,S", "F,U", EShLangPS, false }, + { "EvaluateAttributeSnapped", nullptr, nullptr, "SVM,V2", "F,I", EShLangPS, false }, + { "exp", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "exp2", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "f16tof32", nullptr, "F", "SV", "U", EShLangAll, false }, + { "f32tof16", nullptr, "U", "SV", "F", EShLangAll, false }, + { "faceforward", nullptr, nullptr, "V,,", "F,,", EShLangAll, false }, + { "firstbithigh", nullptr, nullptr, "SV", "UI", EShLangAll, false }, + { "firstbitlow", nullptr, nullptr, "SV", "UI", EShLangAll, false }, + { "floor", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "fma", nullptr, nullptr, "SVM,,", "D,,", EShLangAll, false }, + { "fmod", nullptr, nullptr, "SVM,", "F,", EShLangAll, false }, + { "frac", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "frexp", nullptr, nullptr, "SVM,", "F,", EShLangAll, false }, + { "fwidth", nullptr, nullptr, "SVM", "F", EShLangPS, false }, + { "GetRenderTargetSampleCount", "S", "U", "-", "-", EShLangAll, false }, + { "GetRenderTargetSamplePosition", "V2", "F", "V1", "I", EShLangAll, false }, + { "GroupMemoryBarrier", nullptr, nullptr, "-", "-", EShLangCS, false }, + { "GroupMemoryBarrierWithGroupSync", nullptr, nullptr, "-", "-", EShLangCS, false }, + { "InterlockedAdd", "-", "-", "SVM,,>", "UI,,", EShLangPSCS, false }, + { "InterlockedAdd", "-", "-", "SVM,", "UI,", EShLangPSCS, false }, + { "InterlockedAnd", "-", "-", "SVM,,>", "UI,,", EShLangPSCS, false }, + { "InterlockedAnd", "-", "-", "SVM,", "UI,", EShLangPSCS, false }, + { "InterlockedCompareExchange", "-", "-", "SVM,,,>", "UI,,,", EShLangPSCS, false }, + { "InterlockedCompareStore", "-", "-", "SVM,,", "UI,,", EShLangPSCS, false }, + { "InterlockedExchange", "-", "-", "SVM,,>", "UI,,", EShLangPSCS, false }, + { "InterlockedMax", "-", "-", "SVM,,>", "UI,,", EShLangPSCS, false }, + { "InterlockedMax", "-", "-", "SVM,", "UI,", EShLangPSCS, false }, + { "InterlockedMin", "-", "-", "SVM,,>", "UI,,", EShLangPSCS, false }, + { "InterlockedMin", "-", "-", "SVM,", "UI,", EShLangPSCS, false }, + { "InterlockedOr", "-", "-", "SVM,,>", "UI,,", EShLangPSCS, false }, + { "InterlockedOr", "-", "-", "SVM,", "UI,", EShLangPSCS, false }, + { "InterlockedXor", "-", "-", "SVM,,>", "UI,,", EShLangPSCS, false }, + { "InterlockedXor", "-", "-", "SVM,", "UI,", EShLangPSCS, false }, + { "isfinite", nullptr, "B" , "SVM", "F", EShLangAll, false }, + { "isinf", nullptr, "B" , "SVM", "F", EShLangAll, false }, + { "isnan", nullptr, "B" , "SVM", "F", EShLangAll, false }, + { "ldexp", nullptr, nullptr, "SVM,", "F,", EShLangAll, false }, + { "length", "S", "F", "SV", "F", EShLangAll, false }, + { "lerp", nullptr, nullptr, "VM,,", "F,,", EShLangAll, false }, + { "lerp", nullptr, nullptr, "SVM,,S", "F,,", EShLangAll, false }, + { "lit", "V4", "F", "S,,", "F,,", EShLangAll, false }, + { "log", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "log10", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "log2", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "mad", nullptr, nullptr, "SVM,,", "DFUI,,", EShLangAll, false }, + { "max", nullptr, nullptr, "SVM,", "FIU,", EShLangAll, false }, + { "min", nullptr, nullptr, "SVM,", "FIU,", EShLangAll, false }, + { "modf", nullptr, nullptr, "SVM,>", "FIU,", EShLangAll, false }, + { "msad4", "V4", "U", "S,V2,V4", "U,,", EShLangAll, false }, + { "mul", "S", nullptr, "S,S", "FI,", EShLangAll, false }, + { "mul", "V", nullptr, "S,V", "FI,", EShLangAll, false }, + { "mul", "M", nullptr, "S,M", "FI,", EShLangAll, false }, + { "mul", "V", nullptr, "V,S", "FI,", EShLangAll, false }, + { "mul", "S", nullptr, "V,V", "FI,", EShLangAll, false }, + { "mul", "M", nullptr, "M,S", "FI,", EShLangAll, false }, // mat*mat form of mul is handled in createMatTimesMat() - { "noise", "S", "F", "V", "F", EShLangFragmentMask }, - { "normalize", nullptr, nullptr, "V", "F", EShLangAll }, - { "pow", nullptr, nullptr, "SVM,", "F,", EShLangAll }, - // { "printf", "-", "-", "", "", EShLangAll }, TODO: varargs - { "Process2DQuadTessFactorsAvg", "-", "-", "V4,V2,>V4,>V2,>V2", "F,,,,", EShLangTessControlMask }, - { "Process2DQuadTessFactorsMax", "-", "-", "V4,V2,>V4,>V2,>V2", "F,,,,", EShLangTessControlMask }, - { "Process2DQuadTessFactorsMin", "-", "-", "V4,V2,>V4,>V2,>V2", "F,,,,", EShLangTessControlMask }, - { "ProcessIsolineTessFactors", "-", "-", "S,,>,>", "F,,,", EShLangTessControlMask }, - { "ProcessQuadTessFactorsAvg", "-", "-", "V4,S,>V4,>V2,>V2", "F,,,,", EShLangTessControlMask }, - { "ProcessQuadTessFactorsMax", "-", "-", "V4,S,>V4,>V2,>V2", "F,,,,", EShLangTessControlMask }, - { "ProcessQuadTessFactorsMin", "-", "-", "V4,S,>V4,>V2,>V2", "F,,,,", EShLangTessControlMask }, - { "ProcessTriTessFactorsAvg", "-", "-", "V3,S,>V3,>S,>S", "F,,,,", EShLangTessControlMask }, - { "ProcessTriTessFactorsMax", "-", "-", "V3,S,>V3,>S,>S", "F,,,,", EShLangTessControlMask }, - { "ProcessTriTessFactorsMin", "-", "-", "V3,S,>V3,>S,>S", "F,,,,", EShLangTessControlMask }, - { "radians", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "rcp", nullptr, nullptr, "SVM", "FD", EShLangAll }, - { "reflect", nullptr, nullptr, "V,", "F,", EShLangAll }, - { "refract", nullptr, nullptr, "V,V,S", "F,,", EShLangAll }, - { "reversebits", nullptr, nullptr, "SV", "U", EShLangAll }, - { "round", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "rsqrt", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "saturate", nullptr, nullptr , "SVM", "F", EShLangAll }, - { "sign", nullptr, nullptr, "SVM", "FI", EShLangAll }, - { "sin", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "sincos", "-", "-", "SVM,>,>", "F,,", EShLangAll }, - { "sinh", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "smoothstep", nullptr, nullptr, "SVM,,", "F,,", EShLangAll }, - { "sqrt", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "step", nullptr, nullptr, "SVM,", "F,", EShLangAll }, - { "tan", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "tanh", nullptr, nullptr, "SVM", "F", EShLangAll }, - { "tex1D", "V4", "F", "V1,S", "S,F", EShLangFragmentMask }, - { "tex1D", "V4", "F", "V1,S,V1,V1", "S,F,F,F",EShLangFragmentMask }, - { "tex1Dbias", "V4", "F", "V1,V4", "S,F", EShLangFragmentMask }, - { "tex1Dgrad", "V4", "F", "V1,V1,V1,V1","S,F,F,F",EShLangFragmentMask }, - { "tex1Dlod", "V4", "F", "V1,V4", "S,F", EShLangFragmentMask }, - { "tex1Dproj", "V4", "F", "V1,V4", "S,F", EShLangFragmentMask }, - { "tex2D", "V4", "F", "V2,V2", "S,F", EShLangFragmentMask }, - { "tex2D", "V4", "F", "V2,V2,V2,V2","S,F,F,F",EShLangFragmentMask }, - { "tex2Dbias", "V4", "F", "V2,V4", "S,F", EShLangFragmentMask }, - { "tex2Dgrad", "V4", "F", "V2,V2,V2,V2","S,F,F,F",EShLangFragmentMask }, - { "tex2Dlod", "V4", "F", "V2,V4", "S,F", EShLangFragmentMask }, - { "tex2Dproj", "V4", "F", "V2,V4", "S,F", EShLangFragmentMask }, - { "tex3D", "V4", "F", "V3,V3", "S,F", EShLangFragmentMask }, - { "tex3D", "V4", "F", "V3,V3,V3,V3","S,F,F,F",EShLangFragmentMask }, - { "tex3Dbias", "V4", "F", "V3,V4", "S,F", EShLangFragmentMask }, - { "tex3Dgrad", "V4", "F", "V3,V3,V3,V3","S,F,F,F",EShLangFragmentMask }, - { "tex3Dlod", "V4", "F", "V3,V4", "S,F", EShLangFragmentMask }, - { "tex3Dproj", "V4", "F", "V3,V4", "S,F", EShLangFragmentMask }, - { "texCUBE", "V4", "F", "V4,V3", "S,F", EShLangFragmentMask }, - { "texCUBE", "V4", "F", "V4,V3,V3,V3","S,F,F,F",EShLangFragmentMask }, - { "texCUBEbias", "V4", "F", "V4,V4", "S,F", EShLangFragmentMask }, - { "texCUBEgrad", "V4", "F", "V4,V3,V3,V3","S,F,F,F",EShLangFragmentMask }, - { "texCUBElod", "V4", "F", "V4,V4", "S,F", EShLangFragmentMask }, - { "texCUBEproj", "V4", "F", "V4,V4", "S,F", EShLangFragmentMask }, - { "transpose", "^M", nullptr, "M", "F", EShLangAll }, - { "trunc", nullptr, nullptr, "SVM", "F", EShLangAll }, + { "noise", "S", "F", "V", "F", EShLangPS, false }, + { "normalize", nullptr, nullptr, "V", "F", EShLangAll, false }, + { "pow", nullptr, nullptr, "SVM,", "F,", EShLangAll, false }, + // { "printf", "-", "-", "", "", EShLangAll, false }, TODO: varargs + { "Process2DQuadTessFactorsAvg", "-", "-", "V4,V2,>V4,>V2,", "F,,,,", EShLangHS, false }, + { "Process2DQuadTessFactorsMax", "-", "-", "V4,V2,>V4,>V2,", "F,,,,", EShLangHS, false }, + { "Process2DQuadTessFactorsMin", "-", "-", "V4,V2,>V4,>V2,", "F,,,,", EShLangHS, false }, + { "ProcessIsolineTessFactors", "-", "-", "S,,>,>", "F,,,", EShLangHS, false }, + { "ProcessQuadTessFactorsAvg", "-", "-", "V4,S,>V4,>V2,", "F,,,,", EShLangHS, false }, + { "ProcessQuadTessFactorsMax", "-", "-", "V4,S,>V4,>V2,", "F,,,,", EShLangHS, false }, + { "ProcessQuadTessFactorsMin", "-", "-", "V4,S,>V4,>V2,", "F,,,,", EShLangHS, false }, + { "ProcessTriTessFactorsAvg", "-", "-", "V3,S,>V3,>S,", "F,,,,", EShLangHS, false }, + { "ProcessTriTessFactorsMax", "-", "-", "V3,S,>V3,>S,", "F,,,,", EShLangHS, false }, + { "ProcessTriTessFactorsMin", "-", "-", "V3,S,>V3,>S,", "F,,,,", EShLangHS, false }, + { "radians", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "rcp", nullptr, nullptr, "SVM", "FD", EShLangAll, false }, + { "reflect", nullptr, nullptr, "V,", "F,", EShLangAll, false }, + { "refract", nullptr, nullptr, "V,V,S", "F,,", EShLangAll, false }, + { "reversebits", nullptr, nullptr, "SV", "UI", EShLangAll, false }, + { "round", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "rsqrt", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "saturate", nullptr, nullptr , "SVM", "F", EShLangAll, false }, + { "sign", nullptr, nullptr, "SVM", "FI", EShLangAll, false }, + { "sin", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "sincos", "-", "-", "SVM,>,>", "F,,", EShLangAll, false }, + { "sinh", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "smoothstep", nullptr, nullptr, "SVM,,", "F,,", EShLangAll, false }, + { "sqrt", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "step", nullptr, nullptr, "SVM,", "F,", EShLangAll, false }, + { "tan", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "tanh", nullptr, nullptr, "SVM", "F", EShLangAll, false }, + { "tex1D", "V4", "F", "V1,S", "S,F", EShLangPS, false }, + { "tex1D", "V4", "F", "V1,S,V1,", "S,F,,", EShLangPS, false }, + { "tex1Dbias", "V4", "F", "V1,V4", "S,F", EShLangPS, false }, + { "tex1Dgrad", "V4", "F", "V1,,,", "S,F,,", EShLangPS, false }, + { "tex1Dlod", "V4", "F", "V1,V4", "S,F", EShLangPS, false }, + { "tex1Dproj", "V4", "F", "V1,V4", "S,F", EShLangPS, false }, + { "tex2D", "V4", "F", "V2,", "S,F", EShLangPS, false }, + { "tex2D", "V4", "F", "V2,,,", "S,F,,", EShLangPS, false }, + { "tex2Dbias", "V4", "F", "V2,V4", "S,F", EShLangPS, false }, + { "tex2Dgrad", "V4", "F", "V2,,,", "S,F,,", EShLangPS, false }, + { "tex2Dlod", "V4", "F", "V2,V4", "S,F", EShLangPS, false }, + { "tex2Dproj", "V4", "F", "V2,V4", "S,F", EShLangPS, false }, + { "tex3D", "V4", "F", "V3,", "S,F", EShLangPS, false }, + { "tex3D", "V4", "F", "V3,,,", "S,F,,", EShLangPS, false }, + { "tex3Dbias", "V4", "F", "V3,V4", "S,F", EShLangPS, false }, + { "tex3Dgrad", "V4", "F", "V3,,,", "S,F,,", EShLangPS, false }, + { "tex3Dlod", "V4", "F", "V3,V4", "S,F", EShLangPS, false }, + { "tex3Dproj", "V4", "F", "V3,V4", "S,F", EShLangPS, false }, + { "texCUBE", "V4", "F", "V4,V3", "S,F", EShLangPS, false }, + { "texCUBE", "V4", "F", "V4,V3,,", "S,F,,", EShLangPS, false }, + { "texCUBEbias", "V4", "F", "V4,", "S,F", EShLangPS, false }, + { "texCUBEgrad", "V4", "F", "V4,V3,,", "S,F,,", EShLangPS, false }, + { "texCUBElod", "V4", "F", "V4,", "S,F", EShLangPS, false }, + { "texCUBEproj", "V4", "F", "V4,", "S,F", EShLangPS, false }, + { "transpose", "^M", nullptr, "M", "FUIB", EShLangAll, false }, + { "trunc", nullptr, nullptr, "SVM", "F", EShLangAll, false }, // Texture object methods. Return type can be overridden by shader declaration. - // !O = no offset, O = offset, !A = no array, A = array - { "Sample", /*!O !A*/ "V4", nullptr, "%V,S,V", "FIU,S,F", EShLangFragmentMask }, - { "Sample", /* O !A*/ "V4", nullptr, "%V,S,V,V", "FIU,S,F,I", EShLangFragmentMask }, - { "Sample", /*!O A*/ "V4", nullptr, "@V,S,V", "FIU,S,F", EShLangFragmentMask }, - { "Sample", /* O A*/ "V4", nullptr, "@V,S,V,V", "FIU,S,F,I", EShLangFragmentMask }, + // !O = no offset, O = offset + { "Sample", /*!O*/ "V4", nullptr, "%@,S,V", "FIU,S,F", EShLangPS, true }, + { "Sample", /* O*/ "V4", nullptr, "%@,S,V,", "FIU,S,F,I", EShLangPS, true }, - { "SampleBias", /*!O !A*/ "V4", nullptr, "%V,S,V,S", "FIU,S,F,F", EShLangFragmentMask }, - { "SampleBias", /* O !A*/ "V4", nullptr, "%V,S,V,S,V", "FIU,S,F,F,I", EShLangFragmentMask }, - { "SampleBias", /*!O A*/ "V4", nullptr, "@V,S,V,S", "FIU,S,F,F", EShLangFragmentMask }, - { "SampleBias", /* O A*/ "V4", nullptr, "@V,S,V,S,V", "FIU,S,F,F,I", EShLangFragmentMask }, + { "SampleBias", /*!O*/ "V4", nullptr, "%@,S,V,S", "FIU,S,F,", EShLangPS, true }, + { "SampleBias", /* O*/ "V4", nullptr, "%@,S,V,S,V", "FIU,S,F,,I", EShLangPS, true }, - // { "SampleCmp", /*!O !A*/ "V4", nullptr, "%V,S,V,S", "FIU,S,F,F", EShLangFragmentMask }, - // { "SampleCmp", /* O !A*/ "V4", nullptr, "%V,S,V,S,V", "FIU,S,F,F,I", EShLangFragmentMask }, - // { "SampleCmp", /*!O A*/ "V4", nullptr, "@V,S,V,S", "FIU,S,F,F", EShLangFragmentMask }, - // { "SampleCmp", /* O A*/ "V4", nullptr, "@V,S,V,S,V", "FIU,S,F,F,I", EShLangFragmentMask }, + // TODO: FXC accepts int/uint samplers here. unclear what that means. + { "SampleCmp", /*!O*/ "S", "F", "%@,S,V,S", "FIU,s,F,", EShLangPS, true }, + { "SampleCmp", /* O*/ "S", "F", "%@,S,V,S,V", "FIU,s,F,,I", EShLangPS, true }, - // { "SampleCmpLevelZero", /*!O !A*/ "V4", nullptr, "%V,S,V", "FIU,S,F", EShLangFragmentMask }, - // { "SampleCmpLevelZero", /* O !A*/ "V4", nullptr, "%V,S,V,V", "FIU,S,F,I", EShLangFragmentMask }, - // { "SampleCmpLevelZero", /*!O A*/ "V4", nullptr, "@V,S,V", "FIU,S,F", EShLangFragmentMask }, - // { "SampleCmpLevelZero", /* O A*/ "V4", nullptr, "@V,S,V,V", "FIU,S,F,I", EShLangFragmentMask }, + // TODO: FXC accepts int/uint samplers here. unclear what that means. + { "SampleCmpLevelZero", /*!O*/ "S", "F", "%@,S,V,S", "FIU,s,F,F", EShLangPS, true }, + { "SampleCmpLevelZero", /* O*/ "S", "F", "%@,S,V,S,V", "FIU,s,F,F,I", EShLangPS, true }, - { "SampleGrad", /*!O !A*/ "V4", nullptr, "%V,S,V,V,V", "FIU,S,F,F,F", EShLangAll }, - { "SampleGrad", /* O !A*/ "V4", nullptr, "%V,S,V,V,V,V", "FIU,S,F,F,F,I", EShLangAll }, - { "SampleGrad", /*!O A*/ "V4", nullptr, "@V,S,V,V,V", "FIU,S,F,F,F", EShLangAll }, - { "SampleGrad", /* O A*/ "V4", nullptr, "@V,S,V,V,V,V", "FIU,S,F,F,F,I", EShLangAll }, + { "SampleGrad", /*!O*/ "V4", nullptr, "%@,S,V,,", "FIU,S,F,,", EShLangAll, true }, + { "SampleGrad", /* O*/ "V4", nullptr, "%@,S,V,,,", "FIU,S,F,,,I", EShLangAll, true }, - // { "SampleLevel", /*!O !A*/ "V4", nullptr, "%V,S,V,S", "FIU,S,F,F", EShLangFragmentMask }, - // { "SampleLevel", /* O !A*/ "V4", nullptr, "%V,S,V,S,V", "FIU,S,F,F,I", EShLangFragmentMask }, - // { "SampleLevel", /*!O A*/ "V4", nullptr, "@V,S,V,S", "FIU,S,F,F", EShLangFragmentMask }, - // { "SampleLevel", /* O A*/ "V4", nullptr, "@V,S,V,S,V", "FIU,S,F,F,I", EShLangFragmentMask }, + { "SampleLevel", /*!O*/ "V4", nullptr, "%@,S,V,S", "FIU,S,F,", EShLangAll, true }, + { "SampleLevel", /* O*/ "V4", nullptr, "%@,S,V,S,V", "FIU,S,F,,I", EShLangAll, true }, - // TODO: ... - // { "Load", "V4", nullptr, "%V,V", "FIU,I", EShLangFragmentMask }, - // { "Load", /* +sampleidex*/ "V4", nullptr, "%V,V,S", "FIU,I,I", EShLangFragmentMask }, - // { "Load", /* +samplindex, offset*/ "V4", nullptr, "%V,V,S,V", "FIU,I,I,I", EShLangFragmentMask }, - // { "Load", "V4", nullptr, "@V,V", "FIU,I", EShLangFragmentMask }, - // { "Load", /* +sampleidex*/ "V4", nullptr, "@V,V,S", "FIU,I,I", EShLangFragmentMask }, - // { "Load", /* +samplindex, offset*/ "V4", nullptr, "@V,V,S,V", "FIU,I,I,I", EShLangFragmentMask }, + { "Load", /*!O*/ "V4", nullptr, "%@,V", "FIU,I", EShLangAll, true }, + { "Load", /* O*/ "V4", nullptr, "%@,V,V", "FIU,I,I", EShLangAll, true }, + { "Load", /* +sampleidex*/ "V4", nullptr, "$&,V,S", "FIU,I,I", EShLangAll, true }, + { "Load", /* +samplindex, offset*/ "V4", nullptr, "$&,V,S,V", "FIU,I,I,I", EShLangAll, true }, + + // RWTexture loads + { "Load", "V4", nullptr, "!#,V", "FIU,I", EShLangAll, true }, + // (RW)Buffer loads + { "Load", "V4", nullptr, "~*1,V", "FIU,I", EShLangAll, true }, + + { "Gather", /*!O*/ "V4", nullptr, "%@,S,V", "FIU,S,F", EShLangAll, true }, + { "Gather", /* O*/ "V4", nullptr, "%@,S,V,V", "FIU,S,F,I", EShLangAll, true }, + + { "CalculateLevelOfDetail", "S", "F", "%@,S,V", "FUI,S,F", EShLangPS, true }, + { "CalculateLevelOfDetailUnclamped", "S", "F", "%@,S,V", "FUI,S,F", EShLangPS, true }, + + { "GetSamplePosition", "V2", "F", "$&2,S", "FUI,I", EShLangVSPSGS,true }, + + // + // UINT Width + // UINT MipLevel, UINT Width, UINT NumberOfLevels + { "GetDimensions", /* 1D */ "-", "-", "%!~1,>S", "FUI,U", EShLangAll, true }, + { "GetDimensions", /* 1D */ "-", "-", "%!~1,>S", "FUI,F", EShLangAll, true }, + { "GetDimensions", /* 1D */ "-", "-", "%1,S,>S,", "FUI,U,,", EShLangAll, true }, + { "GetDimensions", /* 1D */ "-", "-", "%1,S,>S,", "FUI,U,F,", EShLangAll, true }, + + // UINT Width, UINT Elements + // UINT MipLevel, UINT Width, UINT Elements, UINT NumberOfLevels + { "GetDimensions", /* 1DArray */ "-", "-", "@#1,>S,", "FUI,U,", EShLangAll, true }, + { "GetDimensions", /* 1DArray */ "-", "-", "@#1,>S,", "FUI,F,", EShLangAll, true }, + { "GetDimensions", /* 1DArray */ "-", "-", "@1,S,>S,,", "FUI,U,,,", EShLangAll, true }, + { "GetDimensions", /* 1DArray */ "-", "-", "@1,S,>S,,", "FUI,U,F,,", EShLangAll, true }, + + // UINT Width, UINT Height + // UINT MipLevel, UINT Width, UINT Height, UINT NumberOfLevels + { "GetDimensions", /* 2D */ "-", "-", "%!2,>S,", "FUI,U,", EShLangAll, true }, + { "GetDimensions", /* 2D */ "-", "-", "%!2,>S,", "FUI,F,", EShLangAll, true }, + { "GetDimensions", /* 2D */ "-", "-", "%2,S,>S,,", "FUI,U,,,", EShLangAll, true }, + { "GetDimensions", /* 2D */ "-", "-", "%2,S,>S,,", "FUI,U,F,,", EShLangAll, true }, + + // UINT Width, UINT Height, UINT Elements + // UINT MipLevel, UINT Width, UINT Height, UINT Elements, UINT NumberOfLevels + { "GetDimensions", /* 2DArray */ "-", "-", "@#2,>S,,", "FUI,U,,", EShLangAll, true }, + { "GetDimensions", /* 2DArray */ "-", "-", "@#2,>S,,", "FUI,F,F,F", EShLangAll, true }, + { "GetDimensions", /* 2DArray */ "-", "-", "@2,S,>S,,,", "FUI,U,,,,", EShLangAll, true }, + { "GetDimensions", /* 2DArray */ "-", "-", "@2,S,>S,,,", "FUI,U,F,,,", EShLangAll, true }, + + // UINT Width, UINT Height, UINT Depth + // UINT MipLevel, UINT Width, UINT Height, UINT Depth, UINT NumberOfLevels + { "GetDimensions", /* 3D */ "-", "-", "%!3,>S,,", "FUI,U,,", EShLangAll, true }, + { "GetDimensions", /* 3D */ "-", "-", "%!3,>S,,", "FUI,F,,", EShLangAll, true }, + { "GetDimensions", /* 3D */ "-", "-", "%3,S,>S,,,", "FUI,U,,,,", EShLangAll, true }, + { "GetDimensions", /* 3D */ "-", "-", "%3,S,>S,,,", "FUI,U,F,,,", EShLangAll, true }, + + // UINT Width, UINT Height + // UINT MipLevel, UINT Width, UINT Height, UINT NumberOfLevels + { "GetDimensions", /* Cube */ "-", "-", "%4,>S,", "FUI,U,", EShLangAll, true }, + { "GetDimensions", /* Cube */ "-", "-", "%4,>S,", "FUI,F,", EShLangAll, true }, + { "GetDimensions", /* Cube */ "-", "-", "%4,S,>S,,", "FUI,U,,,", EShLangAll, true }, + { "GetDimensions", /* Cube */ "-", "-", "%4,S,>S,,", "FUI,U,F,,", EShLangAll, true }, + + // UINT Width, UINT Height, UINT Elements + // UINT MipLevel, UINT Width, UINT Height, UINT Elements, UINT NumberOfLevels + { "GetDimensions", /* CubeArray */ "-", "-", "@4,>S,,", "FUI,U,,", EShLangAll, true }, + { "GetDimensions", /* CubeArray */ "-", "-", "@4,>S,,", "FUI,F,,", EShLangAll, true }, + { "GetDimensions", /* CubeArray */ "-", "-", "@4,S,>S,,,", "FUI,U,,,,", EShLangAll, true }, + { "GetDimensions", /* CubeArray */ "-", "-", "@4,S,>S,,,", "FUI,U,F,,,", EShLangAll, true }, + + // UINT Width, UINT Height, UINT Samples + // UINT Width, UINT Height, UINT Elements, UINT Samples + { "GetDimensions", /* 2DMS */ "-", "-", "$2,>S,,", "FUI,U,,", EShLangAll, true }, + { "GetDimensions", /* 2DMS */ "-", "-", "$2,>S,,", "FUI,U,,", EShLangAll, true }, + { "GetDimensions", /* 2DMSArray */ "-", "-", "&2,>S,,,", "FUI,U,,,", EShLangAll, true }, + { "GetDimensions", /* 2DMSArray */ "-", "-", "&2,>S,,,", "FUI,U,,,", EShLangAll, true }, + + // SM5 texture methods + { "GatherRed", /*!O*/ "V4", nullptr, "%@,S,V", "FIU,S,F", EShLangAll, true }, + { "GatherRed", /* O*/ "V4", nullptr, "%@,S,V,", "FIU,S,F,I", EShLangAll, true }, + { "GatherRed", /* O, status*/ "V4", nullptr, "%@,S,V,,>S", "FIU,S,F,I,U", EShLangAll, true }, + { "GatherRed", /* O-4 */ "V4", nullptr, "%@,S,V,,,,", "FIU,S,F,I,,,", EShLangAll, true }, + { "GatherRed", /* O-4, status */"V4", nullptr, "%@,S,V,,,,,S", "FIU,S,F,I,,,,U", EShLangAll, true }, + + { "GatherGreen", /*!O*/ "V4", nullptr, "%@,S,V", "FIU,S,F", EShLangAll, true }, + { "GatherGreen", /* O*/ "V4", nullptr, "%@,S,V,", "FIU,S,F,I", EShLangAll, true }, + { "GatherGreen", /* O, status*/ "V4", nullptr, "%@,S,V,,>S", "FIU,S,F,I,U", EShLangAll, true }, + { "GatherGreen", /* O-4 */ "V4", nullptr, "%@,S,V,,,,", "FIU,S,F,I,,,", EShLangAll, true }, + { "GatherGreen", /* O-4, status */"V4", nullptr, "%@,S,V,,,,,S", "FIU,S,F,I,,,,U", EShLangAll, true }, + + { "GatherBlue", /*!O*/ "V4", nullptr, "%@,S,V", "FIU,S,F", EShLangAll, true }, + { "GatherBlue", /* O*/ "V4", nullptr, "%@,S,V,", "FIU,S,F,I", EShLangAll, true }, + { "GatherBlue", /* O, status*/ "V4", nullptr, "%@,S,V,,>S", "FIU,S,F,I,U", EShLangAll, true }, + { "GatherBlue", /* O-4 */ "V4", nullptr, "%@,S,V,,,,", "FIU,S,F,I,,,", EShLangAll, true }, + { "GatherBlue", /* O-4, status */"V4", nullptr, "%@,S,V,,,,,S", "FIU,S,F,I,,,,U", EShLangAll, true }, + + { "GatherAlpha", /*!O*/ "V4", nullptr, "%@,S,V", "FIU,S,F", EShLangAll, true }, + { "GatherAlpha", /* O*/ "V4", nullptr, "%@,S,V,", "FIU,S,F,I", EShLangAll, true }, + { "GatherAlpha", /* O, status*/ "V4", nullptr, "%@,S,V,,>S", "FIU,S,F,I,U", EShLangAll, true }, + { "GatherAlpha", /* O-4 */ "V4", nullptr, "%@,S,V,,,,", "FIU,S,F,I,,,", EShLangAll, true }, + { "GatherAlpha", /* O-4, status */"V4", nullptr, "%@,S,V,,,,,S", "FIU,S,F,I,,,,U", EShLangAll, true }, + + { "GatherCmp", /*!O*/ "V4", nullptr, "%@,S,V,S", "FIU,s,F,", EShLangAll, true }, + { "GatherCmp", /* O*/ "V4", nullptr, "%@,S,V,S,V", "FIU,s,F,,I", EShLangAll, true }, + { "GatherCmp", /* O, status*/ "V4", nullptr, "%@,S,V,S,V,>S", "FIU,s,F,,I,U", EShLangAll, true }, + { "GatherCmp", /* O-4 */ "V4", nullptr, "%@,S,V,S,V,,,", "FIU,s,F,,I,,,", EShLangAll, true }, + { "GatherCmp", /* O-4, status */"V4", nullptr, "%@,S,V,S,V,,V,S","FIU,s,F,,I,,,,U",EShLangAll, true }, + + { "GatherCmpRed", /*!O*/ "V4", nullptr, "%@,S,V,S", "FIU,s,F,", EShLangAll, true }, + { "GatherCmpRed", /* O*/ "V4", nullptr, "%@,S,V,S,V", "FIU,s,F,,I", EShLangAll, true }, + { "GatherCmpRed", /* O, status*/ "V4", nullptr, "%@,S,V,S,V,>S", "FIU,s,F,,I,U", EShLangAll, true }, + { "GatherCmpRed", /* O-4 */ "V4", nullptr, "%@,S,V,S,V,,,", "FIU,s,F,,I,,,", EShLangAll, true }, + { "GatherCmpRed", /* O-4, status */"V4", nullptr, "%@,S,V,S,V,,V,S","FIU,s,F,,I,,,,U",EShLangAll, true }, + + { "GatherCmpGreen", /*!O*/ "V4", nullptr, "%@,S,V,S", "FIU,s,F,", EShLangAll, true }, + { "GatherCmpGreen", /* O*/ "V4", nullptr, "%@,S,V,S,V", "FIU,s,F,,I", EShLangAll, true }, + { "GatherCmpGreen", /* O, status*/ "V4", nullptr, "%@,S,V,S,V,>S", "FIU,s,F,,I,U", EShLangAll, true }, + { "GatherCmpGreen", /* O-4 */ "V4", nullptr, "%@,S,V,S,V,,,", "FIU,s,F,,I,,,", EShLangAll, true }, + { "GatherCmpGreen", /* O-4, status */"V4", nullptr, "%@,S,V,S,V,,,,S","FIU,s,F,,I,,,,U",EShLangAll, true }, + + { "GatherCmpBlue", /*!O*/ "V4", nullptr, "%@,S,V,S", "FIU,s,F,", EShLangAll, true }, + { "GatherCmpBlue", /* O*/ "V4", nullptr, "%@,S,V,S,V", "FIU,s,F,,I", EShLangAll, true }, + { "GatherCmpBlue", /* O, status*/ "V4", nullptr, "%@,S,V,S,V,>S", "FIU,s,F,,I,U", EShLangAll, true }, + { "GatherCmpBlue", /* O-4 */ "V4", nullptr, "%@,S,V,S,V,,,", "FIU,s,F,,I,,,", EShLangAll, true }, + { "GatherCmpBlue", /* O-4, status */"V4", nullptr, "%@,S,V,S,V,,,,S","FIU,s,F,,I,,,,U",EShLangAll, true }, + + { "GatherCmpAlpha", /*!O*/ "V4", nullptr, "%@,S,V,S", "FIU,s,F,", EShLangAll, true }, + { "GatherCmpAlpha", /* O*/ "V4", nullptr, "%@,S,V,S,V", "FIU,s,F,,I", EShLangAll, true }, + { "GatherCmpAlpha", /* O, status*/ "V4", nullptr, "%@,S,V,S,V,>S", "FIU,s,F,,I,U", EShLangAll, true }, + { "GatherCmpAlpha", /* O-4 */ "V4", nullptr, "%@,S,V,S,V,,,", "FIU,s,F,,I,,,", EShLangAll, true }, + { "GatherCmpAlpha", /* O-4, status */"V4", nullptr, "%@,S,V,S,V,,,,S","FIU,s,F,,I,,,,U",EShLangAll, true }, + + // geometry methods + { "Append", "-", "-", "-", "-", EShLangGS , true }, + { "RestartStrip", "-", "-", "-", "-", EShLangGS , true }, + + // Methods for structurebuffers. TODO: wildcard type matching. + { "Load", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "Load2", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "Load3", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "Load4", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "Store", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "Store2", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "Store3", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "Store4", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "GetDimensions", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "InterlockedAdd", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "InterlockedAnd", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "InterlockedCompareExchange", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "InterlockedCompareStore", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "InterlockedExchange", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "InterlockedMax", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "InterlockedMin", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "InterlockedOr", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "InterlockedXor", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "IncrementCounter", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "DecrementCounter", nullptr, nullptr, "-", "-", EShLangAll, true }, + { "Consume", nullptr, nullptr, "-", "-", EShLangAll, true }, + + // SM 6.0 + + { "WaveIsFirstLane", "S", "B", "-", "-", EShLangPSCS, false}, + { "WaveGetLaneCount", "S", "U", "-", "-", EShLangPSCS, false}, + { "WaveGetLaneIndex", "S", "U", "-", "-", EShLangPSCS, false}, + { "WaveActiveAnyTrue", "S", "B", "S", "B", EShLangPSCS, false}, + { "WaveActiveAllTrue", "S", "B", "S", "B", EShLangPSCS, false}, + { "WaveActiveBallot", "V4", "U", "S", "B", EShLangPSCS, false}, + { "WaveReadLaneAt", nullptr, nullptr, "SV,S", "DFUI,U", EShLangPSCS, false}, + { "WaveReadLaneFirst", nullptr, nullptr, "SV", "DFUI", EShLangPSCS, false}, + { "WaveActiveAllEqual", "S", "B", "SV", "DFUI", EShLangPSCS, false}, + { "WaveActiveAllEqualBool", "S", "B", "S", "B", EShLangPSCS, false}, + { "WaveActiveCountBits", "S", "U", "S", "B", EShLangPSCS, false}, + + { "WaveActiveSum", nullptr, nullptr, "SV", "DFUI", EShLangPSCS, false}, + { "WaveActiveProduct", nullptr, nullptr, "SV", "DFUI", EShLangPSCS, false}, + { "WaveActiveBitAnd", nullptr, nullptr, "SV", "DFUI", EShLangPSCS, false}, + { "WaveActiveBitOr", nullptr, nullptr, "SV", "DFUI", EShLangPSCS, false}, + { "WaveActiveBitXor", nullptr, nullptr, "SV", "DFUI", EShLangPSCS, false}, + { "WaveActiveMin", nullptr, nullptr, "SV", "DFUI", EShLangPSCS, false}, + { "WaveActiveMax", nullptr, nullptr, "SV", "DFUI", EShLangPSCS, false}, + { "WavePrefixSum", nullptr, nullptr, "SV", "DFUI", EShLangPSCS, false}, + { "WavePrefixProduct", nullptr, nullptr, "SV", "DFUI", EShLangPSCS, false}, + { "WavePrefixCountBits", "S", "U", "S", "B", EShLangPSCS, false}, + { "QuadReadAcrossX", nullptr, nullptr, "SV", "DFUI", EShLangPSCS, false}, + { "QuadReadAcrossY", nullptr, nullptr, "SV", "DFUI", EShLangPSCS, false}, + { "QuadReadAcrossDiagonal", nullptr, nullptr, "SV", "DFUI", EShLangPSCS, false}, + { "QuadReadLaneAt", nullptr, nullptr, "SV,S", "DFUI,U", EShLangPSCS, false}, + + // Methods for subpass input objects + { "SubpassLoad", "V4", nullptr, "[", "FIU", EShLangPS, true }, + { "SubpassLoad", "V4", nullptr, "],S", "FIU,I", EShLangPS, true }, // Mark end of list, since we want to avoid a range-based for, as some compilers don't handle it yet. - { nullptr, nullptr, nullptr, nullptr, nullptr, 0 }, + { nullptr, nullptr, nullptr, nullptr, nullptr, 0, false }, }; - // Set this to true to avoid generating prototypes that will be invalid for the GLSL parser. - // TODO: turn it off (and remove the code) when the HLSL parser can be used to parse builtins. - static const bool skipInvalidGlsl = true; - // Create prototypes for the intrinsics. TODO: Avoid ranged based for until all compilers can handle it. for (int icount = 0; hlslIntrinsics[icount].name; ++icount) { const auto& intrinsic = hlslIntrinsics[icount]; @@ -592,8 +954,13 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c for (const char* argOrder = intrinsic.argOrder; !IsEndOfArg(argOrder); ++argOrder) { // for each order... const bool isTexture = IsTextureType(*argOrder); - const bool isArrayed = IsTextureArrayed(*argOrder); - const int fixedVecSize = isdigit(argOrder[1]) ? (argOrder[1] - '0') : 0; + const bool isArrayed = IsArrayed(*argOrder); + const bool isMS = IsTextureMS(*argOrder); + const bool isBuffer = IsBuffer(*argOrder); + const bool isImage = IsImage(*argOrder); + const bool mipInCoord = HasMipInCoord(intrinsic.name, isMS, isBuffer, isImage); + const int fixedVecSize = FixedVecSize(argOrder); + const int coordArg = CoordinateArgPos(intrinsic.name, isTexture); // calculate min and max vector and matrix dimensions int dim0Min = 1; @@ -609,8 +976,7 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c const char* retOrder = intrinsic.retOrder ? intrinsic.retOrder : argOrder; const char* retType = intrinsic.retType ? intrinsic.retType : argType; - if (skipInvalidGlsl && !IsValidGlsl(intrinsic.name, *retOrder, *retType, *argOrder, *argType, - dim0, dim1, dim0Max, dim1Max)) + if (!IsValid(intrinsic.name, *retOrder, *retType, *argOrder, *argType, dim0, dim1)) continue; // Reject some forms of sample methods that don't exist. @@ -619,9 +985,18 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c AppendTypeName(s, retOrder, retType, dim0, dim1); // add return type s.append(" "); // space between type and name + + // methods have a prefix. TODO: it would be better as an invalid identifier character, + // but that requires a scanner change. + if (intrinsic.method) + s.append(BUILTIN_PREFIX); + s.append(intrinsic.name); // intrinsic name s.append("("); // open paren + const char* prevArgOrder = nullptr; + const char* prevArgType = nullptr; + // Append argument types, if any. for (int arg = 0; ; ++arg) { const char* nthArgOrder(NthArg(argOrder, arg)); @@ -633,40 +1008,46 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c // cube textures use vec3 coordinates int argDim0 = isTexture && arg > 0 ? std::min(dim0, 3) : dim0; - // arrayed textures have one extra coordinate dimension - if (isArrayed && arg == 2) + s.append(arg > 0 ? ", ": ""); // comma separator if needed + + const char* orderBegin = nthArgOrder; + nthArgOrder = IoParam(s, nthArgOrder); + + // Comma means use the previous argument order and type. + HandleRepeatArg(nthArgOrder, prevArgOrder, orderBegin); + HandleRepeatArg(nthArgType, prevArgType, nthArgType); + + // In case the repeated arg has its own I/O marker + nthArgOrder = IoParam(s, nthArgOrder); + + // arrayed textures have one extra coordinate dimension, except for + // the CalculateLevelOfDetail family. + if (isArrayed && arg == coordArg && !NoArrayCoord(intrinsic.name)) + argDim0++; + + // Some texture methods use an addition arg dimension to hold mip + if (arg == coordArg && mipInCoord) argDim0++; // For textures, the 1D case isn't a 1-vector, but a scalar. if (isTexture && argDim0 == 1 && arg > 0 && *nthArgOrder == 'V') nthArgOrder = "S"; - s.append(arg > 0 ? ", ": ""); // comma separator if needed - - if (*nthArgOrder == '>') { // output params - ++nthArgOrder; - s.append("out "); - } else if (*nthArgOrder == '<') { // input params - ++nthArgOrder; - s.append("in "); - } - - // Comma means use the 1st argument order and type. - if (*nthArgOrder == ',' || *nthArgOrder == '\0') nthArgOrder = argOrder; - if (*nthArgType == ',' || *nthArgType == '\0') nthArgType = argType; - AppendTypeName(s, nthArgOrder, nthArgType, argDim0, dim1); // Add arguments } - - s.append(");\n"); // close paren and trailing semicolon - } - } - } - if (fixedVecSize > 0 || isTexture) // skip over special characters + s.append(");\n"); // close paren and trailing semicolon + } // dim 1 loop + } // dim 0 loop + } // arg type loop + + // skip over special characters + if (isTexture && isalpha(argOrder[1])) ++argOrder; - } - + if (isdigit(argOrder[1])) + ++argOrder; + } // arg order loop + if (intrinsic.stage == EShLangAll) // common builtins are only added once. break; } @@ -695,7 +1076,6 @@ void TBuiltInParseablesHlsl::initialize(const TBuiltInResource& /*resources*/, i { } - // // Finish adding/processing context-independent built-in symbols. // 1) Programmatically add symbols that could not be added by simple text strings above. @@ -729,7 +1109,7 @@ void TBuiltInParseablesHlsl::identifyBuiltIns(int /*version*/, EProfile /*profil symbolTable.relateToOperator("cosh", EOpCosh); symbolTable.relateToOperator("countbits", EOpBitCount); symbolTable.relateToOperator("cross", EOpCross); - // symbolTable.relateToOperator("D3DCOLORtoUBYTE4", EOpD3DCOLORtoUBYTE4); + symbolTable.relateToOperator("D3DCOLORtoUBYTE4", EOpD3DCOLORtoUBYTE4); symbolTable.relateToOperator("ddx", EOpDPdx); symbolTable.relateToOperator("ddx_coarse", EOpDPdxCoarse); symbolTable.relateToOperator("ddx_fine", EOpDPdxFine); @@ -738,8 +1118,8 @@ void TBuiltInParseablesHlsl::identifyBuiltIns(int /*version*/, EProfile /*profil symbolTable.relateToOperator("ddy_fine", EOpDPdyFine); symbolTable.relateToOperator("degrees", EOpDegrees); symbolTable.relateToOperator("determinant", EOpDeterminant); - symbolTable.relateToOperator("DeviceMemoryBarrier", EOpGroupMemoryBarrier); - symbolTable.relateToOperator("DeviceMemoryBarrierWithGroupSync", EOpGroupMemoryBarrierWithGroupSync); // ... + symbolTable.relateToOperator("DeviceMemoryBarrier", EOpDeviceMemoryBarrier); + symbolTable.relateToOperator("DeviceMemoryBarrierWithGroupSync", EOpDeviceMemoryBarrierWithGroupSync); symbolTable.relateToOperator("distance", EOpDistance); symbolTable.relateToOperator("dot", EOpDot); symbolTable.relateToOperator("dst", EOpDst); @@ -844,18 +1224,92 @@ void TBuiltInParseablesHlsl::identifyBuiltIns(int /*version*/, EProfile /*profil symbolTable.relateToOperator("trunc", EOpTrunc); // Texture methods - symbolTable.relateToOperator("Sample", EOpMethodSample); - symbolTable.relateToOperator("SampleBias", EOpMethodSampleBias); - // symbolTable.relateToOperator("SampleCmp", EOpMethodSampleCmp); - // symbolTable.relateToOperator("SampleCmpLevelZero", EOpMethodSampleCmpLevelZero); - symbolTable.relateToOperator("SampleGrad", EOpMethodSampleGrad); - // symbolTable.relateToOperator("SampleLevel", EOpMethodSampleLevel); - // symbolTable.relateToOperator("Load", EOpMethodLoad); + symbolTable.relateToOperator(BUILTIN_PREFIX "Sample", EOpMethodSample); + symbolTable.relateToOperator(BUILTIN_PREFIX "SampleBias", EOpMethodSampleBias); + symbolTable.relateToOperator(BUILTIN_PREFIX "SampleCmp", EOpMethodSampleCmp); + symbolTable.relateToOperator(BUILTIN_PREFIX "SampleCmpLevelZero", EOpMethodSampleCmpLevelZero); + symbolTable.relateToOperator(BUILTIN_PREFIX "SampleGrad", EOpMethodSampleGrad); + symbolTable.relateToOperator(BUILTIN_PREFIX "SampleLevel", EOpMethodSampleLevel); + symbolTable.relateToOperator(BUILTIN_PREFIX "Load", EOpMethodLoad); + symbolTable.relateToOperator(BUILTIN_PREFIX "GetDimensions", EOpMethodGetDimensions); + symbolTable.relateToOperator(BUILTIN_PREFIX "GetSamplePosition", EOpMethodGetSamplePosition); + symbolTable.relateToOperator(BUILTIN_PREFIX "Gather", EOpMethodGather); + symbolTable.relateToOperator(BUILTIN_PREFIX "CalculateLevelOfDetail", EOpMethodCalculateLevelOfDetail); + symbolTable.relateToOperator(BUILTIN_PREFIX "CalculateLevelOfDetailUnclamped", EOpMethodCalculateLevelOfDetailUnclamped); + + // Structure buffer methods (excluding associations already made above for texture methods w/ same name) + symbolTable.relateToOperator(BUILTIN_PREFIX "Load2", EOpMethodLoad2); + symbolTable.relateToOperator(BUILTIN_PREFIX "Load3", EOpMethodLoad3); + symbolTable.relateToOperator(BUILTIN_PREFIX "Load4", EOpMethodLoad4); + symbolTable.relateToOperator(BUILTIN_PREFIX "Store", EOpMethodStore); + symbolTable.relateToOperator(BUILTIN_PREFIX "Store2", EOpMethodStore2); + symbolTable.relateToOperator(BUILTIN_PREFIX "Store3", EOpMethodStore3); + symbolTable.relateToOperator(BUILTIN_PREFIX "Store4", EOpMethodStore4); + symbolTable.relateToOperator(BUILTIN_PREFIX "IncrementCounter", EOpMethodIncrementCounter); + symbolTable.relateToOperator(BUILTIN_PREFIX "DecrementCounter", EOpMethodDecrementCounter); + // Append is also a GS method: we don't add it twice + symbolTable.relateToOperator(BUILTIN_PREFIX "Consume", EOpMethodConsume); + + symbolTable.relateToOperator(BUILTIN_PREFIX "InterlockedAdd", EOpInterlockedAdd); + symbolTable.relateToOperator(BUILTIN_PREFIX "InterlockedAnd", EOpInterlockedAnd); + symbolTable.relateToOperator(BUILTIN_PREFIX "InterlockedCompareExchange", EOpInterlockedCompareExchange); + symbolTable.relateToOperator(BUILTIN_PREFIX "InterlockedCompareStore", EOpInterlockedCompareStore); + symbolTable.relateToOperator(BUILTIN_PREFIX "InterlockedExchange", EOpInterlockedExchange); + symbolTable.relateToOperator(BUILTIN_PREFIX "InterlockedMax", EOpInterlockedMax); + symbolTable.relateToOperator(BUILTIN_PREFIX "InterlockedMin", EOpInterlockedMin); + symbolTable.relateToOperator(BUILTIN_PREFIX "InterlockedOr", EOpInterlockedOr); + symbolTable.relateToOperator(BUILTIN_PREFIX "InterlockedXor", EOpInterlockedXor); + + // SM5 Texture methods + symbolTable.relateToOperator(BUILTIN_PREFIX "GatherRed", EOpMethodGatherRed); + symbolTable.relateToOperator(BUILTIN_PREFIX "GatherGreen", EOpMethodGatherGreen); + symbolTable.relateToOperator(BUILTIN_PREFIX "GatherBlue", EOpMethodGatherBlue); + symbolTable.relateToOperator(BUILTIN_PREFIX "GatherAlpha", EOpMethodGatherAlpha); + symbolTable.relateToOperator(BUILTIN_PREFIX "GatherCmp", EOpMethodGatherCmpRed); // alias + symbolTable.relateToOperator(BUILTIN_PREFIX "GatherCmpRed", EOpMethodGatherCmpRed); + symbolTable.relateToOperator(BUILTIN_PREFIX "GatherCmpGreen", EOpMethodGatherCmpGreen); + symbolTable.relateToOperator(BUILTIN_PREFIX "GatherCmpBlue", EOpMethodGatherCmpBlue); + symbolTable.relateToOperator(BUILTIN_PREFIX "GatherCmpAlpha", EOpMethodGatherCmpAlpha); + + // GS methods + symbolTable.relateToOperator(BUILTIN_PREFIX "Append", EOpMethodAppend); + symbolTable.relateToOperator(BUILTIN_PREFIX "RestartStrip", EOpMethodRestartStrip); + + // Wave ops + symbolTable.relateToOperator("WaveIsFirstLane", EOpSubgroupElect); + symbolTable.relateToOperator("WaveGetLaneCount", EOpWaveGetLaneCount); + symbolTable.relateToOperator("WaveGetLaneIndex", EOpWaveGetLaneIndex); + symbolTable.relateToOperator("WaveActiveAnyTrue", EOpSubgroupAny); + symbolTable.relateToOperator("WaveActiveAllTrue", EOpSubgroupAll); + symbolTable.relateToOperator("WaveActiveBallot", EOpSubgroupBallot); + symbolTable.relateToOperator("WaveReadLaneFirst", EOpSubgroupBroadcastFirst); + symbolTable.relateToOperator("WaveReadLaneAt", EOpSubgroupShuffle); + symbolTable.relateToOperator("WaveActiveAllEqual", EOpSubgroupAllEqual); + symbolTable.relateToOperator("WaveActiveAllEqualBool", EOpSubgroupAllEqual); + symbolTable.relateToOperator("WaveActiveCountBits", EOpWaveActiveCountBits); + symbolTable.relateToOperator("WaveActiveSum", EOpSubgroupAdd); + symbolTable.relateToOperator("WaveActiveProduct", EOpSubgroupMul); + symbolTable.relateToOperator("WaveActiveBitAnd", EOpSubgroupAnd); + symbolTable.relateToOperator("WaveActiveBitOr", EOpSubgroupOr); + symbolTable.relateToOperator("WaveActiveBitXor", EOpSubgroupXor); + symbolTable.relateToOperator("WaveActiveMin", EOpSubgroupMin); + symbolTable.relateToOperator("WaveActiveMax", EOpSubgroupMax); + symbolTable.relateToOperator("WavePrefixSum", EOpSubgroupInclusiveAdd); + symbolTable.relateToOperator("WavePrefixProduct", EOpSubgroupInclusiveMul); + symbolTable.relateToOperator("WavePrefixCountBits", EOpWavePrefixCountBits); + symbolTable.relateToOperator("QuadReadAcrossX", EOpSubgroupQuadSwapHorizontal); + symbolTable.relateToOperator("QuadReadAcrossY", EOpSubgroupQuadSwapVertical); + symbolTable.relateToOperator("QuadReadAcrossDiagonal", EOpSubgroupQuadSwapDiagonal); + symbolTable.relateToOperator("QuadReadLaneAt", EOpSubgroupQuadBroadcast); + + // Subpass input methods + symbolTable.relateToOperator(BUILTIN_PREFIX "SubpassLoad", EOpSubpassLoad); + symbolTable.relateToOperator(BUILTIN_PREFIX "SubpassLoadMS", EOpSubpassLoadMS); } // // Add context-dependent (resource-specific) built-ins not handled by the above. These -// would be ones that need to be programmatically added because they cannot +// would be ones that need to be programmatically added because they cannot // be added by simple text strings. For these, also // 1) Map built-in functions to operators, for those that will turn into an operation node // instead of remaining a function call. @@ -867,5 +1321,4 @@ void TBuiltInParseablesHlsl::identifyBuiltIns(int /*version*/, EProfile /*profil { } - } // end namespace glslang diff --git a/Externals/glslang/hlsl/hlslParseables.h b/Externals/glslang/hlsl/hlslParseables.h index c837590030..28f424b317 100755 --- a/Externals/glslang/hlsl/hlslParseables.h +++ b/Externals/glslang/hlsl/hlslParseables.h @@ -1,11 +1,11 @@ // -//Copyright (C) 2016 LunarG, Inc. +// Copyright (C) 2016 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,18 +19,18 @@ // 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. +// 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 _HLSLPARSEABLES_INCLUDED_ @@ -52,7 +52,7 @@ public: void initialize(const TBuiltInResource& resources, int version, EProfile, const SpvVersion& spvVersion, EShLanguage); void identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable); - + void identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources); private: diff --git a/Externals/glslang/hlsl/hlslScanContext.cpp b/Externals/glslang/hlsl/hlslScanContext.cpp index 8a4eb736b7..28a66bb47d 100755 --- a/Externals/glslang/hlsl/hlslScanContext.cpp +++ b/Externals/glslang/hlsl/hlslScanContext.cpp @@ -1,12 +1,12 @@ // -//Copyright (C) 2016 Google, Inc. -//Copyright (C) 2016 LunarG, Inc. +// Copyright (C) 2016 Google, Inc. +// Copyright (C) 2016 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,25 +20,25 @@ // 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. +// 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. // // // HLSL scanning, leveraging the scanning done by the preprocessor. // -#include +#include #include #include @@ -47,12 +47,11 @@ #include "../glslang/MachineIndependent/ParseHelper.h" #include "hlslScanContext.h" #include "hlslTokens.h" -//#include "Scan.h" // preprocessor includes #include "../glslang/MachineIndependent/preprocessor/PpContext.h" #include "../glslang/MachineIndependent/preprocessor/PpTokens.h" - + namespace { struct str_eq @@ -82,6 +81,7 @@ struct str_hash // After a single process-level initialization, this is read only and thread safe std::unordered_map* KeywordMap = nullptr; std::unordered_set* ReservedSet = nullptr; +std::unordered_map* SemanticMap = nullptr; }; @@ -117,24 +117,42 @@ void HlslScanContext::fillInKeywordMap() (*KeywordMap)["in"] = EHTokIn; (*KeywordMap)["out"] = EHTokOut; (*KeywordMap)["inout"] = EHTokInOut; + (*KeywordMap)["layout"] = EHTokLayout; + (*KeywordMap)["globallycoherent"] = EHTokGloballyCoherent; + (*KeywordMap)["inline"] = EHTokInline; + + (*KeywordMap)["point"] = EHTokPoint; + (*KeywordMap)["line"] = EHTokLine; + (*KeywordMap)["triangle"] = EHTokTriangle; + (*KeywordMap)["lineadj"] = EHTokLineAdj; + (*KeywordMap)["triangleadj"] = EHTokTriangleAdj; + + (*KeywordMap)["PointStream"] = EHTokPointStream; + (*KeywordMap)["LineStream"] = EHTokLineStream; + (*KeywordMap)["TriangleStream"] = EHTokTriangleStream; + + (*KeywordMap)["InputPatch"] = EHTokInputPatch; + (*KeywordMap)["OutputPatch"] = EHTokOutputPatch; (*KeywordMap)["Buffer"] = EHTokBuffer; (*KeywordMap)["vector"] = EHTokVector; (*KeywordMap)["matrix"] = EHTokMatrix; (*KeywordMap)["void"] = EHTokVoid; + (*KeywordMap)["string"] = EHTokString; (*KeywordMap)["bool"] = EHTokBool; (*KeywordMap)["int"] = EHTokInt; (*KeywordMap)["uint"] = EHTokUint; + (*KeywordMap)["uint64_t"] = EHTokUint64; (*KeywordMap)["dword"] = EHTokDword; (*KeywordMap)["half"] = EHTokHalf; (*KeywordMap)["float"] = EHTokFloat; (*KeywordMap)["double"] = EHTokDouble; - (*KeywordMap)["min16float"] = EHTokMin16float; + (*KeywordMap)["min16float"] = EHTokMin16float; (*KeywordMap)["min10float"] = EHTokMin10float; (*KeywordMap)["min16int"] = EHTokMin16int; (*KeywordMap)["min12int"] = EHTokMin12int; - (*KeywordMap)["min16uint"] = EHTokMin16int; + (*KeywordMap)["min16uint"] = EHTokMin16uint; (*KeywordMap)["bool1"] = EHTokBool1; (*KeywordMap)["bool2"] = EHTokBool2; @@ -157,6 +175,47 @@ void HlslScanContext::fillInKeywordMap() (*KeywordMap)["uint3"] = EHTokUint3; (*KeywordMap)["uint4"] = EHTokUint4; + (*KeywordMap)["half1"] = EHTokHalf1; + (*KeywordMap)["half2"] = EHTokHalf2; + (*KeywordMap)["half3"] = EHTokHalf3; + (*KeywordMap)["half4"] = EHTokHalf4; + (*KeywordMap)["min16float1"] = EHTokMin16float1; + (*KeywordMap)["min16float2"] = EHTokMin16float2; + (*KeywordMap)["min16float3"] = EHTokMin16float3; + (*KeywordMap)["min16float4"] = EHTokMin16float4; + (*KeywordMap)["min10float1"] = EHTokMin10float1; + (*KeywordMap)["min10float2"] = EHTokMin10float2; + (*KeywordMap)["min10float3"] = EHTokMin10float3; + (*KeywordMap)["min10float4"] = EHTokMin10float4; + (*KeywordMap)["min16int1"] = EHTokMin16int1; + (*KeywordMap)["min16int2"] = EHTokMin16int2; + (*KeywordMap)["min16int3"] = EHTokMin16int3; + (*KeywordMap)["min16int4"] = EHTokMin16int4; + (*KeywordMap)["min12int1"] = EHTokMin12int1; + (*KeywordMap)["min12int2"] = EHTokMin12int2; + (*KeywordMap)["min12int3"] = EHTokMin12int3; + (*KeywordMap)["min12int4"] = EHTokMin12int4; + (*KeywordMap)["min16uint1"] = EHTokMin16uint1; + (*KeywordMap)["min16uint2"] = EHTokMin16uint2; + (*KeywordMap)["min16uint3"] = EHTokMin16uint3; + (*KeywordMap)["min16uint4"] = EHTokMin16uint4; + + (*KeywordMap)["bool1x1"] = EHTokBool1x1; + (*KeywordMap)["bool1x2"] = EHTokBool1x2; + (*KeywordMap)["bool1x3"] = EHTokBool1x3; + (*KeywordMap)["bool1x4"] = EHTokBool1x4; + (*KeywordMap)["bool2x1"] = EHTokBool2x1; + (*KeywordMap)["bool2x2"] = EHTokBool2x2; + (*KeywordMap)["bool2x3"] = EHTokBool2x3; + (*KeywordMap)["bool2x4"] = EHTokBool2x4; + (*KeywordMap)["bool3x1"] = EHTokBool3x1; + (*KeywordMap)["bool3x2"] = EHTokBool3x2; + (*KeywordMap)["bool3x3"] = EHTokBool3x3; + (*KeywordMap)["bool3x4"] = EHTokBool3x4; + (*KeywordMap)["bool4x1"] = EHTokBool4x1; + (*KeywordMap)["bool4x2"] = EHTokBool4x2; + (*KeywordMap)["bool4x3"] = EHTokBool4x3; + (*KeywordMap)["bool4x4"] = EHTokBool4x4; (*KeywordMap)["int1x1"] = EHTokInt1x1; (*KeywordMap)["int1x2"] = EHTokInt1x2; (*KeywordMap)["int1x3"] = EHTokInt1x3; @@ -221,6 +280,22 @@ void HlslScanContext::fillInKeywordMap() (*KeywordMap)["float4x2"] = EHTokFloat4x2; (*KeywordMap)["float4x3"] = EHTokFloat4x3; (*KeywordMap)["float4x4"] = EHTokFloat4x4; + (*KeywordMap)["half1x1"] = EHTokHalf1x1; + (*KeywordMap)["half1x2"] = EHTokHalf1x2; + (*KeywordMap)["half1x3"] = EHTokHalf1x3; + (*KeywordMap)["half1x4"] = EHTokHalf1x4; + (*KeywordMap)["half2x1"] = EHTokHalf2x1; + (*KeywordMap)["half2x2"] = EHTokHalf2x2; + (*KeywordMap)["half2x3"] = EHTokHalf2x3; + (*KeywordMap)["half2x4"] = EHTokHalf2x4; + (*KeywordMap)["half3x1"] = EHTokHalf3x1; + (*KeywordMap)["half3x2"] = EHTokHalf3x2; + (*KeywordMap)["half3x3"] = EHTokHalf3x3; + (*KeywordMap)["half3x4"] = EHTokHalf3x4; + (*KeywordMap)["half4x1"] = EHTokHalf4x1; + (*KeywordMap)["half4x2"] = EHTokHalf4x2; + (*KeywordMap)["half4x3"] = EHTokHalf4x3; + (*KeywordMap)["half4x4"] = EHTokHalf4x4; (*KeywordMap)["double1x1"] = EHTokDouble1x1; (*KeywordMap)["double1x2"] = EHTokDouble1x2; (*KeywordMap)["double1x3"] = EHTokDouble1x3; @@ -256,9 +331,31 @@ void HlslScanContext::fillInKeywordMap() (*KeywordMap)["TextureCubeArray"] = EHTokTextureCubearray; (*KeywordMap)["Texture2DMS"] = EHTokTexture2DMS; (*KeywordMap)["Texture2DMSArray"] = EHTokTexture2DMSarray; + (*KeywordMap)["RWTexture1D"] = EHTokRWTexture1d; + (*KeywordMap)["RWTexture1DArray"] = EHTokRWTexture1darray; + (*KeywordMap)["RWTexture2D"] = EHTokRWTexture2d; + (*KeywordMap)["RWTexture2DArray"] = EHTokRWTexture2darray; + (*KeywordMap)["RWTexture3D"] = EHTokRWTexture3d; + (*KeywordMap)["RWBuffer"] = EHTokRWBuffer; + (*KeywordMap)["SubpassInput"] = EHTokSubpassInput; + (*KeywordMap)["SubpassInputMS"] = EHTokSubpassInputMS; + (*KeywordMap)["AppendStructuredBuffer"] = EHTokAppendStructuredBuffer; + (*KeywordMap)["ByteAddressBuffer"] = EHTokByteAddressBuffer; + (*KeywordMap)["ConsumeStructuredBuffer"] = EHTokConsumeStructuredBuffer; + (*KeywordMap)["RWByteAddressBuffer"] = EHTokRWByteAddressBuffer; + (*KeywordMap)["RWStructuredBuffer"] = EHTokRWStructuredBuffer; + (*KeywordMap)["StructuredBuffer"] = EHTokStructuredBuffer; + (*KeywordMap)["TextureBuffer"] = EHTokTextureBuffer; + + (*KeywordMap)["class"] = EHTokClass; (*KeywordMap)["struct"] = EHTokStruct; + (*KeywordMap)["cbuffer"] = EHTokCBuffer; + (*KeywordMap)["ConstantBuffer"] = EHTokConstantBuffer; + (*KeywordMap)["tbuffer"] = EHTokTBuffer; (*KeywordMap)["typedef"] = EHTokTypedef; + (*KeywordMap)["this"] = EHTokThis; + (*KeywordMap)["namespace"] = EHTokNamespace; (*KeywordMap)["true"] = EHTokBoolConstant; (*KeywordMap)["false"] = EHTokBoolConstant; @@ -278,11 +375,10 @@ void HlslScanContext::fillInKeywordMap() // TODO: get correct set here ReservedSet = new std::unordered_set; - + ReservedSet->insert("auto"); ReservedSet->insert("catch"); ReservedSet->insert("char"); - ReservedSet->insert("class"); ReservedSet->insert("const_cast"); ReservedSet->insert("enum"); ReservedSet->insert("explicit"); @@ -301,7 +397,6 @@ void HlslScanContext::fillInKeywordMap() ReservedSet->insert("sizeof"); ReservedSet->insert("static_cast"); ReservedSet->insert("template"); - ReservedSet->insert("this"); ReservedSet->insert("throw"); ReservedSet->insert("try"); ReservedSet->insert("typename"); @@ -309,6 +404,47 @@ void HlslScanContext::fillInKeywordMap() ReservedSet->insert("unsigned"); ReservedSet->insert("using"); ReservedSet->insert("virtual"); + + SemanticMap = new std::unordered_map; + + // in DX9, all outputs had to have a semantic associated with them, that was either consumed + // by the system or was a specific register assignment + // in DX10+, only semantics with the SV_ prefix have any meaning beyond decoration + // Fxc will only accept DX9 style semantics in compat mode + // Also, in DX10 if a SV value is present as the input of a stage, but isn't appropriate for that + // stage, it would just be ignored as it is likely there as part of an output struct from one stage + // to the next + bool bParseDX9 = false; + if (bParseDX9) { + (*SemanticMap)["PSIZE"] = EbvPointSize; + (*SemanticMap)["FOG"] = EbvFogFragCoord; + (*SemanticMap)["DEPTH"] = EbvFragDepth; + (*SemanticMap)["VFACE"] = EbvFace; + (*SemanticMap)["VPOS"] = EbvFragCoord; + } + + (*SemanticMap)["SV_POSITION"] = EbvPosition; + (*SemanticMap)["SV_VERTEXID"] = EbvVertexIndex; + (*SemanticMap)["SV_VIEWPORTARRAYINDEX"] = EbvViewportIndex; + (*SemanticMap)["SV_TESSFACTOR"] = EbvTessLevelOuter; + (*SemanticMap)["SV_SAMPLEINDEX"] = EbvSampleId; + (*SemanticMap)["SV_RENDERTARGETARRAYINDEX"] = EbvLayer; + (*SemanticMap)["SV_PRIMITIVEID"] = EbvPrimitiveId; + (*SemanticMap)["SV_OUTPUTCONTROLPOINTID"] = EbvInvocationId; + (*SemanticMap)["SV_ISFRONTFACE"] = EbvFace; + (*SemanticMap)["SV_INSTANCEID"] = EbvInstanceIndex; + (*SemanticMap)["SV_INSIDETESSFACTOR"] = EbvTessLevelInner; + (*SemanticMap)["SV_GSINSTANCEID"] = EbvInvocationId; + (*SemanticMap)["SV_DISPATCHTHREADID"] = EbvGlobalInvocationId; + (*SemanticMap)["SV_GROUPTHREADID"] = EbvLocalInvocationId; + (*SemanticMap)["SV_GROUPINDEX"] = EbvLocalInvocationIndex; + (*SemanticMap)["SV_GROUPID"] = EbvWorkGroupId; + (*SemanticMap)["SV_DOMAINLOCATION"] = EbvTessCoord; + (*SemanticMap)["SV_DEPTH"] = EbvFragDepth; + (*SemanticMap)["SV_COVERAGE"] = EbvSampleMask; + (*SemanticMap)["SV_DEPTHGREATEREQUAL"] = EbvFragDepthGreater; + (*SemanticMap)["SV_DEPTHLESSEQUAL"] = EbvFragDepthLesser; + (*SemanticMap)["SV_STENCILREF"] = EbvFragStencilRef; } void HlslScanContext::deleteKeywordMap() @@ -317,15 +453,26 @@ void HlslScanContext::deleteKeywordMap() KeywordMap = nullptr; delete ReservedSet; ReservedSet = nullptr; + delete SemanticMap; + SemanticMap = nullptr; } -// Wrapper for tokenizeClass()"] = to get everything inside the token. +// Wrapper for tokenizeClass() to get everything inside the token. void HlslScanContext::tokenize(HlslToken& token) { EHlslTokenClass tokenClass = tokenizeClass(token); token.tokenClass = tokenClass; } +glslang::TBuiltInVariable HlslScanContext::mapSemantic(const char* upperCase) +{ + auto it = SemanticMap->find(upperCase); + if (it != SemanticMap->end()) + return it->second; + else + return glslang::EbvNone; +} + // // Fill in token information for the next token, except for the token class. // Returns the enum value of the token class of the next token found. @@ -336,13 +483,14 @@ EHlslTokenClass HlslScanContext::tokenizeClass(HlslToken& token) do { parserToken = &token; TPpToken ppToken; - tokenText = ppContext.tokenize(&ppToken); - if (tokenText == nullptr) + int token = ppContext.tokenize(ppToken); + if (token == EndOfInput) return EHTokNone; + tokenText = ppToken.name; loc = ppToken.loc; parserToken->loc = loc; - switch (ppToken.token) { + switch (token) { case ';': return EHTokSemicolon; case ',': return EHTokComma; case ':': return EHTokColon; @@ -371,11 +519,11 @@ EHlslTokenClass HlslScanContext::tokenizeClass(HlslToken& token) parseContext.error(loc, "illegal use of escape character", "\\", ""); break; - case PpAtomAdd: return EHTokAddAssign; - case PpAtomSub: return EHTokSubAssign; - case PpAtomMul: return EHTokMulAssign; - case PpAtomDiv: return EHTokDivAssign; - case PpAtomMod: return EHTokModAssign; + case PPAtomAddAssign: return EHTokAddAssign; + case PPAtomSubAssign: return EHTokSubAssign; + case PPAtomMulAssign: return EHTokMulAssign; + case PPAtomDivAssign: return EHTokDivAssign; + case PPAtomModAssign: return EHTokModAssign; case PpAtomRight: return EHTokRightOp; case PpAtomLeft: return EHTokLeftOp; @@ -398,8 +546,11 @@ EHlslTokenClass HlslScanContext::tokenizeClass(HlslToken& token) case PpAtomDecrement: return EHTokDecOp; case PpAtomIncrement: return EHTokIncOp; + case PpAtomColonColon: return EHTokColonColon; + case PpAtomConstInt: parserToken->i = ppToken.ival; return EHTokIntConstant; case PpAtomConstUint: parserToken->i = ppToken.ival; return EHTokUintConstant; + case PpAtomConstFloat16: parserToken->d = ppToken.dval; return EHTokFloat16Constant; case PpAtomConstFloat: parserToken->d = ppToken.dval; return EHTokFloatConstant; case PpAtomConstDouble: parserToken->d = ppToken.dval; return EHTokDoubleConstant; case PpAtomIdentifier: @@ -408,13 +559,23 @@ EHlslTokenClass HlslScanContext::tokenizeClass(HlslToken& token) return token; } + case PpAtomConstString: { + parserToken->string = NewPoolTString(tokenText); + return EHTokStringConstant; + } + case EndOfInput: return EHTokNone; default: - char buf[2]; - buf[0] = (char)ppToken.token; - buf[1] = 0; - parseContext.error(loc, "unexpected token", buf, ""); + if (token < PpAtomMaxSingle) { + char buf[2]; + buf[0] = (char)token; + buf[1] = 0; + parseContext.error(loc, "unexpected token", buf, ""); + } else if (tokenText[0] != 0) + parseContext.error(loc, "unexpected token", tokenText, ""); + else + parseContext.error(loc, "unexpected token", "", ""); break; } } while (true); @@ -455,9 +616,31 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier() case EHTokIn: case EHTokOut: case EHTokInOut: + case EHTokPrecise: + case EHTokLayout: + case EHTokGloballyCoherent: + case EHTokInline: + return keyword; + + // primitive types + case EHTokPoint: + case EHTokLine: + case EHTokTriangle: + case EHTokLineAdj: + case EHTokTriangleAdj: + return keyword; + + // stream out types + case EHTokPointStream: + case EHTokLineStream: + case EHTokTriangleStream: + return keyword; + + // Tessellation patches + case EHTokInputPatch: + case EHTokOutputPatch: return keyword; - // template types case EHTokBuffer: case EHTokVector: case EHTokMatrix: @@ -465,9 +648,11 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier() // scalar types case EHTokVoid: + case EHTokString: case EHTokBool: case EHTokInt: case EHTokUint: + case EHTokUint64: case EHTokDword: case EHTokHalf: case EHTokFloat: @@ -499,8 +684,48 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier() case EHTokUint2: case EHTokUint3: case EHTokUint4: + case EHTokHalf1: + case EHTokHalf2: + case EHTokHalf3: + case EHTokHalf4: + case EHTokMin16float1: + case EHTokMin16float2: + case EHTokMin16float3: + case EHTokMin16float4: + case EHTokMin10float1: + case EHTokMin10float2: + case EHTokMin10float3: + case EHTokMin10float4: + case EHTokMin16int1: + case EHTokMin16int2: + case EHTokMin16int3: + case EHTokMin16int4: + case EHTokMin12int1: + case EHTokMin12int2: + case EHTokMin12int3: + case EHTokMin12int4: + case EHTokMin16uint1: + case EHTokMin16uint2: + case EHTokMin16uint3: + case EHTokMin16uint4: // matrix types + case EHTokBool1x1: + case EHTokBool1x2: + case EHTokBool1x3: + case EHTokBool1x4: + case EHTokBool2x1: + case EHTokBool2x2: + case EHTokBool2x3: + case EHTokBool2x4: + case EHTokBool3x1: + case EHTokBool3x2: + case EHTokBool3x3: + case EHTokBool3x4: + case EHTokBool4x1: + case EHTokBool4x2: + case EHTokBool4x3: + case EHTokBool4x4: case EHTokInt1x1: case EHTokInt1x2: case EHTokInt1x3: @@ -517,6 +742,22 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier() case EHTokInt4x2: case EHTokInt4x3: case EHTokInt4x4: + case EHTokUint1x1: + case EHTokUint1x2: + case EHTokUint1x3: + case EHTokUint1x4: + case EHTokUint2x1: + case EHTokUint2x2: + case EHTokUint2x3: + case EHTokUint2x4: + case EHTokUint3x1: + case EHTokUint3x2: + case EHTokUint3x3: + case EHTokUint3x4: + case EHTokUint4x1: + case EHTokUint4x2: + case EHTokUint4x3: + case EHTokUint4x4: case EHTokFloat1x1: case EHTokFloat1x2: case EHTokFloat1x3: @@ -533,6 +774,22 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier() case EHTokFloat4x2: case EHTokFloat4x3: case EHTokFloat4x4: + case EHTokHalf1x1: + case EHTokHalf1x2: + case EHTokHalf1x3: + case EHTokHalf1x4: + case EHTokHalf2x1: + case EHTokHalf2x2: + case EHTokHalf2x3: + case EHTokHalf2x4: + case EHTokHalf3x1: + case EHTokHalf3x2: + case EHTokHalf3x3: + case EHTokHalf3x4: + case EHTokHalf4x1: + case EHTokHalf4x2: + case EHTokHalf4x3: + case EHTokHalf4x4: case EHTokDouble1x1: case EHTokDouble1x2: case EHTokDouble1x3: @@ -569,11 +826,33 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier() case EHTokTextureCubearray: case EHTokTexture2DMS: case EHTokTexture2DMSarray: + case EHTokRWTexture1d: + case EHTokRWTexture1darray: + case EHTokRWTexture2d: + case EHTokRWTexture2darray: + case EHTokRWTexture3d: + case EHTokRWBuffer: + case EHTokAppendStructuredBuffer: + case EHTokByteAddressBuffer: + case EHTokConsumeStructuredBuffer: + case EHTokRWByteAddressBuffer: + case EHTokRWStructuredBuffer: + case EHTokStructuredBuffer: + case EHTokTextureBuffer: + case EHTokSubpassInput: + case EHTokSubpassInputMS: return keyword; // variable, user type, ... + case EHTokClass: case EHTokStruct: case EHTokTypedef: + case EHTokCBuffer: + case EHTokConstantBuffer: + case EHTokTBuffer: + case EHTokThis: + case EHTokNamespace: + return keyword; case EHTokBoolConstant: if (strcmp("true", tokenText) == 0) @@ -621,28 +900,4 @@ EHlslTokenClass HlslScanContext::reservedWord() return EHTokNone; } -EHlslTokenClass HlslScanContext::identifierOrReserved(bool reserved) -{ - if (reserved) { - reservedWord(); - - return EHTokNone; - } - - if (parseContext.forwardCompatible) - parseContext.warn(loc, "using future reserved keyword", tokenText, ""); - - return identifierOrType(); -} - -// For a keyword that was never reserved, until it suddenly -// showed up. -EHlslTokenClass HlslScanContext::nonreservedKeyword(int version) -{ - if (parseContext.version < version) - return identifierOrType(); - - return keyword; -} - } // end namespace glslang diff --git a/Externals/glslang/hlsl/hlslScanContext.h b/Externals/glslang/hlsl/hlslScanContext.h index 144a85343f..9d30a12e1e 100755 --- a/Externals/glslang/hlsl/hlslScanContext.h +++ b/Externals/glslang/hlsl/hlslScanContext.h @@ -1,11 +1,11 @@ // -//Copyright (C) 2016 Google, Inc. +// Copyright (C) 2016 Google, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,18 +19,18 @@ // 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. +// 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. // // @@ -54,7 +54,7 @@ class TPpToken; // Everything needed to fully describe a token. // struct HlslToken { - HlslToken() : string(nullptr), symbol(nullptr) { loc.init(); } + HlslToken() : string(nullptr) { loc.init(); } TSourceLoc loc; // location of token in the source EHlslTokenClass tokenClass; // what kind of token it is union { // what data the token holds @@ -64,7 +64,6 @@ struct HlslToken { bool b; double d; }; - glslang::TSymbol* symbol; // if a symbol-table lookup was done already, this is the result }; // @@ -82,6 +81,7 @@ public: static void deleteKeywordMap(); void tokenize(HlslToken&); + glslang::TBuiltInVariable mapSemantic(const char*); protected: HlslScanContext(HlslScanContext&); diff --git a/Externals/glslang/hlsl/hlslTokenStream.cpp b/Externals/glslang/hlsl/hlslTokenStream.cpp index 47f779a81f..5d9311cfd7 100755 --- a/Externals/glslang/hlsl/hlslTokenStream.cpp +++ b/Externals/glslang/hlsl/hlslTokenStream.cpp @@ -1,11 +1,11 @@ // -//Copyright (C) 2016 Google, Inc. +// Copyright (C) 2016 Google, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,18 +19,18 @@ // 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. +// 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. // #include "hlslTokenStream.h" @@ -39,27 +39,62 @@ namespace glslang { void HlslTokenStream::pushPreToken(const HlslToken& tok) { - assert(preTokenStackSize == 0); - preTokenStack = tok; - ++preTokenStackSize; + assert(preTokenStackSize < tokenBufferSize); + preTokenStack[preTokenStackSize++] = tok; } HlslToken HlslTokenStream::popPreToken() { - assert(preTokenStackSize == 1); - --preTokenStackSize; + assert(preTokenStackSize > 0); - return preTokenStack; + return preTokenStack[--preTokenStackSize]; } void HlslTokenStream::pushTokenBuffer(const HlslToken& tok) { - tokenBuffer = tok; + tokenBuffer[tokenBufferPos] = tok; + tokenBufferPos = (tokenBufferPos+1) % tokenBufferSize; } HlslToken HlslTokenStream::popTokenBuffer() { - return tokenBuffer; + // Back up + tokenBufferPos = (tokenBufferPos+tokenBufferSize-1) % tokenBufferSize; + + return tokenBuffer[tokenBufferPos]; +} + +// +// Make a new source of tokens, not from the source, but from an +// already pre-processed token stream. +// +// This interrupts current token processing which must be restored +// later. Some simplifying assumptions are made (and asserted). +// +void HlslTokenStream::pushTokenStream(const TVector* tokens) +{ + // not yet setup to interrupt a stream that has been receded + // and not yet reconsumed + assert(preTokenStackSize == 0); + + // save current state + currentTokenStack.push_back(token); + + // set up new token stream + tokenStreamStack.push_back(tokens); + + // start position at first token: + token = (*tokens)[0]; + tokenPosition.push_back(0); +} + +// Undo pushTokenStream(), see above +void HlslTokenStream::popTokenStream() +{ + tokenStreamStack.pop_back(); + tokenPosition.pop_back(); + token = currentTokenStack.back(); + currentTokenStack.pop_back(); } // Load 'token' with the next token in the stream of tokens. @@ -68,8 +103,17 @@ void HlslTokenStream::advanceToken() pushTokenBuffer(token); if (preTokenStackSize > 0) token = popPreToken(); - else - scanner.tokenize(token); + else { + if (tokenStreamStack.size() == 0) + scanner.tokenize(token); + else { + ++tokenPosition.back(); + if (tokenPosition.back() >= (int)tokenStreamStack.back()->size()) + token.tokenClass = EHTokNone; + else + token = (*tokenStreamStack.back())[tokenPosition.back()]; + } + } } void HlslTokenStream::recedeToken() diff --git a/Externals/glslang/hlsl/hlslTokenStream.h b/Externals/glslang/hlsl/hlslTokenStream.h index 12c2a2a02d..cb6c9e7234 100755 --- a/Externals/glslang/hlsl/hlslTokenStream.h +++ b/Externals/glslang/hlsl/hlslTokenStream.h @@ -1,11 +1,11 @@ // -//Copyright (C) 2016 Google, Inc. +// Copyright (C) 2016 Google, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -19,18 +19,18 @@ // 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. +// 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 HLSLTOKENSTREAM_H_ @@ -43,7 +43,7 @@ namespace glslang { class HlslTokenStream { public: explicit HlslTokenStream(HlslScanContext& scanner) - : scanner(scanner), preTokenStackSize(0) { } + : scanner(scanner), preTokenStackSize(0), tokenBufferPos(0) { } virtual ~HlslTokenStream() { } public: @@ -52,6 +52,10 @@ namespace glslang { bool acceptTokenClass(EHlslTokenClass); EHlslTokenClass peek() const; bool peekTokenClass(EHlslTokenClass) const; + glslang::TBuiltInVariable mapSemantic(const char* upperCase) { return scanner.mapSemantic(upperCase); } + + void pushTokenStream(const TVector* tokens); + void popTokenStream(); protected: HlslToken token; // the token we are currently looking at, but have not yet accepted @@ -60,22 +64,29 @@ namespace glslang { HlslTokenStream(); HlslTokenStream& operator=(const HlslTokenStream&); - HlslScanContext& scanner; // lexical scanner, to get next token + HlslScanContext& scanner; // lexical scanner, to get next token from source file + TVector*> tokenStreamStack; // for getting the next token from an existing vector of tokens + TVector tokenPosition; + TVector currentTokenStack; + + // This is the number of tokens we can recedeToken() over. + static const int tokenBufferSize = 2; // Previously scanned tokens, returned for future advances, // so logically in front of the token stream. // Is logically a stack; needs last in last out semantics. - // Currently implemented as a stack of size 1. - HlslToken preTokenStack; + // Currently implemented as a stack of size 2. + HlslToken preTokenStack[tokenBufferSize]; int preTokenStackSize; void pushPreToken(const HlslToken&); HlslToken popPreToken(); - // Previously scanned tokens, not yet return for future advances, + // Previously scanned tokens, not yet returned for future advances, // but available for that. // Is logically a fifo for normal advances, and a stack for recession. - // Currently implemented with an intrinsic size of 1. - HlslToken tokenBuffer; + // Currently implemented with an intrinsic size of 2. + HlslToken tokenBuffer[tokenBufferSize]; + int tokenBufferPos; void pushTokenBuffer(const HlslToken&); HlslToken popTokenBuffer(); }; diff --git a/Externals/glslang/hlsl/hlslTokens.h b/Externals/glslang/hlsl/hlslTokens.h index 5a5266ae32..4426bccecb 100755 --- a/Externals/glslang/hlsl/hlslTokens.h +++ b/Externals/glslang/hlsl/hlslTokens.h @@ -1,12 +1,12 @@ // -//Copyright (C) 2016 Google, Inc. -//Copyright (C) 2016 LunarG, Inc. +// Copyright (C) 2016 Google, Inc. +// Copyright (C) 2016 LunarG, Inc. // -//All rights reserved. +// All rights reserved. // -//Redistribution and use in source and binary forms, with or without -//modification, are permitted provided that the following conditions -//are met: +// 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. @@ -20,18 +20,18 @@ // 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. +// 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 EHLSLTOKENS_H_ @@ -64,6 +64,25 @@ enum EHlslTokenClass { EHTokIn, EHTokOut, EHTokInOut, + EHTokLayout, + EHTokGloballyCoherent, + EHTokInline, + + // primitive types + EHTokPoint, + EHTokLine, + EHTokTriangle, + EHTokLineAdj, + EHTokTriangleAdj, + + // stream out types + EHTokPointStream, + EHTokLineStream, + EHTokTriangleStream, + + // Tessellation patches + EHTokInputPatch, + EHTokOutputPatch, // template types EHTokBuffer, @@ -72,9 +91,11 @@ enum EHlslTokenClass { // scalar types EHTokVoid, + EHTokString, EHTokBool, EHTokInt, EHTokUint, + EHTokUint64, EHTokDword, EHTokHalf, EHTokFloat, @@ -106,6 +127,30 @@ enum EHlslTokenClass { EHTokUint2, EHTokUint3, EHTokUint4, + EHTokHalf1, + EHTokHalf2, + EHTokHalf3, + EHTokHalf4, + EHTokMin16float1, + EHTokMin16float2, + EHTokMin16float3, + EHTokMin16float4, + EHTokMin10float1, + EHTokMin10float2, + EHTokMin10float3, + EHTokMin10float4, + EHTokMin16int1, + EHTokMin16int2, + EHTokMin16int3, + EHTokMin16int4, + EHTokMin12int1, + EHTokMin12int2, + EHTokMin12int3, + EHTokMin12int4, + EHTokMin16uint1, + EHTokMin16uint2, + EHTokMin16uint3, + EHTokMin16uint4, // matrix types EHTokInt1x1, @@ -172,6 +217,22 @@ enum EHlslTokenClass { EHTokFloat4x2, EHTokFloat4x3, EHTokFloat4x4, + EHTokHalf1x1, + EHTokHalf1x2, + EHTokHalf1x3, + EHTokHalf1x4, + EHTokHalf2x1, + EHTokHalf2x2, + EHTokHalf2x3, + EHTokHalf2x4, + EHTokHalf3x1, + EHTokHalf3x2, + EHTokHalf3x3, + EHTokHalf3x4, + EHTokHalf4x1, + EHTokHalf4x2, + EHTokHalf4x3, + EHTokHalf4x4, EHTokDouble1x1, EHTokDouble1x2, EHTokDouble1x3, @@ -207,19 +268,43 @@ enum EHlslTokenClass { EHTokTextureCubearray, EHTokTexture2DMS, EHTokTexture2DMSarray, + EHTokRWTexture1d, + EHTokRWTexture1darray, + EHTokRWTexture2d, + EHTokRWTexture2darray, + EHTokRWTexture3d, + EHTokRWBuffer, + EHTokSubpassInput, + EHTokSubpassInputMS, + + // Structure buffer variants + EHTokAppendStructuredBuffer, + EHTokByteAddressBuffer, + EHTokConsumeStructuredBuffer, + EHTokRWByteAddressBuffer, + EHTokRWStructuredBuffer, + EHTokStructuredBuffer, + EHTokTextureBuffer, // variable, user type, ... EHTokIdentifier, - EHTokTypeName, + EHTokClass, EHTokStruct, + EHTokCBuffer, + EHTokTBuffer, EHTokTypedef, + EHTokThis, + EHTokNamespace, + EHTokConstantBuffer, // constant + EHTokFloat16Constant, EHTokFloatConstant, EHTokDoubleConstant, EHTokIntConstant, EHTokUintConstant, EHTokBoolConstant, + EHTokStringConstant, // control flow EHTokFor, @@ -267,6 +352,7 @@ enum EHlslTokenClass { EHTokDot, EHTokComma, EHTokColon, + EHTokColonColon, EHTokSemicolon, EHTokBang, EHTokDash, diff --git a/Externals/glslang/known_good.json b/Externals/glslang/known_good.json new file mode 100644 index 0000000000..7027d48277 --- /dev/null +++ b/Externals/glslang/known_good.json @@ -0,0 +1,18 @@ +{ + "commits" : [ + { + "name" : "spirv-tools", + "site" : "github", + "subrepo" : "KhronosGroup/SPIRV-Tools", + "subdir" : "External/spirv-tools", + "commit" : "545d6ca26d3beddcb8dc5dc363deb1544a2eeb87" + }, + { + "name" : "spirv-tools/external/spirv-headers", + "site" : "github", + "subrepo" : "KhronosGroup/SPIRV-Headers", + "subdir" : "External/spirv-tools/external/spirv-headers", + "commit" : "12f8de9f04327336b699b1b80aa390ae7f9ddbf4" + } + ] +} diff --git a/Externals/glslang/known_good_khr.json b/Externals/glslang/known_good_khr.json new file mode 100644 index 0000000000..083e7711c6 --- /dev/null +++ b/Externals/glslang/known_good_khr.json @@ -0,0 +1,18 @@ +{ + "commits" : [ + { + "name" : "spirv-tools", + "site" : "gitlab", + "subrepo" : "spirv/spirv-tools", + "subdir" : "External/spirv-tools", + "commit" : "d4e2c2eaa6fd2e9f9cd218ea9add9b0c8ae759ba" + }, + { + "name" : "spirv-tools/external/spirv-headers", + "site" : "gitlab", + "subrepo" : "spirv/SPIRV-Headers", + "subdir" : "External/spirv-tools/external/spirv-headers", + "commit" : "4082a777bd5df31ed45acf40e64263094e85ed2e" + } + ] +} diff --git a/Externals/glslang/make-revision b/Externals/glslang/make-revision index 492e437562..a89ff08772 100755 --- a/Externals/glslang/make-revision +++ b/Externals/glslang/make-revision @@ -1,10 +1,6 @@ #!/bin/sh ( echo "// This header is generated by the make-revision script." -echo "// For the version, it uses the latest git tag followed by the number of commits." -echo "// For the date, it uses the current date (when then script is run)." - echo -echo \#define GLSLANG_REVISION \"`git describe --tags --abbrev=0`.`git log --oneline | wc -l`\" -echo \#define GLSLANG_DATE \"`date +%d-%b-%Y`\" +echo \#define GLSLANG_PATCH_LEVEL `git log --oneline | wc -l` ) > glslang/Include/revision.h diff --git a/Externals/glslang/update_glslang_sources.py b/Externals/glslang/update_glslang_sources.py new file mode 100755 index 0000000000..550bc2b143 --- /dev/null +++ b/Externals/glslang/update_glslang_sources.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python + +# Copyright 2017 The Glslang Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Get source files for Glslang and its dependencies from public repositories. +""" + +from __future__ import print_function + +import argparse +import json +import distutils.dir_util +import os.path +import subprocess +import sys + +KNOWN_GOOD_FILE = 'known_good.json' + +SITE_TO_KNOWN_GOOD_FILE = { 'github' : 'known_good.json', + 'gitlab' : 'known_good_khr.json' } + +# Maps a site name to its hostname. +SITE_TO_HOST = { 'github' : 'https://github.com/', + 'gitlab' : 'git@gitlab.khronos.org:' } + +VERBOSE = True + + +def command_output(cmd, directory, fail_ok=False): + """Runs a command in a directory and returns its standard output stream. + + Captures the standard error stream. + + Raises a RuntimeError if the command fails to launch or otherwise fails. + """ + if VERBOSE: + print('In {d}: {cmd}'.format(d=directory, cmd=cmd)) + p = subprocess.Popen(cmd, + cwd=directory, + stdout=subprocess.PIPE) + (stdout, _) = p.communicate() + if p.returncode != 0 and not fail_ok: + raise RuntimeError('Failed to run {} in {}'.format(cmd, directory)) + if VERBOSE: + print(stdout) + return stdout + + +def command_retval(cmd, directory): + """Runs a command in a directory and returns its return value. + + Captures the standard error stream. + """ + p = subprocess.Popen(cmd, + cwd=directory, + stdout=subprocess.PIPE) + (stdout, _) = p.communicate() + return p.returncode + + +class GoodCommit(object): + """Represents a good commit for a repository.""" + + def __init__(self, json): + """Initializes this good commit object. + + Args: + 'json': A fully populated JSON object describing the commit. + """ + self._json = json + self.name = json['name'] + self.site = json['site'] + self.subrepo = json['subrepo'] + self.subdir = json['subdir'] if ('subdir' in json) else '.' + self.commit = json['commit'] + + def GetUrl(self): + """Returns the URL for the repository.""" + host = SITE_TO_HOST[self.site] + return '{host}{subrepo}'.format( + host=host, + subrepo=self.subrepo) + + def AddRemote(self): + """Add the remote 'known-good' if it does not exist.""" + print('Ignore "fatal" errors for missing known-good remote:') + if command_retval(['git', 'remote', 'show', 'known-good'], self.subdir) != 0: + command_output(['git', 'remote', 'add', 'known-good', self.GetUrl()], self.subdir) + + def HasCommit(self): + """Check if the repository contains the known-good commit.""" + return 0 == subprocess.call(['git', 'rev-parse', '--verify', '--quiet', + self.commit + "^{commit}"], + cwd=self.subdir) + + def Clone(self): + distutils.dir_util.mkpath(self.subdir) + command_output(['git', 'clone', self.GetUrl(), '.'], self.subdir) + + def Fetch(self): + command_output(['git', 'fetch', 'known-good'], self.subdir) + + def Checkout(self): + if not os.path.exists(os.path.join(self.subdir,'.git')): + self.Clone() + self.AddRemote() + if not self.HasCommit(): + self.Fetch() + command_output(['git', 'checkout', self.commit], self.subdir) + + +def GetGoodCommits(site): + """Returns the latest list of GoodCommit objects.""" + known_good_file = SITE_TO_KNOWN_GOOD_FILE[site] + with open(known_good_file) as known_good: + return [GoodCommit(c) for c in json.loads(known_good.read())['commits']] + + +def main(): + parser = argparse.ArgumentParser(description='Get Glslang source dependencies at a known-good commit') + parser.add_argument('--dir', dest='dir', default='.', + help="Set target directory for Glslang source root. Default is \'.\'.") + parser.add_argument('--site', dest='site', default='github', + help="Set git server site. Default is github.") + + args = parser.parse_args() + + commits = GetGoodCommits(args.site) + + distutils.dir_util.mkpath(args.dir) + print('Change directory to {d}'.format(d=args.dir)) + os.chdir(args.dir) + + # Create the subdirectories in sorted order so that parent git repositories + # are created first. + for c in sorted(commits, key=lambda x: x.subdir): + print('Get {n}\n'.format(n=c.name)) + c.Checkout() + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/Source/Core/VideoBackends/Vulkan/ShaderCompiler.cpp b/Source/Core/VideoBackends/Vulkan/ShaderCompiler.cpp index 0633456ceb..82f0e825a5 100644 --- a/Source/Core/VideoBackends/Vulkan/ShaderCompiler.cpp +++ b/Source/Core/VideoBackends/Vulkan/ShaderCompiler.cpp @@ -112,7 +112,7 @@ bool CompileShaderToSPV(SPIRVCodeVector* out_code, EShLanguage stage, const char std::unique_ptr shader = std::make_unique(stage); std::unique_ptr program; - glslang::TShader::ForbidInclude includer; + glslang::TShader::ForbidIncluder includer; EProfile profile = ECoreProfile; EShMessages messages = static_cast(EShMsgDefault | EShMsgSpvRules | EShMsgVulkanRules);