diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index d9a9c5cb7c..008a8678c5 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -9,6 +9,6 @@ jobs: steps: - uses: actions/checkout@v2 - name: Build web - run: docker-compose up + run: docker-compose -f source/wasm/docker-compose.yml --project-directory . up - name: Run tests run: node test/wasm/test.js diff --git a/CMakeLists.txt b/CMakeLists.txt index 63eeae8717..f9bfb4a303 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required(VERSION 3.17.2) if (POLICY CMP0048) cmake_policy(SET CMP0048 NEW) endif() diff --git a/DEPS b/DEPS index d6242d815f..b16d696431 100644 --- a/DEPS +++ b/DEPS @@ -4,7 +4,14 @@ vars = { 'github': 'https://github.com', 'effcee_revision': '35912e1b7778ec2ddcff7e7188177761539e59e0', - 'googletest_revision': 'd9bb8412d60b993365abb53f00b6dad9b2c01b62', + + # Pin to the last version of googletest that supports C++11. + # Anything later requires C++14 + 'googletest_revision': 'v1.12.0', + + # Use protobufs before they gained the dependency on abseil + 'protobuf_revision': 'v3.13.0.1', + 're2_revision': 'd2836d1b1c34c4e330a85a1006201db474bf2c8a', 'spirv_headers_revision': '34d04647d384e0aed037e7a2662a655fc39841bb', } @@ -16,6 +23,9 @@ deps = { 'external/googletest': Var('github') + '/google/googletest.git@' + Var('googletest_revision'), + 'external/protobuf': + Var('github') + '/protocolbuffers/protobuf.git@' + Var('protobuf_revision'), + 'external/re2': Var('github') + '/google/re2.git@' + Var('re2_revision'), diff --git a/build_defs.bzl b/build_defs.bzl index a94a425268..3a69de5c7b 100644 --- a/build_defs.bzl +++ b/build_defs.bzl @@ -4,7 +4,9 @@ COMMON_COPTS = [ "-DSPIRV_CHECK_CONTEXT", "-DSPIRV_COLOR_TERMINAL", ] + select({ - "@bazel_tools//src/conditions:windows": [], + # On Windows, assume MSVC. + # C++14 is the default in VisualStudio 2017. + "@platforms//os:windows": [], "//conditions:default": [ "-DSPIRV_LINUX", "-DSPIRV_TIMER_ENABLED", @@ -27,7 +29,7 @@ COMMON_COPTS = [ TEST_COPTS = COMMON_COPTS + [ ] + select({ - "@bazel_tools//src/conditions:windows": [ + "@platforms//os:windows": [ # Disable C4503 "decorated name length exceeded" warning, # triggered by some heavily templated types. # We don't care much about that in test code. diff --git a/kokoro/scripts/linux/build-docker.sh b/kokoro/scripts/linux/build-docker.sh index 80043b8a4e..7d62ee3660 100755 --- a/kokoro/scripts/linux/build-docker.sh +++ b/kokoro/scripts/linux/build-docker.sh @@ -30,14 +30,6 @@ fi cd $ROOT_DIR -function clone_if_missing() { - url=$1 - dir=$2 - if [[ ! -d "$dir" ]]; then - git clone ${@:3} "$url" "$dir" - fi -} - function clean_dir() { dir=$1 if [[ -d "$dir" ]]; then @@ -46,12 +38,8 @@ function clean_dir() { mkdir "$dir" } -clone_if_missing https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers --depth=1 -clone_if_missing https://github.com/google/googletest external/googletest -pushd external/googletest; git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7; popd -clone_if_missing https://github.com/google/effcee external/effcee --depth=1 -clone_if_missing https://github.com/google/re2 external/re2 --depth=1 -clone_if_missing https://github.com/protocolbuffers/protobuf external/protobuf --branch v3.13.0.1 +# Get source for dependencies, as specified in the DEPS file +/usr/bin/python3 utils/git-sync-deps --treeless if [ $TOOL = "cmake" ]; then using cmake-3.17.2 diff --git a/kokoro/scripts/macos/build.sh b/kokoro/scripts/macos/build.sh index 3618e69053..1d346e7618 100644 --- a/kokoro/scripts/macos/build.sh +++ b/kokoro/scripts/macos/build.sh @@ -31,12 +31,7 @@ chmod +x ninja export PATH="$PWD:$PATH" cd $SRC -git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers -git clone https://github.com/google/googletest external/googletest -cd external && cd googletest && git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7 && cd .. && cd .. -git clone --depth=1 https://github.com/google/effcee external/effcee -git clone --depth=1 https://github.com/google/re2 external/re2 -git clone --depth=1 --branch v3.13.0.1 https://github.com/protocolbuffers/protobuf external/protobuf +python3 utils/git-sync-deps --treeless mkdir build && cd $SRC/build diff --git a/kokoro/scripts/windows/build.bat b/kokoro/scripts/windows/build.bat index d5ea6d0c20..89e1f01848 100644 --- a/kokoro/scripts/windows/build.bat +++ b/kokoro/scripts/windows/build.bat @@ -24,14 +24,6 @@ set VS_VERSION=%2 :: Force usage of python 3.6 set PATH=C:\python36;"C:\Program Files\cmake-3.23.1-windows-x86_64\bin";%PATH% -cd %SRC% -git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers -git clone https://github.com/google/googletest external/googletest -cd external && cd googletest && git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7 && cd .. && cd .. -git clone --depth=1 https://github.com/google/effcee external/effcee -git clone --depth=1 https://github.com/google/re2 external/re2 -git clone --depth=1 --branch v3.13.0.1 https://github.com/protocolbuffers/protobuf external/protobuf - :: ######################################### :: set up msvc build env :: ######################################### @@ -41,6 +33,8 @@ if %VS_VERSION% == 2017 ( ) cd %SRC% +python utils/git-sync-deps --treeless + mkdir build cd build diff --git a/source/val/validate_cfg.cpp b/source/val/validate_cfg.cpp index 24d2416927..9ba66f4224 100644 --- a/source/val/validate_cfg.cpp +++ b/source/val/validate_cfg.cpp @@ -560,7 +560,7 @@ spv_result_t StructuredSwitchChecks(ValidationState_t& _, Function* function, target_block->structurally_reachable() && !header->structurally_dominates(*target_block)) { return _.diag(SPV_ERROR_INVALID_CFG, header->label()) - << "Selection header " << _.getIdName(header->id()) + << "Switch header " << _.getIdName(header->id()) << " does not structurally dominate its case construct " << _.getIdName(target); } diff --git a/docker-compose.yml b/source/wasm/docker-compose.yml similarity index 84% rename from docker-compose.yml rename to source/wasm/docker-compose.yml index fb6d114ffb..2340fdb02c 100644 --- a/docker-compose.yml +++ b/source/wasm/docker-compose.yml @@ -1,7 +1,7 @@ version: "3" services: build: - image: emscripten/emsdk:2.0.2 + image: emscripten/emsdk:3.1.28 environment: GITHUB_RUN_NUMBER: ${GITHUB_RUN_NUMBER:-} working_dir: /app diff --git a/test/val/val_cfg_test.cpp b/test/val/val_cfg_test.cpp index 561e817e74..d876c4881d 100644 --- a/test/val/val_cfg_test.cpp +++ b/test/val/val_cfg_test.cpp @@ -2064,6 +2064,106 @@ OpFunctionEnd ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(ValidateCFG, OpSwitchTargetCannotBeOuterLoopMergeBlock) { + std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 + +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpTypeBool +%4 = OpUndef %3 +%5 = OpTypeInt 32 0 +%6 = OpConstant %5 0 + +%7 = OpFunction %1 None %2 + +%8 = OpLabel +OpBranch %9 + +%9 = OpLabel +OpLoopMerge %10 %11 None +OpBranch %12 + +%12 = OpLabel +OpSelectionMerge %13 None +OpSwitch %6 %13 0 %10 1 %14 + +%14 = OpLabel +OpBranch %13 + +%13 = OpLabel +OpBranch %11 + +%11 = OpLabel +OpBranch %9 + +%10 = OpLabel +OpReturn + +OpFunctionEnd +)"; + + CompileSuccessfully(text); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Switch header '12[%12]' does not structurally dominate its case construct '10[%10]'\n" + " %12 = OpLabel")); +} + +TEST_F(ValidateCFG, OpSwitchTargetCannotBeOuterLoopContinueBlock) { + std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 + +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpTypeBool +%4 = OpUndef %3 +%5 = OpTypeInt 32 0 +%6 = OpConstant %5 0 + +%7 = OpFunction %1 None %2 + +%8 = OpLabel +OpBranch %9 + +%9 = OpLabel +OpLoopMerge %10 %11 None +OpBranch %12 + +%12 = OpLabel +OpSelectionMerge %13 None +OpSwitch %6 %13 0 %11 1 %14 + +%14 = OpLabel +OpBranch %13 + +%13 = OpLabel +OpBranch %11 + +%11 = OpLabel +OpBranch %9 + +%10 = OpLabel +OpReturn + +OpFunctionEnd +)"; + + CompileSuccessfully(text); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Switch header '12[%12]' does not structurally dominate its case construct '11[%11]'\n" + " %12 = OpLabel")); +} + TEST_F(ValidateCFG, WrongOperandList) { std::string text = R"( OpCapability Shader diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 86d0bc46a0..ad5f336fec 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -69,6 +69,22 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES}) endif(SPIRV_BUILD_FUZZER) if(ENABLE_SPIRV_TOOLS_INSTALL) - install(TARGETS ${SPIRV_INSTALL_TARGETS} DESTINATION ${CMAKE_INSTALL_BINDIR}) + install(TARGETS ${SPIRV_INSTALL_TARGETS} EXPORT SPIRV-Tools-toolsTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + export(EXPORT SPIRV-Tools-toolsTargets FILE SPIRV-Tools-toolsTargets.cmake) + + spvtools_config_package_dir(SPIRV-Tools-tools PACKAGE_DIR) + install(EXPORT SPIRV-Tools-toolsTargets FILE SPIRV-Tools-toolsTargets.cmake + DESTINATION ${PACKAGE_DIR}) + + file(WRITE ${CMAKE_BINARY_DIR}/SPIRV-Tools-toolsConfig.cmake + "include(CMakeFindDependencyMacro)\n" + "find_dependency(${SPIRV_TOOLS})\n" + "include(\${CMAKE_CURRENT_LIST_DIR}/SPIRV-Tools-toolsTargets.cmake)\n" + ) + + install(FILES ${CMAKE_BINARY_DIR}/SPIRV-Tools-toolsConfig.cmake DESTINATION ${PACKAGE_DIR}) endif(ENABLE_SPIRV_TOOLS_INSTALL) endif() diff --git a/utils/git-sync-deps b/utils/git-sync-deps index 7a7e606ff1..6549afb1e6 100755 --- a/utils/git-sync-deps +++ b/utils/git-sync-deps @@ -28,10 +28,9 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """Parse a DEPS file and git checkout all of the dependencies. +""" -Args: - An optional list of deps_os values. - +EXTRA_HELP = """ Environment Variables: GIT_EXECUTABLE: path to "git" binary; if unset, will look for one of ['git', 'git.exe', 'git.bat'] in your default path. @@ -52,6 +51,7 @@ Git Config: """ +import argparse import os import re import subprocess @@ -59,12 +59,14 @@ import sys import threading from builtins import bytes - def git_executable(): """Find the git executable. Returns: - A string suitable for passing to subprocess functions, or None. + A triple: + A string suitable for passing to subprocess functions, or None. + The major version number + The minor version number """ envgit = os.environ.get('GIT_EXECUTABLE') searchlist = ['git', 'git.exe', 'git.bat'] @@ -72,30 +74,36 @@ def git_executable(): searchlist.insert(0, envgit) with open(os.devnull, 'w') as devnull: for git in searchlist: + major=None + minor=None try: - subprocess.call([git, '--version'], stdout=devnull) + version_info = subprocess.check_output([git, '--version']).decode('utf-8') + match = re.search("^git version (\d+)\.(\d+)",version_info) + print("Using {}".format(version_info)) + if match: + major = int(match.group(1)) + minor = int(match.group(2)) + else: + continue except (OSError,): continue - return git - return None + return (git,major,minor) + return (None,0,0) DEFAULT_DEPS_PATH = os.path.normpath( os.path.join(os.path.dirname(__file__), os.pardir, 'DEPS')) +def get_deps_os_str(deps_file): + parsed_deps = parse_file_to_dict(deps_file) + parts = [] + if 'deps_os' in parsed_deps: + for deps_os in parsed_deps['deps_os']: + parts.append(' [{}]]'.format(deps_os)) + return "\n".join(parts) -def usage(deps_file_path = None): - sys.stderr.write( - 'Usage: run to grab dependencies, with optional platform support:\n') - sys.stderr.write(' %s %s' % (sys.executable, __file__)) - if deps_file_path: - parsed_deps = parse_file_to_dict(deps_file_path) - if 'deps_os' in parsed_deps: - for deps_os in parsed_deps['deps_os']: - sys.stderr.write(' [%s]' % deps_os) - sys.stderr.write('\n\n') - sys.stderr.write(__doc__) - +def looks_like_raw_commit(commit): + return re.match('^[a-f0-9]{40}$', commit) is not None def git_repository_sync_is_disabled(git, directory): try: @@ -125,14 +133,14 @@ def is_git_toplevel(git, directory): def status(directory, checkoutable): def truncate(s, length): - return s if len(s) <= length else s[:(length - 3)] + '...' + return s if len(s) <= length else '...' + s[-(length - 3):] dlen = 36 directory = truncate(directory, dlen) checkoutable = truncate(checkoutable, 40) sys.stdout.write('%-*s @ %s\n' % (dlen, directory, checkoutable)) -def git_checkout_to_directory(git, repo, checkoutable, directory, verbose): +def git_checkout_to_directory(git, repo, checkoutable, directory, verbose, treeless): """Checkout (and clone if needed) a Git repository. Args: @@ -147,13 +155,22 @@ def git_checkout_to_directory(git, repo, checkoutable, directory, verbose): directory (string) the path into which the repository should be checked out. - verbose (boolean) + verbose (boolean): emit status info to stdout + + treeless (boolean): when true, clone without any trees. Raises an exception if any calls to git fail. """ if not os.path.isdir(directory): + # Use blobless or treeless checkouts for faster downloads. + # This defers some work to checkout time. + # https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/ + filter = ['--filter=tree:0'] if treeless else ['--filter=blob:none'] + # If the thing to check out looks like a tag (and not like a commit), + # then limit the checkout to that branch. + branch = [] if looks_like_raw_commit(checkoutable) else ['--branch={}'.format(checkoutable)] subprocess.check_call( - [git, 'clone', '--quiet', repo, directory]) + [git, 'clone', '--quiet', '--single-branch'] + filter + branch + [repo, directory]) if not is_git_toplevel(git, directory): # if the directory exists, but isn't a git repo, you will modify @@ -200,7 +217,7 @@ def parse_file_to_dict(path): return dictionary -def git_sync_deps(deps_file_path, command_line_os_requests, verbose): +def git_sync_deps(deps_file_path, command_line_os_requests, verbose, treeless): """Grab dependencies, with optional platform support. Args: @@ -210,11 +227,20 @@ def git_sync_deps(deps_file_path, command_line_os_requests, verbose): List of strings that should each be a key in the deps_os dictionary in the DEPS file. + verbose (boolean): emit status info to stdout + + treeless (boolean): when true, clone as treeless instead of blobless + Raises git Exceptions. """ - git = git_executable() + (git,git_major,git_minor) = git_executable() assert git + # --filter=tree:0 is available in git 2.20 and later + if (git_major,git_minor) < (2,20): + print("disabling --treeless: git is older than v2.20") + treeless = False + deps_file_directory = os.path.dirname(deps_file_path) deps_file = parse_file_to_dict(deps_file_path) dependencies = deps_file['deps'].copy() @@ -241,7 +267,7 @@ def git_sync_deps(deps_file_path, command_line_os_requests, verbose): relative_directory = os.path.join(deps_file_directory, directory) list_of_arg_lists.append( - (git, repo, checkoutable, relative_directory, verbose)) + (git, repo, checkoutable, relative_directory, verbose, treeless)) multithread(git_checkout_to_directory, list_of_arg_lists) @@ -264,17 +290,47 @@ def multithread(function, list_of_arg_lists): def main(argv): - deps_file_path = os.environ.get('GIT_SYNC_DEPS_PATH', DEFAULT_DEPS_PATH) - verbose = not bool(os.environ.get('GIT_SYNC_DEPS_QUIET', False)) - - if '--help' in argv or '-h' in argv: - usage(deps_file_path) - return 1 - - git_sync_deps(deps_file_path, argv, verbose) - # subprocess.check_call( - # [sys.executable, - # os.path.join(os.path.dirname(deps_file_path), 'bin', 'fetch-gn')]) + argparser = argparse.ArgumentParser( + prog = "git-sync-deps", + description = "Checkout git-based dependencies as specified by the DEPS file", + add_help=False # Because we want to print deps_os with -h option + ) + argparser.add_argument("--help", "-h", + action='store_true', + help="show this help message and exit") + argparser.add_argument("--deps", + default = os.environ.get('GIT_SYNC_DEPS_PATH', DEFAULT_DEPS_PATH), + help="location of the the DEPS file") + argparser.add_argument("--verbose", + default=not bool(os.environ.get('GIT_SYNC_DEPS_QUIET', False)), + action='store_true', + help="be verbose: print status messages") + argparser.add_argument("--treeless", + default=False, + action='store_true', + help=""" + Clone repos without trees (--filter=tree:0). + This is the fastest option for a build machine, + when you only need a single commit. + Defers getting objects until checking out a commit. + + The default is to clone with trees but without blobs. + + Only takes effect if using git 2.20 or later. + + See https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/ + """) + argparser.add_argument("os_requests",nargs="*", + help="OS requests, as keys in the deps_os dictionariy in the DEPS file") + + args = argparser.parse_args() + if args.help: + print(argparser.format_help()) + print(EXTRA_HELP) + print(get_deps_os_str(args.deps)) + return 0 + + git_sync_deps(args.deps, args.os_requests, args.verbose, args.treeless) return 0