diff --git a/.bazelrc b/.bazelrc index f2b63fda1..61306e8f6 100644 --- a/.bazelrc +++ b/.bazelrc @@ -15,7 +15,6 @@ # ~~~~ General flags ~~~~ # Common flags -common --announce_rc common --experimental_repo_remote_exec common --verbose_failures @@ -25,25 +24,20 @@ common --enable_platform_specific_config build:linux --copt=-std=c++17 build:linux --cxxopt=-std=c++17 -build:linux --per_file_copt="googletest/.*@-Xassembler,-W" +build:linux --copt=-O3 build:macos --copt=-std=c++17 build:macos --cxxopt=-std=c++17 +build:macos --copt=-O3 build:windows --copt=/std:c++17 build:windows --cxxopt=/std:c++17 - -build --copt=-D_GLIBCXX_USE_CXX11_ABI=1 -build --cxxopt=-D_GLIBCXX_USE_CXX11_ABI=1 +build:windows --copt=/O2 # The default for vector instruction sets is to exclude them. # Config options later in this file can be layered to enable them. build --build_tag_filters=-avx,-sse test --test_tag_filters=-avx,-sse -# "bazel run" inherits options from "build". Our run targets don't have tags, -# so we must clear the filter explicitly or we get "No targets found to run". -run:sse --build_tag_filters= -run:avx --build_tag_filters= # CUDA options build:cuda --@local_config_cuda//:enable_cuda @@ -56,9 +50,11 @@ test --test_timeout=600 # Configs for verbose builds & tests common:verbose --announce_rc common:verbose --auto_output_filter=none -build:verbose --show_progress_rate_limit=1 +common:verbose --subcommands test:verbose --test_summary=detailed +# Flags to silence warnings we can't do anything about. +build:linux --per_file_copt="googletest/.*@-Xassembler,-W" # ~~~~ Sanitizers (choose one, or nosan for none) ~~~~ @@ -81,23 +77,41 @@ build:msan --linkopt=-fsanitize=leak build:nosan -- -# ~~~~ Instruction set options (choose one) ~~~~ +# ~~~~ Instruction set options (can be combined) ~~~~ + +# Build with AVX +build:avx --define=qsim_avx=true +build:avx --build_tag_filters= +test:avx --test_tag_filters= -# Build with AVX2 + FMA -build:avx --copt=-O3 -build:avx --copt=-mavx2 -build:avx --copt=-mfma -build:avx --build_tag_filters=avx --ui_event_filters=-WARNING -test:avx --test_tag_filters=avx --ui_event_filters=-WARNING +# Build with AVX2 +build:avx2 --define=qsim_avx2=true +build:avx2 --build_tag_filters= +test:avx2 --test_tag_filters= + +# Build with AVX512 +build:avx512 --define=qsim_avx512=true +build:avx512 --build_tag_filters= +test:avx512 --test_tag_filters= # Build with SSE -build:sse --copt=-O3 -build:sse --copt=-msse4 -build:sse --build_tag_filters=sse --ui_event_filters=-WARNING -test:sse --test_tag_filters=sse --ui_event_filters=-WARNING +build:sse --define=qsim_sse=true +build:sse --build_tag_filters= +test:sse --test_tag_filters= + +# Build with BMI +build:bmi --config=bmi2 + +# Build with BMI2 +build:bmi2 --define=qsim_bmi2=true + +# Let the compiler pick the best combination for the native architecture. +build:native --define=qsim_native=true +build:native --build_tag_filters= +test:native --test_tag_filters= # Build without AVX or SSE -build:basic --copt=-O3 +build:basic -- # ~~~~ Parallelization (choose one, or nopenmp for none) ~~~~ diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 011561bd7..d5a1aca14 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -308,7 +308,7 @@ jobs: strategy: matrix: # Hardware optimizers. - hardware_opt: [avx, sse, basic] + hardware_opt: [avx, sse, native, basic] # Optimizers for parallelism. parallel_opt: [openmp, nopenmp] steps: diff --git a/BUILD b/BUILD new file mode 100644 index 000000000..52d2ee1a6 --- /dev/null +++ b/BUILD @@ -0,0 +1,76 @@ +# Copyright 2026 Google LLC +# +# 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 +# +# https://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. + +load("//dev_tools:bazel_utils.bzl", "qsim_print_config", "qsim_validate_host") + +qsim_validate_host( + name = "validate_host", + visibility = ["//visibility:public"], +) + +qsim_print_config(name = "print_config") + +# Define configurations for build with AVX, SSE, and BMI support. + +config_setting( + name = "avx_requested", + values = {"define": "qsim_avx=true"}, +) + +config_setting( + name = "avx2_requested", + values = {"define": "qsim_avx2=true"}, +) + +config_setting( + name = "avx512_requested", + values = {"define": "qsim_avx512=true"}, +) + +config_setting( + name = "sse_requested", + values = {"define": "qsim_sse=true"}, +) + +config_setting( + name = "bmi_requested", + values = {"define": "qsim_bmi=true"}, +) + +config_setting( + name = "bmi2_requested", + values = {"define": "qsim_bmi2=true"}, +) + +config_setting( + name = "native_requested", + values = {"define": "qsim_native=true"}, +) + +config_setting( + name = "native_on_linux", + constraint_values = ["@platforms//os:linux"], + values = {"define": "qsim_native=true"}, +) + +config_setting( + name = "native_on_macos", + constraint_values = ["@platforms//os:macos"], + values = {"define": "qsim_native=true"}, +) + +config_setting( + name = "verbose_requested", + values = {"define": "qsim_verbose=true"}, +) diff --git a/apps/BUILD b/apps/BUILD index 76c45e83a..f46c44bb1 100644 --- a/apps/BUILD +++ b/apps/BUILD @@ -14,18 +14,15 @@ # TODO: remove reliance on getopt (unistd.h) to allow apps to run on Windows. -load("@local_compiler_config//:compiler_config.bzl", "SUPPORTS_GSFRAME") load("@rules_cc//cc:defs.bzl", "cc_binary") +load("//dev_tools:bazel_utils.bzl", "qsim_select_copts") -gsframe_copts = select({ - "@platforms//os:linux": ["-Wa,--gsframe=no"] if SUPPORTS_GSFRAME else [], - "//conditions:default": [], -}) +qsim_copts = qsim_select_copts(target_level = "avx") cc_binary( name = "qsim_base", srcs = ["qsim_base.cc"], - copts = gsframe_copts, + copts = qsim_copts, data = ["//circuits:circuit_q24"], deps = [ "//lib:run_qsim_lib", @@ -35,7 +32,7 @@ cc_binary( cc_binary( name = "qsim_von_neumann", srcs = ["qsim_von_neumann.cc"], - copts = gsframe_copts, + copts = qsim_copts, deps = [ "//lib:run_qsim_lib", ], @@ -44,29 +41,9 @@ cc_binary( cc_binary( name = "qsim_amplitudes", srcs = ["qsim_amplitudes.cc"], - copts = gsframe_copts, + copts = qsim_copts, deps = [ "//lib:bitstring", "//lib:run_qsim_lib", ], ) - -cc_binary( - name = "qsimh_base", - srcs = ["qsimh_base.cc"], - copts = gsframe_copts, - deps = [ - "//lib:bitstring", - "//lib:run_qsimh_lib", - ], -) - -cc_binary( - name = "qsimh_amplitudes", - srcs = ["qsimh_amplitudes.cc"], - copts = gsframe_copts, - deps = [ - "//lib:bitstring", - "//lib:run_qsimh_lib", - ], -) diff --git a/dev_tools/BUILD b/dev_tools/BUILD index 1118ed25a..41f23f18e 100644 --- a/dev_tools/BUILD +++ b/dev_tools/BUILD @@ -1 +1,17 @@ -# Empty BUILD file to make dev_tools a package. +# Copyright 2026 Google LLC +# +# 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 +# +# https://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. + +load(":compiler_probe_test.bzl", "compiler_probe_test_suite") + +compiler_probe_test_suite(name = "compiler_probe_tests") diff --git a/dev_tools/bazel_utils.bzl b/dev_tools/bazel_utils.bzl new file mode 100644 index 000000000..d96e7d7fc --- /dev/null +++ b/dev_tools/bazel_utils.bzl @@ -0,0 +1,255 @@ +# Copyright 2026 Google LLC +# +# 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 +# +# https://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. + +"""Utility functions for qsim Bazel builds.""" + +load("@bazel_skylib//lib:selects.bzl", "selects") +load( + "@local_compiler_config//:compiler_config.bzl", + "AVX2_COPTS", + "AVX512_COPTS", + "AVX_COPTS", + "BMI2_COPTS", + "BMI_COPTS", + "HOST_HAS_AVX", + "HOST_HAS_AVX2", + "HOST_HAS_AVX512", + "HOST_HAS_BMI", + "HOST_HAS_BMI2", + "HOST_HAS_SSE", + "SSE_COPTS", + "SUPPORTS_GSFRAME", +) + +def qsim_select_copts(target_level = "basic"): + """Returns a select block for qsim compiler options based on active config. + + Handles additive combinations of AVX, SSE, and BMI. + + Args: + target_level: The maximum instruction set level for this target. + Options: "basic", "avx", "avx2", "avx512", "sse". + If "basic", SIMD flags are only added if requested. + + Returns: + A list of select blocks that sum to the appropriate compiler flags. + """ + + # 1. Native configuration. + # Windows (MSVC) does not support -march=native. + native_part = selects.with_or({ + ("//:native_on_linux", "//:native_on_macos"): ["-march=native"], + "//conditions:default": [], + }) + + # 2. AVX part (additive) + # If native is requested, we don't add specific AVX flags to avoid conflict. + avx_part = select({ + "//:native_requested": [], + "//:avx512_requested": AVX512_COPTS if target_level == "avx512" else ( + AVX2_COPTS if target_level == "avx2" else AVX_COPTS + ), + "//:avx2_requested": AVX2_COPTS if target_level in [ + "avx2", + "avx512", + ] else AVX_COPTS, + "//:avx_requested": AVX_COPTS, + "//conditions:default": [], + }) + + # 3. SSE part (additive) + sse_part = select({ + "//:native_requested": [], + "//:sse_requested": SSE_COPTS, + "//conditions:default": [], + }) + + # 4. BMI part (additive) + bmi_part = select({ + "//:native_requested": [], + "//:bmi2_requested": BMI2_COPTS, + "//:bmi_requested": BMI_COPTS, + "//conditions:default": [], + }) + + # 5. Linux specific flags (SFrame) + gsframe_flags = ["-Wa,--gsframe=no"] if SUPPORTS_GSFRAME else [] + gsframe_part = select({ + "@platforms//os:linux": gsframe_flags, + "//conditions:default": [], + }) + + return native_part + avx_part + sse_part + bmi_part + gsframe_part + +def _qsim_validate_host_impl(ctx): + # Check for mutual exclusivity of native and specific flags. + if ctx.attr.native_requested and ( + ctx.attr.avx_requested or ctx.attr.avx2_requested or + ctx.attr.avx512_requested or ctx.attr.sse_requested or + ctx.attr.bmi_requested or ctx.attr.bmi2_requested + ): + fail("--config=native is incompatible with specific architecture flags.") + + # Check host support for requested features. + if ctx.attr.avx_requested and not HOST_HAS_AVX: + fail("Requested AVX support, but host CPU does not support it.") + if ctx.attr.avx2_requested and not HOST_HAS_AVX2: + fail("Requested AVX2 support, but host CPU does not support it.") + if ctx.attr.avx512_requested and not HOST_HAS_AVX512: + fail("Requested AVX512 support, but host CPU does not support it.") + if ctx.attr.sse_requested and not HOST_HAS_SSE: + fail("Requested SSE support, but host CPU does not support it.") + if ctx.attr.bmi_requested and not HOST_HAS_BMI: + fail("Requested BMI support, but host CPU does not support it.") + if ctx.attr.bmi2_requested and not HOST_HAS_BMI2: + fail("Requested BMI2 support, but host CPU does not support it.") + + return [CcInfo()] + +qsim_validate_host_rule = rule( + implementation = _qsim_validate_host_impl, + attrs = { + "avx_requested": attr.bool(), + "avx2_requested": attr.bool(), + "avx512_requested": attr.bool(), + "bmi_requested": attr.bool(), + "bmi2_requested": attr.bool(), + "native_requested": attr.bool(), + "sse_requested": attr.bool(), + }, + provides = [CcInfo], +) + +def qsim_validate_host(name, **kwargs): + """Enforces host compatibility and flag exclusivity.""" + qsim_validate_host_rule( + name = name, + avx_requested = select({ + "//:avx_requested": True, + "//conditions:default": False, + }), + avx2_requested = select({ + "//:avx2_requested": True, + "//conditions:default": False, + }), + avx512_requested = select({ + "//:avx512_requested": True, + "//conditions:default": False, + }), + bmi_requested = select({ + "//:bmi_requested": True, + "//conditions:default": False, + }), + bmi2_requested = select({ + "//:bmi2_requested": True, + "//conditions:default": False, + }), + native_requested = select({ + "//:native_requested": True, + "//conditions:default": False, + }), + sse_requested = select({ + "//:sse_requested": True, + "//conditions:default": False, + }), + **kwargs + ) + +def _qsim_print_config_impl(ctx): + if ctx.attr.verbose: + print("--- qsim Build Configuration ---") # buildifier: disable=print + print("Active compiler flags: " + " ".join(ctx.attr.flags)) # buildifier: disable=print + print("--------------------------------") # buildifier: disable=print + return [CcInfo()] + +qsim_print_config_rule = rule( + implementation = _qsim_print_config_impl, + attrs = { + "flags": attr.string_list(), + "verbose": attr.bool(), + }, + provides = [CcInfo], +) + +def qsim_print_config(name, **kwargs): + """Prints build configuration if --config=verbose is active.""" + qsim_print_config_rule( + name = name, + flags = qsim_select_copts(target_level = "avx512"), + verbose = select({ + "//:verbose_requested": True, + "//conditions:default": False, + }), + **kwargs + ) + +def qsim_feature_compatibility(feature): + """Returns a select block for target_compatible_with based on required feature. + + Args: + feature: The feature name to check for ("avx", "avx2", "avx512" or "sse"). + + Returns: + A select block that evaluates to an empty list if compatible, or + ["@platforms//:incompatible"] otherwise. + """ + + # We reuse the logic: if native or specific flag is requested, check host. + # If NO flag is requested, it might still be incompatible if it's a feature test. + + avx_ok = [] if HOST_HAS_AVX or HOST_HAS_AVX2 or HOST_HAS_AVX512 else [ + "@platforms//:incompatible", + ] + avx2_ok = [] if HOST_HAS_AVX2 or HOST_HAS_AVX512 else [ + "@platforms//:incompatible", + ] + avx512_ok = [] if HOST_HAS_AVX512 else ["@platforms//:incompatible"] + sse_ok = [] if HOST_HAS_SSE else ["@platforms//:incompatible"] + + if feature == "avx": + return selects.with_or({ + ( + "//:avx_requested", + "//:avx2_requested", + "//:avx512_requested", + "//:native_requested", + ): avx_ok, + "//conditions:default": ["@platforms//:incompatible"], + }) + elif feature == "avx2": + return selects.with_or({ + ( + "//:avx2_requested", + "//:avx512_requested", + "//:native_requested", + ): avx2_ok, + "//conditions:default": ["@platforms//:incompatible"], + }) + elif feature == "avx512": + return selects.with_or({ + ( + "//:avx512_requested", + "//:native_requested", + ): avx512_ok, + "//conditions:default": ["@platforms//:incompatible"], + }) + elif feature == "sse": + return selects.with_or({ + ( + "//:sse_requested", + "//:native_requested", + ): sse_ok, + "//conditions:default": ["@platforms//:incompatible"], + }) + return [] diff --git a/dev_tools/compiler_probe.bzl b/dev_tools/compiler_probe.bzl index ce29d6b3b..53a439f54 100644 --- a/dev_tools/compiler_probe.bzl +++ b/dev_tools/compiler_probe.bzl @@ -12,29 +12,202 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Repository rule to probe compiler support for SFrame flags.""" - -def _compiler_probe_impl(repository_ctx): - # Try to determine the compiler. Prefer CC from environment. - cc = repository_ctx.os.environ.get("CC", "c++") - - # Run a test compilation to test if the flag is recognized. - # This is hacky and I wish there was a better way. - res = repository_ctx.execute([ - cc, - "-Wa,--gsframe=no", - "-c", - "-x", - "c++", - "/dev/null", - "-o", - "/dev/null", - ]) - - supports_gsframe = (res.return_code == 0) - - repository_ctx.file("BUILD.bazel", "package(default_visibility = ['//visibility:public'])\n") - repository_ctx.file("compiler_config.bzl", "SUPPORTS_GSFRAME = %s\n" % supports_gsframe) +"""Repository rule to probe compiler support and host CPU features.""" + +def _is_windows(os_name): + return "windows" in os_name + +def _is_macos(os_name): + return "mac" in os_name or "darwin" in os_name + +def _compiler_probe_impl(repo_ctx): + os_name = repo_ctx.os.name.lower() + is_win = _is_windows(os_name) + is_mac = _is_macos(os_name) + + default_cc = "cl.exe" if is_win else "c++" + env_cc = repo_ctx.os.environ.get("CC", default_cc) + cc_path = repo_ctx.which(env_cc) + cc = str(cc_path) if cc_path else env_cc + + supports_gsframe = False + cpu_info = "" + + if is_mac: + result = repo_ctx.execute([ + "sysctl", + "-n", + "machdep.cpu.features", + "machdep.cpu.leaf7_features", + ]) + cpu_info = result.stdout if result.return_code == 0 else "" + elif not is_win: + result = repo_ctx.execute(["cat", "/proc/cpuinfo"]) + cpu_info = result.stdout if result.return_code == 0 else "" + + # Run a test compilation to test if the SFrame flag is recognized. + if not is_win: + gsframe_test = repo_ctx.execute([ + cc, + "-Wa,--gsframe=no", + "-c", + "-x", + "c++", + "/dev/null", + "-o", + "/dev/null", + ]) + supports_gsframe = (gsframe_test.return_code == 0) + + features = get_cpu_features(os_name, cpu_info) + avx_copts, sse_copts = get_compiler_flags(os_name, features) + has_avx, has_avx2, has_avx512, has_sse, has_bmi, has_bmi2, cpu_features_str = get_feature_booleans(features) + + # Specific flags for requested levels + if is_win: + avx2_flags = ["/arch:AVX2"] + avx512_flags = ["/arch:AVX512"] + else: + avx2_flags = ["-mavx2", "-mfma"] + avx512_flags = ["-mavx512f", "-mavx2", "-mfma"] + + bmi_flags = ["-mbmi"] if has_bmi and not has_bmi2 else [] + bmi2_flags = ["-mbmi2"] if has_bmi2 else [] + + repo_ctx.file( + "BUILD.bazel", + "package(default_visibility = ['//visibility:public'])\n", + ) + repo_ctx.file( + "compiler_config.bzl", + """# Generated by compiler_probe.bzl. Do not edit. +SUPPORTS_GSFRAME = {gsframe} +AVX_COPTS = {avx} +AVX2_COPTS = {avx2} +AVX512_COPTS = {avx512} +SSE_COPTS = {sse} +BMI_COPTS = {bmi} +BMI2_COPTS = {bmi2} +CPU_FEATURES_STR = "{cpu_features}" +HOST_HAS_AVX = {has_avx} +HOST_HAS_AVX2 = {has_avx2} +HOST_HAS_AVX512 = {has_avx512} +HOST_HAS_SSE = {has_sse} +HOST_HAS_BMI = {has_bmi} +HOST_HAS_BMI2 = {has_bmi2} +""".format( + gsframe = supports_gsframe, + avx = avx_copts, + avx2 = avx2_flags, + avx512 = avx512_flags, + sse = sse_copts, + bmi = bmi_flags, + bmi2 = bmi2_flags, + cpu_features = cpu_features_str, + has_avx = has_avx, + has_avx2 = has_avx2, + has_avx512 = has_avx512, + has_sse = has_sse, + has_bmi = has_bmi, + has_bmi2 = has_bmi2, + ), + ) + + # Print a message to inform the user what was found. + flags_str = " ".join(avx_copts) + " " + " ".join(sse_copts) + " " + " ".join(bmi_flags) + " " + " ".join(bmi2_flags) + print("Host CPU features detected: " + cpu_features_str) # buildifier: disable=print + print("Available host-optimized flags: " + flags_str) # buildifier: disable=print + +def get_feature_booleans(features): + """Summarizes feature presence as booleans and a string. + + Args: + features: A dict of detected features (from get_cpu_features). + + Returns: + A tuple of (has_avx, has_avx2, has_avx512, has_sse, has_bmi, has_bmi2, cpu_features_str). + """ + cpu_features_str = " ".join([feat.upper() for feat, found in features.items() if found]) + has_avx = features.get("avx", False) + has_avx2 = features.get("avx2", False) + has_avx512 = features.get("avx512f", False) + has_sse = "SSE" in cpu_features_str + has_bmi = features.get("bmi", False) + has_bmi2 = features.get("bmi2", False) + return has_avx, has_avx2, has_avx512, has_sse, has_bmi, has_bmi2, cpu_features_str + +def get_cpu_features(os_name, cpu_info): + """Parses system command output to identify CPU features. + + Args: + os_name: The lowercase name of the OS (from repository_ctx.os.name). + cpu_info: String containing CPU feature flags. + + Returns: + A dict of detected features. + """ + + # Protection against None/empty command execution outputs. + cpu_info_lower = (cpu_info or "").lower() + is_win = _is_windows(os_name) + + # Map desired feature keys to strings we expect to find in the OS output. + feature_map = { + "avx512f": ["avx512f"], + "avx2": ["avx2"], + "avx": ["avx"], + "fma": ["fma"], + "bmi": ["bmi1", "bmi "], # bmi1 is often just 'bmi' + "bmi2": ["bmi2"], + "sse4": ["sse4_1", "sse4_2", "sse4.1", "sse4.2"], + "sse2": ["sse2"], + } + + features = {} + for feat, search_terms in feature_map.items(): + if is_win: + # Heuristic fallback for Windows hosts. + features[feat] = feat in ("avx2", "sse4", "sse2") + else: + features[feat] = any([term in cpu_info_lower for term in search_terms]) + + return features + +def get_compiler_flags(os_name, features): + """Determines compiler flags based on OS and detected features. + + Args: + os_name: The lowercase name of the OS. + features: A dict of detected features (from get_cpu_features). + + Returns: + A tuple of (avx_copts, sse_copts). + """ + is_win = _is_windows(os_name) + avx_copts = [] + sse_copts = [] + + if is_win: + if features.get("avx512f"): + avx_copts = ["/arch:AVX512"] + elif features.get("avx2"): + avx_copts = ["/arch:AVX2"] + else: + avx_copts = ["/arch:AVX"] + else: + if features.get("avx512f"): + avx_copts = ["-mavx512f"] + elif features.get("avx2"): + avx_copts = ["-mavx2", "-mfma"] + else: + avx_copts = ["-mavx"] + + if features.get("sse4"): + sse_copts = ["-msse4"] + elif features.get("sse2"): + sse_copts = ["-msse2"] + + return avx_copts, sse_copts compiler_probe = repository_rule( implementation = _compiler_probe_impl, diff --git a/dev_tools/compiler_probe_test.bzl b/dev_tools/compiler_probe_test.bzl new file mode 100644 index 000000000..b205ef174 --- /dev/null +++ b/dev_tools/compiler_probe_test.bzl @@ -0,0 +1,120 @@ +# Copyright 2026 Google LLC +# +# 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 +# +# https://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. + +"""Unit tests for compiler_probe.bzl.""" + +load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") +load("//dev_tools:compiler_probe.bzl", "get_compiler_flags", "get_cpu_features", "get_feature_booleans") + +def _test_linux_basic_impl(ctx): + env = unittest.begin(ctx) + + # Mock /proc/cpuinfo output for an older AVX/SSE2 Linux box + cmd_output = "flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 cx16 pcid movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust erms invpcid rdseed adx smap clflushopt xsaveopt xsavec xgetbv1 xsaves arat umip arch_capabilities" + + features = get_cpu_features("linux", cmd_output) + asserts.true(env, features["avx"]) + asserts.false(env, features["avx2"]) + asserts.true(env, features["sse2"]) + asserts.false(env, features["sse4"]) + + avx_copts, sse_copts = get_compiler_flags("linux", features) + asserts.equals(env, ["-mavx"], avx_copts) + asserts.equals(env, ["-msse2"], sse_copts) + + has_avx, has_sse, features_str = get_feature_booleans(features) + asserts.true(env, has_avx) + asserts.true(env, has_sse) + asserts.true(env, "AVX" in features_str) + asserts.true(env, "SSE2" in features_str) + + return unittest.end(env) + +def _test_linux_avx2_impl(ctx): + env = unittest.begin(ctx) + + # Mock /proc/cpuinfo output for a standard AVX2 Linux box + cmd_output = "flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt xsaveopt xsavec xgetbv1 xsaves arat umip arch_capabilities" + + features = get_cpu_features("linux", cmd_output) + asserts.true(env, features["avx2"]) + asserts.true(env, features["fma"]) + asserts.true(env, features["bmi2"]) + asserts.true(env, features["sse4"]) + asserts.false(env, features["avx512f"]) + + avx_copts, sse_copts = get_compiler_flags("linux", features) + asserts.equals(env, ["-mavx2", "-mfma", "-mbmi2"], avx_copts) + asserts.equals(env, ["-msse4"], sse_copts) + + return unittest.end(env) + +def _test_linux_avx512_impl(ctx): + env = unittest.begin(ctx) + + # Mock /proc/cpuinfo output for an AVX512 Linux box + cmd_output = "flags : ... avx512f avx512dq avx512cd avx512bw avx512vl avx2 bmi2 ..." + + features = get_cpu_features("linux", cmd_output) + asserts.true(env, features["avx512f"]) + asserts.true(env, features["bmi2"]) + + avx_copts, _ = get_compiler_flags("linux", features) + asserts.equals(env, ["-mavx512f", "-mbmi2"], avx_copts) + + return unittest.end(env) + +def _test_macos_impl(ctx): + env = unittest.begin(ctx) + + # Mock sysctl -a output for macOS + cmd_output = "machdep.cpu.features: FPU VME DE PSE TSC MSR PAE MCE CX8 APIC SEP MTRR PGE MCA CMOV PAT PSE36 CLFSH DS ACPI MMX FXSR SSE SSE2 SS HTT TM PBE SSE3 PCLMULQDQ DTES64 MON DSCPL VMX EST TM2 SSSE3 FMA CX16 TPR PDCM SSE4.1 SSE4.2 x2APIC MOVBE POPCNT AES PCID XSAVE OSXSAVE SEGLIM64 VMM TSCTMR AVX1.0 RDRAND F16C\nmachdep.cpu.leaf7_features: SMEP ERMS RDWRFSGS TSC_THREAD_OFFSET BMI1 HLE AVX2 BMI2 INVPCID RTM RDSEED ADX SMAP CLFLUSHOPT IPT" + + features = get_cpu_features("darwin", cmd_output) + asserts.true(env, features["avx2"]) + asserts.true(env, features["sse4"]) + + avx_copts, sse_copts = get_compiler_flags("darwin", features) + asserts.equals(env, ["-mavx2", "-mfma", "-mbmi2"], avx_copts) + asserts.equals(env, ["-msse4"], sse_copts) + + return unittest.end(env) + +def _test_windows_impl(ctx): + env = unittest.begin(ctx) + + # Windows logic is currently a heuristic + features = get_cpu_features("windows", "") + asserts.true(env, features["avx2"]) + + avx_copts, _ = get_compiler_flags("windows", features) + asserts.equals(env, ["/arch:AVX2"], avx_copts) + + return unittest.end(env) + +linux_basic_test = unittest.make(_test_linux_basic_impl) +linux_avx2_test = unittest.make(_test_linux_avx2_impl) +linux_avx512_test = unittest.make(_test_linux_avx512_impl) +macos_test = unittest.make(_test_macos_impl) +windows_test = unittest.make(_test_windows_impl) + +def compiler_probe_test_suite(name): + unittest.suite( + name, + linux_basic_test, + linux_avx2_test, + linux_avx512_test, + macos_test, + windows_test, + ) diff --git a/dev_tools/test_libs.sh b/dev_tools/test_libs.sh index 16f4417d1..3eea82c07 100755 --- a/dev_tools/test_libs.sh +++ b/dev_tools/test_libs.sh @@ -22,9 +22,7 @@ sample programs in apps/. If the first option on the command line is -h, --help, or help, this help text will be printed and the program will exit. Any other options on the command -line are passed directly to Bazel. - -This script makes use of the Python package 'py-cpuinfo'." +line are passed directly to Bazel." # Exit early if the user requested help. if [[ "$1" == "-h" || "$1" == "--help" || "$1" == "help" ]]; then @@ -32,42 +30,14 @@ if [[ "$1" == "-h" || "$1" == "--help" || "$1" == "help" ]]; then exit 0 fi -if ! python -m pip show -qq py-cpuinfo 2>/dev/null; then - echo "Error: missing package 'py-cpuinfo'." >&2 - exit 1 -fi - -# Look for AVX and SSE in the processor's feature flags. -declare features="" -declare filters="" -declare -a configs=() -features="$(python -c 'import cpuinfo; print(" ".join(cpuinfo.get_cpu_info().get("flags", [])))')" -if [[ "$features" == *avx2* ]]; then - filters+=",avx" - configs+=( "--config=avx" ) -fi -if [[ "$features" == *sse4* ]]; then - filters+=",sse" - configs+=( "--config=sse" ) -fi -filters="${filters#,}" - -# If none of the optimization configs were added, use the basic config. -if [[ ${#configs[@]} -eq 0 ]]; then - configs=( "--config=basic" ) -fi - -declare -a build_filters=() -declare -a test_filters=() -if [[ -n "$filters" ]]; then - build_filters=( "--build_tag_filters=$filters" ) - test_filters=( "--test_tag_filters=$filters" ) -fi +# We use the 'native' config to automatically detect and use the best +# instruction set available on the current host. +declare -a configs=( "--config=native" ) # The apps are sample programs and are only meant to run on Linux. if [[ "$OSTYPE" == "linux-gnu"* ]]; then - bazel build "${configs[@]}" "${build_filters[@]}" "$@" apps:all + bazel build "${configs[@]}" "$@" apps:all fi -# Run all basic tests. This should work on all platforms. -bazel test "${configs[@]}" "${test_filters[@]}" "$@" tests:all +# Run all tests. Incompatible SIMD tests will be skipped automatically. +bazel test "${configs[@]}" "$@" tests:all diff --git a/docs/bazel.md b/docs/bazel.md index f93f0d65b..e81fd72ba 100644 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -7,73 +7,93 @@ for qsim tests and sample applications. The Bazel targets are `tests` and and software environment. On hardware and software platforms that support them, qsim can be configured to -take advantage of certain hardware optimizations, specifically AVX (a hardware -extension for optimizing vector arithmetic), SSE (streaming SIMD extensions), -and/or OpenMP (a software API for shared-memory parallel programming). By -default, the basic qsim build configuration does _not_ compile in support for -these features. (On some systems such as MacOS on Apple Silicon, they are not -available.) A basic build & test run is obtained using the following command: +take advantage of certain CPU hardware extensions for optimizing operations. +Specifically, qsim can take advantage of AVX (Advanced Vector Extensions), SSE +(Streaming SIMD Extensions), BMI (Bit Manipulation Instructions), and/or OpenMP +(shared-memory parallel programming). -```shell -bazel test tests:all -``` - -As an example of using optimization options, if your computer has support for -AVX and OpenMP, the following command will build and run all the tests with the -appropriate config options to make use of those features: +By default, the basic qsim build configuration does _not_ include these +optimizations. A basic build and test run is obtained using the following +command: ```shell -bazel test --config=avx --config=openmp tests:all +bazel test tests:all ``` -To run a sample simulation, use the command below. Note that this command -requires the `circuit_q24` file to be specified both on the command line and in -the `data` field of the `qsim_base` BUILD rule. +Conversely, if you want to get all optimizations possible, you can use this: ```shell -bazel run --config=avx --config=openmp apps:qsim_base -- -c circuits/circuit_q24 +bazel test --config=native --config=openmp tests:all ``` ## Build configurations -Depending on your computer's hardware architecture and the features available, -different Bazel config flags (such as `--config=avx`, above) can be used to -control which hardware optimizers are included in a given build or test run. +qsim uses an additive, host-aware configuration model. Multiple hardware +features can be enabled simultaneously, and Bazel will automatically verify +that your host CPU supports the requested instruction sets. -### Vector arithmetic optimizers +### Vector arithmetic and bit manipulation -Pick at most one of the following options: +You can combine one or more of the following options. Bazel will fail fast if +the host hardware does not support a requested feature. ```bazel -# Use AVX instructions for vector arithmetic. +# Use AVX2 and AVX instructions. +--config=avx2 + +# Use AVX512 instructions (implies AVX2/AVX). +--config=avx512 + +# Use AVX instructions (includes AVX2 and AVX512). --config=avx -# Use SSE instructions for vector arithmetic. +# Use SSE 4.1 instructions. --config=sse -# Do not use vector arithmetic optimization (default). +# Use BMI2 instructions. +--config=bmi + +# Automatically detect and use the best instruction set for the host. +--config=native + +# Do not use AVX, SSE, or BMI optimizations (default). --config=basic ``` +For example, if your computer supports AVX2, SSE, and BMI, you can enable all +of them: + +```shell +bazel test --config=avx2 --config=sse --config=bmi tests:all +``` + +For another example, if you want to let the build system choose all the +optimizations supported on your host computer, you can use this: + +```shell +bazel test --config=native tests:all +``` + ### Parallelism optimizers -Pick at most one of the following options: +qsim can take advantage of [OpenMP]( https://en.wikipedia.org/wiki/OpenMP) +(Open Multi-Processing), an industry-standard API for shared-memory parallel +programming. You can enable the use of OpenMP this way: ```bazel # Use OpenMP to run operations in parallel when possible. --config=openmp - -# Do not use OpenMP for parallelism (default). ---config=nopenmp ``` +To explicitly disable the use of OpenMP, you can use `--config=nopenmp` or not +use the OpenMP option at all (which is the default). + ### Memory allocators -[TCMalloc](https://github.com/google/tcmalloc) is a fast, multithreaded -implementation of C's `malloc()` and C++'s `new` operator. It is an independent -open-source library developed by Google. TCMalloc can be used with qsim as an -alternative to the default `malloc()`. Pick at most one of the following -options: +[TCMalloc](https://github.com/google/tcmalloc) can be used as a faster +alternative to the default `malloc()`. Consult the TCMalloc documentation for +information about how to install it. If it is available on your system, you +can tell Bazel to build qsim with it like this: ```bazel # Use TCMalloc for memory allocation. @@ -83,9 +103,19 @@ options: --config=malloc ``` -### Additional configuration options +### Diagnostics and Verbosity + +To see the active compiler flags and detected host CPU features, add the +`--config=verbose` configuration to any of the other options. For example, + +```shell +bazel build --config=verbose --config=native tests:all +``` + +You can also add `--config=verbose` to any `test` or `run` command for +detailed build information. -To provide more information when building and testing qsim, you can add the -configuration option `--config=verbose` to any of the `bazel` commands above. +--- -Other configuration options are described elsewhere in the qsim documentation. +For more details on running sample simulations, see the documentation for +individual apps in the `apps/` directory. diff --git a/lib/BUILD b/lib/BUILD index 60fd0e51a..d7e637dfa 100644 --- a/lib/BUILD +++ b/lib/BUILD @@ -75,6 +75,7 @@ cc_library( "util_cpu.h", "vectorspace.h", ], + deps = ["//:validate_host"], ) cc_library( @@ -156,6 +157,7 @@ cuda_library( ], deps = [ ":cuda", + "//:validate_host", "@local_config_cuda//cuda:cuda_headers", ], ) @@ -231,6 +233,7 @@ cuda_library( copts = ["-D__CUSTATEVEC__"], deps = [ ":cuda", + "//:validate_host", "@local_config_cuda//cuda:cuda_headers", "@local_config_cuquantum//:cuquantum_headers", "@local_config_cuquantum//:libcuquantum", @@ -281,6 +284,7 @@ cc_library( "util_cpu.h", "vectorspace.h", ], + deps = ["//:validate_host"], ) # Library to run qsimh with qsim circuit parser and parallel `for` @@ -320,6 +324,7 @@ cc_library( "util_cpu.h", "vectorspace.h", ], + deps = ["//:validate_host"], ) ##### Basic libraries ##### @@ -340,7 +345,9 @@ cc_library( cc_library( name = "matrix", hdrs = ["matrix.h"], - deps = [":bits"], + deps = [ + ":bits", + ], ) cc_library( diff --git a/pyproject.toml b/pyproject.toml index c0f14b96e..5363b459a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -106,7 +106,6 @@ dev = [ # Linters, formatters, and test utilities. "black~=26.3.1", "isort[colors]~=8.0.1", - "py-cpuinfo", "pylint~=4.0.2", "pytest", "pytest-xdist", diff --git a/tests/BUILD b/tests/BUILD index b4be45302..693897f4c 100644 --- a/tests/BUILD +++ b/tests/BUILD @@ -12,30 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@local_compiler_config//:compiler_config.bzl", "SUPPORTS_GSFRAME") load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") - -gsframe_copts = ["-Wa,--gsframe=no"] if SUPPORTS_GSFRAME else [] - -# Options for testing different simulator types. -avx_copts = [ - "-mavx2", - "-mfma", -] + gsframe_copts - -avx512_copts = ["-march=native"] + gsframe_copts - -sse_copts = ["-msse4"] + gsframe_copts - -windows_copts = [ - "/arch:AVX", - "/std:c++17", -] - -windows_avx512_copts = [ - "/arch:AVX512", - "/std:c++17", -] +load("//dev_tools:bazel_utils.bzl", "qsim_feature_compatibility", "qsim_select_copts") config_setting( name = "windows", @@ -46,10 +24,7 @@ cc_test( name = "bitstring_test", size = "small", srcs = ["bitstring_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:bitstring", "@com_google_googletest//:gtest_main", @@ -60,10 +35,7 @@ cc_test( name = "channel_test", size = "small", srcs = ["channel_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:channel", "//lib:formux", @@ -78,10 +50,7 @@ cc_test( name = "channels_cirq_test", size = "small", srcs = ["channels_cirq_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:channels_cirq", "//lib:circuit", @@ -100,10 +69,7 @@ cc_test( name = "circuit_qsim_parser_test", size = "small", srcs = ["circuit_qsim_parser_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:circuit_qsim_parser", "//lib:gates_qsim", @@ -115,10 +81,7 @@ cc_test( name = "expect_test", size = "small", srcs = ["expect_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:expect", "//lib:formux", @@ -135,10 +98,7 @@ cc_test( name = "fuser_basic_test", size = "small", srcs = ["fuser_basic_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:circuit_qsim_parser", "//lib:fuser_basic", @@ -151,10 +111,7 @@ cc_test( name = "fuser_mqubit_test", size = "small", srcs = ["fuser_mqubit_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:formux", "//lib:fuser_mqubit", @@ -181,10 +138,7 @@ cc_test( name = "gates_qsim_test", size = "small", srcs = ["gates_qsim_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:gates_qsim", "@com_google_googletest//:gtest_main", @@ -195,10 +149,7 @@ cc_library( name = "hybrid_testfixture", testonly = 1, hdrs = ["hybrid_testfixture.h"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:circuit_qsim_parser", "//lib:formux", @@ -214,11 +165,9 @@ cc_test( name = "hybrid_avx_test", size = "small", srcs = ["hybrid_avx_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": avx_copts, - }), + copts = qsim_select_copts(target_level = "avx"), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx"), deps = [ ":hybrid_testfixture", "//lib:seqfor", @@ -231,10 +180,7 @@ cc_test( name = "matrix_test", size = "small", srcs = ["matrix_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:matrix", "@com_google_googletest//:gtest_main", @@ -245,10 +191,7 @@ cc_library( name = "qtrajectory_testfixture", testonly = 1, hdrs = ["qtrajectory_testfixture.h"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:channel", "//lib:channels_cirq", @@ -267,11 +210,9 @@ cc_test( name = "qtrajectory_avx_test", size = "small", srcs = ["qtrajectory_avx_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": avx_copts, - }), + copts = qsim_select_copts(target_level = "avx"), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx"), deps = [ ":qtrajectory_testfixture", "//lib:fuser_mqubit", @@ -288,10 +229,7 @@ cc_test( name = "run_qsim_test", size = "small", srcs = ["run_qsim_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ ":gates_cirq_testfixture", "//lib:run_qsim_lib", @@ -299,29 +237,11 @@ cc_test( ], ) -cc_test( - name = "run_qsimh_test", - size = "small", - srcs = ["run_qsimh_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), - deps = [ - ":gates_cirq_testfixture", - "//lib:run_qsimh_lib", - "@com_google_googletest//:gtest_main", - ], -) - cc_library( name = "simulator_testfixture", testonly = 1, hdrs = ["simulator_testfixture.h"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:expect", "//lib:fuser_mqubit", @@ -337,11 +257,9 @@ cc_test( name = "simulator_avx_test", size = "small", srcs = ["simulator_avx_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": avx_copts, - }), + copts = qsim_select_copts(target_level = "avx"), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx"), deps = [ ":simulator_testfixture", "//lib:parfor", @@ -355,11 +273,9 @@ cc_test( name = "simulator_avx512_test", size = "small", srcs = ["simulator_avx512_test.cc"], - copts = select({ - ":windows": windows_avx512_copts, - "//conditions:default": avx512_copts, - }), + copts = qsim_select_copts(target_level = "avx512"), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx512"), deps = [ ":simulator_testfixture", "//lib:parfor", @@ -373,10 +289,7 @@ cc_test( name = "simulator_basic_test", size = "small", srcs = ["simulator_basic_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ ":simulator_testfixture", "//lib:parfor", @@ -390,11 +303,9 @@ cc_test( name = "simulator_sse_test", size = "small", srcs = ["simulator_sse_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": sse_copts, - }), + copts = qsim_select_copts(target_level = "sse"), tags = ["sse"], + target_compatible_with = qsim_feature_compatibility("sse"), deps = [ ":simulator_testfixture", "//lib:parfor", @@ -408,10 +319,7 @@ cc_library( name = "statespace_testfixture", testonly = 1, hdrs = ["statespace_testfixture.h"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "sse"), deps = [ "//lib:circuit_qsim_parser", "//lib:fuser_basic", @@ -426,11 +334,9 @@ cc_test( name = "statespace_avx_test", size = "small", srcs = ["statespace_avx_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": avx_copts, - }), + copts = qsim_select_copts(target_level = "avx"), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx"), deps = [ ":statespace_testfixture", "//lib:parfor", @@ -445,11 +351,9 @@ cc_test( name = "statespace_avx512_test", size = "small", srcs = ["statespace_avx512_test.cc"], - copts = select({ - ":windows": windows_avx512_copts, - "//conditions:default": avx512_copts, - }), + copts = qsim_select_copts(target_level = "avx512"), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx512"), deps = [ ":statespace_testfixture", "//lib:parfor", @@ -464,10 +368,7 @@ cc_test( name = "statespace_basic_test", size = "small", srcs = ["statespace_basic_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ ":statespace_testfixture", "//lib:parfor", @@ -482,11 +383,9 @@ cc_test( name = "statespace_sse_test", size = "small", srcs = ["statespace_sse_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": sse_copts, - }), + copts = qsim_select_copts(target_level = "sse"), tags = ["sse"], + target_compatible_with = qsim_feature_compatibility("sse"), deps = [ ":statespace_testfixture", "//lib:parfor", @@ -501,10 +400,7 @@ cc_library( name = "unitaryspace_testfixture", testonly = 1, hdrs = ["unitaryspace_testfixture.h"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "sse"), deps = [ "@com_google_googletest//:gtest_main", ], @@ -514,11 +410,9 @@ cc_test( name = "unitaryspace_avx_test", size = "small", srcs = ["unitaryspace_avx_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": avx_copts, - }), + copts = qsim_select_copts(target_level = "avx"), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx"), deps = [ ":unitaryspace_testfixture", "//lib:formux", @@ -531,11 +425,9 @@ cc_test( name = "unitaryspace_avx512_test", size = "small", srcs = ["unitaryspace_avx512_test.cc"], - copts = select({ - ":windows": windows_avx512_copts, - "//conditions:default": avx512_copts, - }), + copts = qsim_select_copts(target_level = "avx512"), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx512"), deps = [ ":unitaryspace_testfixture", "//lib:formux", @@ -548,10 +440,7 @@ cc_test( name = "unitaryspace_basic_test", size = "small", srcs = ["unitaryspace_basic_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ ":unitaryspace_testfixture", "//lib:formux", @@ -564,11 +453,9 @@ cc_test( name = "unitaryspace_sse_test", size = "small", srcs = ["unitaryspace_sse_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": sse_copts, - }), + copts = qsim_select_copts(target_level = "sse"), tags = ["sse"], + target_compatible_with = qsim_feature_compatibility("sse"), deps = [ ":unitaryspace_testfixture", "//lib:formux", @@ -581,10 +468,7 @@ cc_library( name = "unitary_calculator_testfixture", testonly = 1, hdrs = ["unitary_calculator_testfixture.h"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "sse"), deps = [ "//lib:fuser", "//lib:gate_appl", @@ -597,11 +481,9 @@ cc_test( name = "unitary_calculator_avx_test", size = "small", srcs = ["unitary_calculator_avx_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": avx_copts, - }), + copts = qsim_select_copts(target_level = "avx"), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx"), deps = [ ":unitary_calculator_testfixture", "//lib:formux", @@ -615,11 +497,9 @@ cc_test( name = "unitary_calculator_avx512_test", size = "small", srcs = ["unitary_calculator_avx512_test.cc"], - copts = select({ - ":windows": windows_avx512_copts, - "//conditions:default": avx512_copts, - }), + copts = qsim_select_copts(target_level = "avx512"), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx512"), deps = [ ":unitary_calculator_testfixture", "//lib:formux", @@ -633,10 +513,7 @@ cc_test( name = "unitary_calculator_basic_test", size = "small", srcs = ["unitary_calculator_basic_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ ":unitary_calculator_testfixture", "//lib:formux", @@ -650,11 +527,9 @@ cc_test( name = "unitary_calculator_sse_test", size = "small", srcs = ["unitary_calculator_sse_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": sse_copts, - }), + copts = qsim_select_copts(target_level = "sse"), tags = ["sse"], + target_compatible_with = qsim_feature_compatibility("sse"), deps = [ ":unitary_calculator_testfixture", "//lib:formux", @@ -668,10 +543,7 @@ cc_test( name = "vectorspace_test", size = "small", srcs = ["vectorspace_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:formux", "//lib:vectorspace", @@ -683,10 +555,7 @@ cc_test( name = "mps_statespace_test", size = "small", srcs = ["mps_statespace_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:formux", "//lib:mps_statespace", @@ -698,10 +567,7 @@ cc_test( name = "mps_simulator_test", size = "small", srcs = ["mps_simulator_test.cc"], - copts = select({ - ":windows": windows_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:formux", "//lib:gate_appl",