From 4407461a46beabc2ca561557b2a917c2f505f9b6 Mon Sep 17 00:00:00 2001 From: mhucka Date: Thu, 7 May 2026 23:23:39 +0000 Subject: [PATCH 01/18] Remove setting `_GLIBCXX_USE_CXX11_ABI` The value is the default, and no longer seems to be necessary. --- .bazelrc | 3 --- 1 file changed, 3 deletions(-) diff --git a/.bazelrc b/.bazelrc index fd4f6b3a8..abd1a5436 100644 --- a/.bazelrc +++ b/.bazelrc @@ -32,9 +32,6 @@ build:macos --cxxopt=-std=c++17 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 - # 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 From 41a092bbaee1757872bb5cd5cae310dddec375fb Mon Sep 17 00:00:00 2001 From: mhucka Date: Sat, 9 May 2026 23:42:02 +0000 Subject: [PATCH 02/18] Perform build-time probing of host capabilities This now probes the current host's capabilities for AVX and SSE features. For example, using `bazel build --config=avx` will get the right AVX (AVX2, AVX512F, etc.) based on what the host reports it supports. --- .bazelrc | 15 ++-- BUILD | 27 ++++++ apps/BUILD | 18 ++-- dev_tools/BUILD | 18 +++- dev_tools/compiler_probe.bzl | 160 ++++++++++++++++++++++++++++++----- tests/BUILD | 77 +++++++++++++---- 6 files changed, 262 insertions(+), 53 deletions(-) create mode 100644 BUILD diff --git a/.bazelrc b/.bazelrc index 4dd557430..3c38311dc 100644 --- a/.bazelrc +++ b/.bazelrc @@ -80,18 +80,17 @@ build:nosan -- # ~~~~ Instruction set options (choose one) ~~~~ -# Build with AVX2 + FMA +# Build with AVX +build:avx --define=qsim_avx=true 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:avx --build_tag_filters=-sse --ui_event_filters=-WARNING +test:avx --test_tag_filters=-sse --ui_event_filters=-WARNING # Build with SSE +build:sse --define=qsim_sse=true 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 --build_tag_filters=-avx --ui_event_filters=-WARNING +test:sse --test_tag_filters=-avx --ui_event_filters=-WARNING # Build without AVX or SSE build:basic --copt=-O3 diff --git a/BUILD b/BUILD new file mode 100644 index 000000000..2c9d76bc8 --- /dev/null +++ b/BUILD @@ -0,0 +1,27 @@ +# 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. + +package(default_visibility = ["//visibility:public"]) + +# Define configurations for build with AVX and/or SSE support. + +config_setting( + name = "avx_requested", + values = {"define": "qsim_avx=true"}, +) + +config_setting( + name = "sse_requested", + values = {"define": "qsim_sse=true"}, +) diff --git a/apps/BUILD b/apps/BUILD index 76c45e83a..f46e3567b 100644 --- a/apps/BUILD +++ b/apps/BUILD @@ -14,7 +14,7 @@ # TODO: remove reliance on getopt (unistd.h) to allow apps to run on Windows. -load("@local_compiler_config//:compiler_config.bzl", "SUPPORTS_GSFRAME") +load("@local_compiler_config//:compiler_config.bzl", "AVX_COPTS", "SSE_COPTS", "SUPPORTS_GSFRAME") load("@rules_cc//cc:defs.bzl", "cc_binary") gsframe_copts = select({ @@ -22,10 +22,16 @@ gsframe_copts = select({ "//conditions:default": [], }) +qsim_copts = gsframe_copts + select({ + "//:avx_requested": AVX_COPTS, + "//:sse_requested": SSE_COPTS, + "//conditions:default": [], +}) + 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 +41,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,7 +50,7 @@ cc_binary( cc_binary( name = "qsim_amplitudes", srcs = ["qsim_amplitudes.cc"], - copts = gsframe_copts, + copts = qsim_copts, deps = [ "//lib:bitstring", "//lib:run_qsim_lib", @@ -54,7 +60,7 @@ cc_binary( cc_binary( name = "qsimh_base", srcs = ["qsimh_base.cc"], - copts = gsframe_copts, + copts = qsim_copts, deps = [ "//lib:bitstring", "//lib:run_qsimh_lib", @@ -64,7 +70,7 @@ cc_binary( cc_binary( name = "qsimh_amplitudes", srcs = ["qsimh_amplitudes.cc"], - copts = gsframe_copts, + copts = qsim_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/compiler_probe.bzl b/dev_tools/compiler_probe.bzl index ce29d6b3b..f3acf510e 100644 --- a/dev_tools/compiler_probe.bzl +++ b/dev_tools/compiler_probe.bzl @@ -12,29 +12,143 @@ # 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) + + 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} +SSE_COPTS = {sse} +""".format( + gsframe = supports_gsframe, + avx = avx_copts, + sse = sse_copts, + ), + ) + +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"], + "fma": ["fma"], + "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", "-mbmi2"] + elif features.get("avx2"): + avx_copts = ["-mavx2", "-mfma"] + (["-mbmi2"] if features.get("bmi2") else []) + 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/tests/BUILD b/tests/BUILD index b4be45302..2ead3d7aa 100644 --- a/tests/BUILD +++ b/tests/BUILD @@ -12,30 +12,21 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@local_compiler_config//:compiler_config.bzl", "SUPPORTS_GSFRAME") +load("@local_compiler_config//:compiler_config.bzl", "AVX_COPTS", "SSE_COPTS", "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 +avx_copts = AVX_COPTS + gsframe_copts -avx512_copts = ["-march=native"] + gsframe_copts +avx512_copts = AVX_COPTS + gsframe_copts -sse_copts = ["-msse4"] + gsframe_copts +sse_copts = SSE_COPTS + gsframe_copts -windows_copts = [ - "/arch:AVX", - "/std:c++17", -] +windows_copts = AVX_COPTS -windows_avx512_copts = [ - "/arch:AVX512", - "/std:c++17", -] +windows_avx512_copts = AVX_COPTS config_setting( name = "windows", @@ -48,6 +39,8 @@ cc_test( srcs = ["bitstring_test.cc"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -62,6 +55,8 @@ cc_test( srcs = ["channel_test.cc"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -80,6 +75,8 @@ cc_test( srcs = ["channels_cirq_test.cc"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -102,6 +99,8 @@ cc_test( srcs = ["circuit_qsim_parser_test.cc"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -117,6 +116,8 @@ cc_test( srcs = ["expect_test.cc"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -137,6 +138,8 @@ cc_test( srcs = ["fuser_basic_test.cc"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -153,6 +156,8 @@ cc_test( srcs = ["fuser_mqubit_test.cc"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -183,6 +188,8 @@ cc_test( srcs = ["gates_qsim_test.cc"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -197,6 +204,8 @@ cc_library( hdrs = ["hybrid_testfixture.h"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -233,6 +242,8 @@ cc_test( srcs = ["matrix_test.cc"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -247,6 +258,8 @@ cc_library( hdrs = ["qtrajectory_testfixture.h"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -290,6 +303,8 @@ cc_test( srcs = ["run_qsim_test.cc"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -305,6 +320,8 @@ cc_test( srcs = ["run_qsimh_test.cc"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -320,6 +337,8 @@ cc_library( hdrs = ["simulator_testfixture.h"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -357,6 +376,8 @@ cc_test( srcs = ["simulator_avx512_test.cc"], copts = select({ ":windows": windows_avx512_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": avx512_copts, }), tags = ["avx"], @@ -375,6 +396,8 @@ cc_test( srcs = ["simulator_basic_test.cc"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -410,6 +433,8 @@ cc_library( hdrs = ["statespace_testfixture.h"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -447,6 +472,8 @@ cc_test( srcs = ["statespace_avx512_test.cc"], copts = select({ ":windows": windows_avx512_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": avx512_copts, }), tags = ["avx"], @@ -466,6 +493,8 @@ cc_test( srcs = ["statespace_basic_test.cc"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -503,6 +532,8 @@ cc_library( hdrs = ["unitaryspace_testfixture.h"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -533,6 +564,8 @@ cc_test( srcs = ["unitaryspace_avx512_test.cc"], copts = select({ ":windows": windows_avx512_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": avx512_copts, }), tags = ["avx"], @@ -550,6 +583,8 @@ cc_test( srcs = ["unitaryspace_basic_test.cc"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -583,6 +618,8 @@ cc_library( hdrs = ["unitary_calculator_testfixture.h"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -617,6 +654,8 @@ cc_test( srcs = ["unitary_calculator_avx512_test.cc"], copts = select({ ":windows": windows_avx512_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": avx512_copts, }), tags = ["avx"], @@ -635,6 +674,8 @@ cc_test( srcs = ["unitary_calculator_basic_test.cc"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -670,6 +711,8 @@ cc_test( srcs = ["vectorspace_test.cc"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -685,6 +728,8 @@ cc_test( srcs = ["mps_statespace_test.cc"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ @@ -700,6 +745,8 @@ cc_test( srcs = ["mps_simulator_test.cc"], copts = select({ ":windows": windows_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, "//conditions:default": [], }), deps = [ From 1495b86ede916608a96749b4ca240abd1cd0dc89 Mon Sep 17 00:00:00 2001 From: mhucka Date: Sat, 9 May 2026 23:54:43 +0000 Subject: [PATCH 03/18] Add unit tests for compiler_probe.bzl --- dev_tools/compiler_probe_test.bzl | 94 +++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 dev_tools/compiler_probe_test.bzl diff --git a/dev_tools/compiler_probe_test.bzl b/dev_tools/compiler_probe_test.bzl new file mode 100644 index 000000000..53454426b --- /dev/null +++ b/dev_tools/compiler_probe_test.bzl @@ -0,0 +1,94 @@ +# 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") + +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_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_avx2_test, + linux_avx512_test, + macos_test, + windows_test, + ) From e2767fed35624f73761770277ee73a42bbea54e0 Mon Sep 17 00:00:00 2001 From: mhucka Date: Sun, 10 May 2026 00:01:04 +0000 Subject: [PATCH 04/18] Add support for `--config=native` This provides a way to pass `-march=native` to the build. --- .bazelrc | 6 ++++++ BUILD | 5 +++++ apps/BUILD | 1 + tests/BUILD | 40 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+) diff --git a/.bazelrc b/.bazelrc index 3c38311dc..fb0fec36b 100644 --- a/.bazelrc +++ b/.bazelrc @@ -92,6 +92,12 @@ build:sse --copt=-O3 build:sse --build_tag_filters=-avx --ui_event_filters=-WARNING test:sse --test_tag_filters=-avx --ui_event_filters=-WARNING +# Build with native architecture +build:native --define=qsim_native=true +build:native --copt=-O3 +build:native --build_tag_filters= --ui_event_filters=-WARNING +test:native --test_tag_filters= --ui_event_filters=-WARNING + # Build without AVX or SSE build:basic --copt=-O3 diff --git a/BUILD b/BUILD index 2c9d76bc8..7594cb8e6 100644 --- a/BUILD +++ b/BUILD @@ -25,3 +25,8 @@ config_setting( name = "sse_requested", values = {"define": "qsim_sse=true"}, ) + +config_setting( + name = "native_requested", + values = {"define": "qsim_native=true"}, +) diff --git a/apps/BUILD b/apps/BUILD index f46e3567b..d7e52127e 100644 --- a/apps/BUILD +++ b/apps/BUILD @@ -23,6 +23,7 @@ gsframe_copts = select({ }) qsim_copts = gsframe_copts + select({ + "//:native_requested": ["-march=native"], "//:avx_requested": AVX_COPTS, "//:sse_requested": SSE_COPTS, "//conditions:default": [], diff --git a/tests/BUILD b/tests/BUILD index 2ead3d7aa..f752f34b2 100644 --- a/tests/BUILD +++ b/tests/BUILD @@ -24,6 +24,8 @@ avx512_copts = AVX_COPTS + gsframe_copts sse_copts = SSE_COPTS + gsframe_copts +native_copts = ["-march=native"] + gsframe_copts + windows_copts = AVX_COPTS windows_avx512_copts = AVX_COPTS @@ -39,6 +41,7 @@ cc_test( srcs = ["bitstring_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -55,6 +58,7 @@ cc_test( srcs = ["channel_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -75,6 +79,7 @@ cc_test( srcs = ["channels_cirq_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -99,6 +104,7 @@ cc_test( srcs = ["circuit_qsim_parser_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -116,6 +122,7 @@ cc_test( srcs = ["expect_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -138,6 +145,7 @@ cc_test( srcs = ["fuser_basic_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -156,6 +164,7 @@ cc_test( srcs = ["fuser_mqubit_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -188,6 +197,7 @@ cc_test( srcs = ["gates_qsim_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -204,6 +214,7 @@ cc_library( hdrs = ["hybrid_testfixture.h"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -225,6 +236,7 @@ cc_test( srcs = ["hybrid_avx_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//conditions:default": avx_copts, }), tags = ["avx"], @@ -242,6 +254,7 @@ cc_test( srcs = ["matrix_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -258,6 +271,7 @@ cc_library( hdrs = ["qtrajectory_testfixture.h"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -282,6 +296,7 @@ cc_test( srcs = ["qtrajectory_avx_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//conditions:default": avx_copts, }), tags = ["avx"], @@ -303,6 +318,7 @@ cc_test( srcs = ["run_qsim_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -320,6 +336,7 @@ cc_test( srcs = ["run_qsimh_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -337,6 +354,7 @@ cc_library( hdrs = ["simulator_testfixture.h"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -358,6 +376,7 @@ cc_test( srcs = ["simulator_avx_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//conditions:default": avx_copts, }), tags = ["avx"], @@ -376,6 +395,7 @@ cc_test( srcs = ["simulator_avx512_test.cc"], copts = select({ ":windows": windows_avx512_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": avx512_copts, @@ -396,6 +416,7 @@ cc_test( srcs = ["simulator_basic_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -415,6 +436,7 @@ cc_test( srcs = ["simulator_sse_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//conditions:default": sse_copts, }), tags = ["sse"], @@ -433,6 +455,7 @@ cc_library( hdrs = ["statespace_testfixture.h"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -453,6 +476,7 @@ cc_test( srcs = ["statespace_avx_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//conditions:default": avx_copts, }), tags = ["avx"], @@ -472,6 +496,7 @@ cc_test( srcs = ["statespace_avx512_test.cc"], copts = select({ ":windows": windows_avx512_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": avx512_copts, @@ -493,6 +518,7 @@ cc_test( srcs = ["statespace_basic_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -513,6 +539,7 @@ cc_test( srcs = ["statespace_sse_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//conditions:default": sse_copts, }), tags = ["sse"], @@ -532,6 +559,7 @@ cc_library( hdrs = ["unitaryspace_testfixture.h"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -547,6 +575,7 @@ cc_test( srcs = ["unitaryspace_avx_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//conditions:default": avx_copts, }), tags = ["avx"], @@ -564,6 +593,7 @@ cc_test( srcs = ["unitaryspace_avx512_test.cc"], copts = select({ ":windows": windows_avx512_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": avx512_copts, @@ -583,6 +613,7 @@ cc_test( srcs = ["unitaryspace_basic_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -601,6 +632,7 @@ cc_test( srcs = ["unitaryspace_sse_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//conditions:default": sse_copts, }), tags = ["sse"], @@ -618,6 +650,7 @@ cc_library( hdrs = ["unitary_calculator_testfixture.h"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -636,6 +669,7 @@ cc_test( srcs = ["unitary_calculator_avx_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//conditions:default": avx_copts, }), tags = ["avx"], @@ -654,6 +688,7 @@ cc_test( srcs = ["unitary_calculator_avx512_test.cc"], copts = select({ ":windows": windows_avx512_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": avx512_copts, @@ -674,6 +709,7 @@ cc_test( srcs = ["unitary_calculator_basic_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -693,6 +729,7 @@ cc_test( srcs = ["unitary_calculator_sse_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//conditions:default": sse_copts, }), tags = ["sse"], @@ -711,6 +748,7 @@ cc_test( srcs = ["vectorspace_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -728,6 +766,7 @@ cc_test( srcs = ["mps_statespace_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], @@ -745,6 +784,7 @@ cc_test( srcs = ["mps_simulator_test.cc"], copts = select({ ":windows": windows_copts, + "//:native_requested": native_copts, "//:avx_requested": avx_copts, "//:sse_requested": sse_copts, "//conditions:default": [], From e9e1bba5b05159472af54c7339ea50ace3e80975 Mon Sep 17 00:00:00 2001 From: mhucka Date: Sun, 10 May 2026 00:24:13 +0000 Subject: [PATCH 05/18] Remove incorrect ui filter --- .bazelrc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.bazelrc b/.bazelrc index fb0fec36b..ee6f0327f 100644 --- a/.bazelrc +++ b/.bazelrc @@ -95,8 +95,8 @@ test:sse --test_tag_filters=-avx --ui_event_filters=-WARNING # Build with native architecture build:native --define=qsim_native=true build:native --copt=-O3 -build:native --build_tag_filters= --ui_event_filters=-WARNING -test:native --test_tag_filters= --ui_event_filters=-WARNING +build:native --build_tag_filters= +test:native --test_tag_filters= # Build without AVX or SSE build:basic --copt=-O3 From aba0eb3f28eabb0b6f6ab14ef6eacdf903b2e065 Mon Sep 17 00:00:00 2001 From: mhucka Date: Sun, 10 May 2026 00:30:24 +0000 Subject: [PATCH 06/18] Print debug messages about flags being used --- dev_tools/compiler_probe.bzl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dev_tools/compiler_probe.bzl b/dev_tools/compiler_probe.bzl index f3acf510e..ef88f97ed 100644 --- a/dev_tools/compiler_probe.bzl +++ b/dev_tools/compiler_probe.bzl @@ -79,6 +79,12 @@ SSE_COPTS = {sse} ), ) + # Print a message to inform the user what was found. + cpu_features_str = " ".join([feat.upper() for feat, found in features.items() if found]) + flags_str = " ".join(avx_copts) + " " + " ".join(sse_copts) + print("Host CPU features detected: " + cpu_features_str) # buildifier: disable=print + print("Build options being used: " + flags_str) # buildifier: disable=print + def get_cpu_features(os_name, cpu_info): """Parses system command output to identify CPU features. From f7b6922a200f7f6e967f8b73e8313202d532667d Mon Sep 17 00:00:00 2001 From: mhucka Date: Sun, 10 May 2026 03:16:17 +0000 Subject: [PATCH 07/18] Improve options-handling --- .bazelrc | 20 +- BUILD | 23 +- apps/BUILD | 14 +- dev_tools/bazel_utils.bzl | 85 +++++ dev_tools/compiler_probe.bzl | 25 +- dev_tools/compiler_probe_test.bzl | 28 +- lib/BUILD | 10 +- tests/BUILD | 503 +++++++++++++++--------------- 8 files changed, 439 insertions(+), 269 deletions(-) create mode 100644 dev_tools/bazel_utils.bzl diff --git a/.bazelrc b/.bazelrc index ee6f0327f..3c8e04133 100644 --- a/.bazelrc +++ b/.bazelrc @@ -37,10 +37,6 @@ build:windows --cxxopt=/std:c++17 # 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 @@ -81,19 +77,19 @@ build:nosan -- # ~~~~ Instruction set options (choose one) ~~~~ # Build with AVX -build:avx --define=qsim_avx=true +build:avx --define=qsim_avx=true --define=cpu_features=AVX build:avx --copt=-O3 -build:avx --build_tag_filters=-sse --ui_event_filters=-WARNING -test:avx --test_tag_filters=-sse --ui_event_filters=-WARNING +build:avx --build_tag_filters= +test:avx --test_tag_filters= # Build with SSE -build:sse --define=qsim_sse=true +build:sse --define=qsim_sse=true --define=cpu_features=SSE build:sse --copt=-O3 -build:sse --build_tag_filters=-avx --ui_event_filters=-WARNING -test:sse --test_tag_filters=-avx --ui_event_filters=-WARNING +build:sse --build_tag_filters= +test:sse --test_tag_filters= -# Build with native architecture -build:native --define=qsim_native=true +# Let the compiler pick the best combination for the native architecture. +build:native --define=qsim_native=true --define=cpu_features=Native build:native --copt=-O3 build:native --build_tag_filters= test:native --test_tag_filters= diff --git a/BUILD b/BUILD index 7594cb8e6..dc4ba18a3 100644 --- a/BUILD +++ b/BUILD @@ -12,7 +12,20 @@ # See the License for the specific language governing permissions and # limitations under the License. -package(default_visibility = ["//visibility:public"]) +load("@local_compiler_config//:compiler_config.bzl", "AVX_COPTS", "SSE_COPTS") +load("//dev_tools:bazel_utils.bzl", "qsim_print_flags", "qsim_select_copts") + +qsim_print_flags( + name = "show_flags", + flags = qsim_select_copts( + avx_copts = AVX_COPTS, + default = [], + native_copts = ["-march=native"], + sse_copts = SSE_COPTS, + windows_copts = AVX_COPTS, + ), + visibility = ["//visibility:public"], +) # Define configurations for build with AVX and/or SSE support. @@ -26,6 +39,14 @@ config_setting( values = {"define": "qsim_sse=true"}, ) +config_setting( + name = "avx_and_sse_requested", + define_values = { + "qsim_avx": "true", + "qsim_sse": "true", + }, +) + config_setting( name = "native_requested", values = {"define": "qsim_native=true"}, diff --git a/apps/BUILD b/apps/BUILD index d7e52127e..da519e63d 100644 --- a/apps/BUILD +++ b/apps/BUILD @@ -16,18 +16,20 @@ load("@local_compiler_config//:compiler_config.bzl", "AVX_COPTS", "SSE_COPTS", "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 = gsframe_copts + select({ - "//:native_requested": ["-march=native"], - "//:avx_requested": AVX_COPTS, - "//:sse_requested": SSE_COPTS, - "//conditions:default": [], -}) +qsim_copts = gsframe_copts + qsim_select_copts( + avx_copts = AVX_COPTS, + default = [], + native_copts = ["-march=native"], + sse_copts = SSE_COPTS, + windows_copts = AVX_COPTS, +) cc_binary( name = "qsim_base", diff --git a/dev_tools/bazel_utils.bzl b/dev_tools/bazel_utils.bzl new file mode 100644 index 000000000..6391ebad0 --- /dev/null +++ b/dev_tools/bazel_utils.bzl @@ -0,0 +1,85 @@ +# 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("@local_compiler_config//:compiler_config.bzl", "HOST_HAS_AVX", "HOST_HAS_SSE") + +def qsim_select_copts(native_copts, avx_copts, sse_copts, windows_copts, default = []): + """Returns a select block for qsim compiler options based on active config. + + Handles AVX+SSE combination and errors on invalid mixtures with native. + + Args: + native_copts: Compiler options to use when --config=native is active. + avx_copts: Compiler options to use when AVX is requested. + sse_copts: Compiler options to use when SSE is requested. + windows_copts: Compiler options to use when building on Windows. + default: Fallback compiler options if no specific configuration is active. + + Returns: + A select block containing the appropriate compiler flags. + """ + return select({ + "//:native_requested": native_copts, + "//:avx_and_sse_requested": avx_copts + sse_copts, + "//:avx_requested": avx_copts, + "//:sse_requested": sse_copts, + "@platforms//os:windows": windows_copts, + "//conditions:default": default, + }) + +def qsim_feature_compatibility(feature): + """Returns a select block for target_compatible_with based on required feature. + + Ensures SIMD tests are only built/run when the corresponding config is active + OR when the host supports it in native mode. + + Args: + feature: The feature name to check for ("avx" or "sse"). + + Returns: + A select block that evaluates to an empty list if compatible, or + ["@platforms//:incompatible"] otherwise. + """ + if feature == "avx": + native_compatible = [] if HOST_HAS_AVX else ["@platforms//:incompatible"] + return select({ + "//:avx_requested": [], + "//:avx_and_sse_requested": [], + "//:native_requested": native_compatible, + "//conditions:default": ["@platforms//:incompatible"], + }) + elif feature == "sse": + native_compatible = [] if HOST_HAS_SSE else ["@platforms//:incompatible"] + return select({ + "//:sse_requested": [], + "//:avx_and_sse_requested": [], + "//:native_requested": native_compatible, + "//conditions:default": ["@platforms//:incompatible"], + }) + return [] + +def _qsim_print_flags_impl(ctx): + if ctx.attr.flags: + print("Active qsim compiler flags: " + " ".join(ctx.attr.flags)) # buildifier: disable=print + return [CcInfo()] + +qsim_print_flags = rule( + implementation = _qsim_print_flags_impl, + attrs = { + "flags": attr.string_list(), + }, + provides = [CcInfo], +) diff --git a/dev_tools/compiler_probe.bzl b/dev_tools/compiler_probe.bzl index ef88f97ed..2e88cb5da 100644 --- a/dev_tools/compiler_probe.bzl +++ b/dev_tools/compiler_probe.bzl @@ -61,6 +61,7 @@ def _compiler_probe_impl(repo_ctx): features = get_cpu_features(os_name, cpu_info) avx_copts, sse_copts = get_compiler_flags(os_name, features) + has_avx, has_sse, cpu_features_str = get_feature_booleans(features) repo_ctx.file( "BUILD.bazel", @@ -72,18 +73,37 @@ def _compiler_probe_impl(repo_ctx): SUPPORTS_GSFRAME = {gsframe} AVX_COPTS = {avx} SSE_COPTS = {sse} +CPU_FEATURES_STR = "{cpu_features}" +HOST_HAS_AVX = {has_avx} +HOST_HAS_SSE = {has_sse} """.format( gsframe = supports_gsframe, avx = avx_copts, sse = sse_copts, + cpu_features = cpu_features_str, + has_avx = has_avx, + has_sse = has_sse, ), ) # Print a message to inform the user what was found. - cpu_features_str = " ".join([feat.upper() for feat, found in features.items() if found]) flags_str = " ".join(avx_copts) + " " + " ".join(sse_copts) print("Host CPU features detected: " + cpu_features_str) # buildifier: disable=print - print("Build options being used: " + flags_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_sse, cpu_features_str). + """ + cpu_features_str = " ".join([feat.upper() for feat, found in features.items() if found]) + has_avx = "AVX" in cpu_features_str + has_sse = "SSE" in cpu_features_str + return has_avx, has_sse, cpu_features_str def get_cpu_features(os_name, cpu_info): """Parses system command output to identify CPU features. @@ -104,6 +124,7 @@ def get_cpu_features(os_name, cpu_info): feature_map = { "avx512f": ["avx512f"], "avx2": ["avx2"], + "avx": ["avx"], "fma": ["fma"], "bmi2": ["bmi2"], "sse4": ["sse4_1", "sse4_2", "sse4.1", "sse4.2"], diff --git a/dev_tools/compiler_probe_test.bzl b/dev_tools/compiler_probe_test.bzl index 53454426b..b205ef174 100644 --- a/dev_tools/compiler_probe_test.bzl +++ b/dev_tools/compiler_probe_test.bzl @@ -15,7 +15,31 @@ """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") +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) @@ -79,6 +103,7 @@ def _test_windows_impl(ctx): 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) @@ -87,6 +112,7 @@ 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, diff --git a/lib/BUILD b/lib/BUILD index 60fd0e51a..1f0ab49b9 100644 --- a/lib/BUILD +++ b/lib/BUILD @@ -75,6 +75,7 @@ cc_library( "util_cpu.h", "vectorspace.h", ], + deps = ["//:show_flags"], ) cc_library( @@ -156,6 +157,7 @@ cuda_library( ], deps = [ ":cuda", + "//:show_flags", "@local_config_cuda//cuda:cuda_headers", ], ) @@ -330,22 +332,28 @@ cc_library( cc_library( name = "bitstring", hdrs = ["bitstring.h"], + deps = ["//:show_flags"], ) cc_library( name = "bits", hdrs = ["bits.h"], + deps = ["//:show_flags"], ) cc_library( name = "matrix", hdrs = ["matrix.h"], - deps = [":bits"], + deps = [ + ":bits", + "//:show_flags", + ], ) cc_library( name = "util", hdrs = ["util.h"], + deps = ["//:show_flags"], ) cc_library( diff --git a/tests/BUILD b/tests/BUILD index f752f34b2..c1158a42d 100644 --- a/tests/BUILD +++ b/tests/BUILD @@ -14,6 +14,7 @@ load("@local_compiler_config//:compiler_config.bzl", "AVX_COPTS", "SSE_COPTS", "SUPPORTS_GSFRAME") load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") +load("//dev_tools:bazel_utils.bzl", "qsim_feature_compatibility", "qsim_select_copts") gsframe_copts = ["-Wa,--gsframe=no"] if SUPPORTS_GSFRAME else [] @@ -39,13 +40,12 @@ cc_test( name = "bitstring_test", size = "small", srcs = ["bitstring_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ "//lib:bitstring", "@com_google_googletest//:gtest_main", @@ -56,13 +56,12 @@ cc_test( name = "channel_test", size = "small", srcs = ["channel_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ "//lib:channel", "//lib:formux", @@ -77,13 +76,12 @@ cc_test( name = "channels_cirq_test", size = "small", srcs = ["channels_cirq_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ "//lib:channels_cirq", "//lib:circuit", @@ -102,13 +100,12 @@ cc_test( name = "circuit_qsim_parser_test", size = "small", srcs = ["circuit_qsim_parser_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ "//lib:circuit_qsim_parser", "//lib:gates_qsim", @@ -120,13 +117,12 @@ cc_test( name = "expect_test", size = "small", srcs = ["expect_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ "//lib:expect", "//lib:formux", @@ -143,13 +139,12 @@ cc_test( name = "fuser_basic_test", size = "small", srcs = ["fuser_basic_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ "//lib:circuit_qsim_parser", "//lib:fuser_basic", @@ -162,13 +157,12 @@ cc_test( name = "fuser_mqubit_test", size = "small", srcs = ["fuser_mqubit_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ "//lib:formux", "//lib:fuser_mqubit", @@ -195,13 +189,12 @@ cc_test( name = "gates_qsim_test", size = "small", srcs = ["gates_qsim_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ "//lib:gates_qsim", "@com_google_googletest//:gtest_main", @@ -212,13 +205,12 @@ cc_library( name = "hybrid_testfixture", testonly = 1, hdrs = ["hybrid_testfixture.h"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ "//lib:circuit_qsim_parser", "//lib:formux", @@ -234,12 +226,15 @@ cc_test( name = "hybrid_avx_test", size = "small", srcs = ["hybrid_avx_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//conditions:default": avx_copts, - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + default = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx"), deps = [ ":hybrid_testfixture", "//lib:seqfor", @@ -252,13 +247,12 @@ cc_test( name = "matrix_test", size = "small", srcs = ["matrix_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ "//lib:matrix", "@com_google_googletest//:gtest_main", @@ -269,13 +263,12 @@ cc_library( name = "qtrajectory_testfixture", testonly = 1, hdrs = ["qtrajectory_testfixture.h"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ "//lib:channel", "//lib:channels_cirq", @@ -294,12 +287,15 @@ cc_test( name = "qtrajectory_avx_test", size = "small", srcs = ["qtrajectory_avx_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//conditions:default": avx_copts, - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + default = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx"), deps = [ ":qtrajectory_testfixture", "//lib:fuser_mqubit", @@ -316,13 +312,12 @@ cc_test( name = "run_qsim_test", size = "small", srcs = ["run_qsim_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ ":gates_cirq_testfixture", "//lib:run_qsim_lib", @@ -334,13 +329,12 @@ cc_test( name = "run_qsimh_test", size = "small", srcs = ["run_qsimh_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ ":gates_cirq_testfixture", "//lib:run_qsimh_lib", @@ -352,13 +346,12 @@ cc_library( name = "simulator_testfixture", testonly = 1, hdrs = ["simulator_testfixture.h"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ "//lib:expect", "//lib:fuser_mqubit", @@ -374,12 +367,15 @@ cc_test( name = "simulator_avx_test", size = "small", srcs = ["simulator_avx_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//conditions:default": avx_copts, - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + default = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx"), deps = [ ":simulator_testfixture", "//lib:parfor", @@ -393,14 +389,15 @@ cc_test( name = "simulator_avx512_test", size = "small", srcs = ["simulator_avx512_test.cc"], - copts = select({ - ":windows": windows_avx512_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": avx512_copts, - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + default = avx512_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_avx512_copts, + ), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx"), deps = [ ":simulator_testfixture", "//lib:parfor", @@ -414,13 +411,12 @@ cc_test( name = "simulator_basic_test", size = "small", srcs = ["simulator_basic_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ ":simulator_testfixture", "//lib:parfor", @@ -434,12 +430,15 @@ cc_test( name = "simulator_sse_test", size = "small", srcs = ["simulator_sse_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//conditions:default": sse_copts, - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + default = sse_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), tags = ["sse"], + target_compatible_with = qsim_feature_compatibility("sse"), deps = [ ":simulator_testfixture", "//lib:parfor", @@ -453,13 +452,12 @@ cc_library( name = "statespace_testfixture", testonly = 1, hdrs = ["statespace_testfixture.h"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ "//lib:circuit_qsim_parser", "//lib:fuser_basic", @@ -474,12 +472,15 @@ cc_test( name = "statespace_avx_test", size = "small", srcs = ["statespace_avx_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//conditions:default": avx_copts, - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + default = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx"), deps = [ ":statespace_testfixture", "//lib:parfor", @@ -494,14 +495,15 @@ cc_test( name = "statespace_avx512_test", size = "small", srcs = ["statespace_avx512_test.cc"], - copts = select({ - ":windows": windows_avx512_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": avx512_copts, - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + default = avx512_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_avx512_copts, + ), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx"), deps = [ ":statespace_testfixture", "//lib:parfor", @@ -516,13 +518,12 @@ cc_test( name = "statespace_basic_test", size = "small", srcs = ["statespace_basic_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ ":statespace_testfixture", "//lib:parfor", @@ -537,12 +538,15 @@ cc_test( name = "statespace_sse_test", size = "small", srcs = ["statespace_sse_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//conditions:default": sse_copts, - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + default = sse_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), tags = ["sse"], + target_compatible_with = qsim_feature_compatibility("sse"), deps = [ ":statespace_testfixture", "//lib:parfor", @@ -557,13 +561,12 @@ cc_library( name = "unitaryspace_testfixture", testonly = 1, hdrs = ["unitaryspace_testfixture.h"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ "@com_google_googletest//:gtest_main", ], @@ -573,12 +576,15 @@ cc_test( name = "unitaryspace_avx_test", size = "small", srcs = ["unitaryspace_avx_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//conditions:default": avx_copts, - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + default = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx"), deps = [ ":unitaryspace_testfixture", "//lib:formux", @@ -591,14 +597,15 @@ cc_test( name = "unitaryspace_avx512_test", size = "small", srcs = ["unitaryspace_avx512_test.cc"], - copts = select({ - ":windows": windows_avx512_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": avx512_copts, - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + default = avx512_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_avx512_copts, + ), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx"), deps = [ ":unitaryspace_testfixture", "//lib:formux", @@ -611,13 +618,12 @@ cc_test( name = "unitaryspace_basic_test", size = "small", srcs = ["unitaryspace_basic_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ ":unitaryspace_testfixture", "//lib:formux", @@ -630,12 +636,15 @@ cc_test( name = "unitaryspace_sse_test", size = "small", srcs = ["unitaryspace_sse_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//conditions:default": sse_copts, - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + default = sse_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), tags = ["sse"], + target_compatible_with = qsim_feature_compatibility("sse"), deps = [ ":unitaryspace_testfixture", "//lib:formux", @@ -648,13 +657,12 @@ cc_library( name = "unitary_calculator_testfixture", testonly = 1, hdrs = ["unitary_calculator_testfixture.h"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ "//lib:fuser", "//lib:gate_appl", @@ -667,12 +675,15 @@ cc_test( name = "unitary_calculator_avx_test", size = "small", srcs = ["unitary_calculator_avx_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//conditions:default": avx_copts, - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + default = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx"), deps = [ ":unitary_calculator_testfixture", "//lib:formux", @@ -686,14 +697,15 @@ cc_test( name = "unitary_calculator_avx512_test", size = "small", srcs = ["unitary_calculator_avx512_test.cc"], - copts = select({ - ":windows": windows_avx512_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": avx512_copts, - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + default = avx512_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_avx512_copts, + ), tags = ["avx"], + target_compatible_with = qsim_feature_compatibility("avx"), deps = [ ":unitary_calculator_testfixture", "//lib:formux", @@ -707,13 +719,12 @@ cc_test( name = "unitary_calculator_basic_test", size = "small", srcs = ["unitary_calculator_basic_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ ":unitary_calculator_testfixture", "//lib:formux", @@ -727,12 +738,15 @@ cc_test( name = "unitary_calculator_sse_test", size = "small", srcs = ["unitary_calculator_sse_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//conditions:default": sse_copts, - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + default = sse_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), tags = ["sse"], + target_compatible_with = qsim_feature_compatibility("sse"), deps = [ ":unitary_calculator_testfixture", "//lib:formux", @@ -746,13 +760,12 @@ cc_test( name = "vectorspace_test", size = "small", srcs = ["vectorspace_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ "//lib:formux", "//lib:vectorspace", @@ -764,13 +777,12 @@ cc_test( name = "mps_statespace_test", size = "small", srcs = ["mps_statespace_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ "//lib:formux", "//lib:mps_statespace", @@ -782,13 +794,12 @@ cc_test( name = "mps_simulator_test", size = "small", srcs = ["mps_simulator_test.cc"], - copts = select({ - ":windows": windows_copts, - "//:native_requested": native_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "//conditions:default": [], - }), + copts = qsim_select_copts( + avx_copts = avx_copts, + native_copts = native_copts, + sse_copts = sse_copts, + windows_copts = windows_copts, + ), deps = [ "//lib:formux", "//lib:gate_appl", From 6ff42dc5f8369c818bed7f0dc6dd06d30e09b9e6 Mon Sep 17 00:00:00 2001 From: mhucka Date: Sun, 10 May 2026 05:30:46 +0000 Subject: [PATCH 08/18] Add the ability to specify avx2 and avx512 independently --- .bazelrc | 12 ++ BUILD | 56 +++++-- apps/BUILD | 14 +- dev_tools/bazel_utils.bzl | 142 +++++++++++++--- dev_tools/compiler_probe.bzl | 36 ++++- tests/BUILD | 304 +++++------------------------------ 6 files changed, 246 insertions(+), 318 deletions(-) diff --git a/.bazelrc b/.bazelrc index 3c8e04133..bc2468179 100644 --- a/.bazelrc +++ b/.bazelrc @@ -82,6 +82,18 @@ build:avx --copt=-O3 build:avx --build_tag_filters= test:avx --test_tag_filters= +# Build with AVX2 +build:avx2 --define=qsim_avx2=true --define=cpu_features=AVX2 +build:avx2 --copt=-O3 +build:avx2 --build_tag_filters= +test:avx2 --test_tag_filters= + +# Build with AVX512 +build:avx512 --define=qsim_avx512=true --define=cpu_features=AVX512 +build:avx512 --copt=-O3 +build:avx512 --build_tag_filters= +test:avx512 --test_tag_filters= + # Build with SSE build:sse --define=qsim_sse=true --define=cpu_features=SSE build:sse --copt=-O3 diff --git a/BUILD b/BUILD index dc4ba18a3..f176aaf5f 100644 --- a/BUILD +++ b/BUILD @@ -12,18 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@local_compiler_config//:compiler_config.bzl", "AVX_COPTS", "SSE_COPTS") load("//dev_tools:bazel_utils.bzl", "qsim_print_flags", "qsim_select_copts") qsim_print_flags( name = "show_flags", - flags = qsim_select_copts( - avx_copts = AVX_COPTS, - default = [], - native_copts = ["-march=native"], - sse_copts = SSE_COPTS, - windows_copts = AVX_COPTS, - ), + flags = qsim_select_copts(target_level = "avx"), visibility = ["//visibility:public"], ) @@ -35,8 +28,46 @@ config_setting( ) config_setting( - name = "sse_requested", - values = {"define": "qsim_sse=true"}, + name = "avx2_requested", + values = {"define": "qsim_avx2=true"}, +) + +config_setting( + name = "avx512_requested", + values = {"define": "qsim_avx512=true"}, +) + +config_setting( + name = "avx_and_avx2_requested", + define_values = { + "qsim_avx": "true", + "qsim_avx2": "true", + }, +) + +config_setting( + name = "avx_and_avx512_requested", + define_values = { + "qsim_avx": "true", + "qsim_avx512": "true", + }, +) + +config_setting( + name = "avx512_and_avx2_requested", + define_values = { + "qsim_avx512": "true", + "qsim_avx2": "true", + }, +) + +config_setting( + name = "avx_all_requested", + define_values = { + "qsim_avx": "true", + "qsim_avx2": "true", + "qsim_avx512": "true", + }, ) config_setting( @@ -47,6 +78,11 @@ config_setting( }, ) +config_setting( + name = "sse_requested", + values = {"define": "qsim_sse=true"}, +) + config_setting( name = "native_requested", values = {"define": "qsim_native=true"}, diff --git a/apps/BUILD b/apps/BUILD index da519e63d..46608a3fc 100644 --- a/apps/BUILD +++ b/apps/BUILD @@ -14,22 +14,10 @@ # TODO: remove reliance on getopt (unistd.h) to allow apps to run on Windows. -load("@local_compiler_config//:compiler_config.bzl", "AVX_COPTS", "SSE_COPTS", "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 = gsframe_copts + qsim_select_copts( - avx_copts = AVX_COPTS, - default = [], - native_copts = ["-march=native"], - sse_copts = SSE_COPTS, - windows_copts = AVX_COPTS, -) +qsim_copts = qsim_select_copts(target_level = "avx") cc_binary( name = "qsim_base", diff --git a/dev_tools/bazel_utils.bzl b/dev_tools/bazel_utils.bzl index 6391ebad0..6ccff656e 100644 --- a/dev_tools/bazel_utils.bzl +++ b/dev_tools/bazel_utils.bzl @@ -14,59 +14,149 @@ """Utility functions for qsim Bazel builds.""" -load("@local_compiler_config//:compiler_config.bzl", "HOST_HAS_AVX", "HOST_HAS_SSE") +load("@local_compiler_config//:compiler_config.bzl", "AVX2_COPTS", "AVX512_COPTS", "AVX_COPTS", "BMI2_COPTS", "HOST_HAS_AVX", "HOST_HAS_AVX2", "HOST_HAS_AVX512", "HOST_HAS_SSE", "SSE_COPTS", "SUPPORTS_GSFRAME") -def qsim_select_copts(native_copts, avx_copts, sse_copts, windows_copts, default = []): +def qsim_select_copts(target_level = "basic"): """Returns a select block for qsim compiler options based on active config. - Handles AVX+SSE combination and errors on invalid mixtures with native. + Handles AVX variants and SSE combinations. Args: - native_copts: Compiler options to use when --config=native is active. - avx_copts: Compiler options to use when AVX is requested. - sse_copts: Compiler options to use when SSE is requested. - windows_copts: Compiler options to use when building on Windows. - default: Fallback compiler options if no specific configuration is active. + target_level: The instruction set level for this target. + Options: "basic", "avx", "avx2", "avx512", "sse". + If "basic", SIMD flags are only added if --config=native is active. Returns: A select block containing the appropriate compiler flags. """ - return select({ - "//:native_requested": native_copts, - "//:avx_and_sse_requested": avx_copts + sse_copts, - "//:avx_requested": avx_copts, - "//:sse_requested": sse_copts, - "@platforms//os:windows": windows_copts, - "//conditions:default": default, + + gsframe_flags = ["-Wa,--gsframe=no"] if SUPPORTS_GSFRAME else [] + linux_gsframe = select({ + "@platforms//os:linux": gsframe_flags, + "//conditions:default": [], + }) + + # 1. Native configuration: always uses host optimization. + native_part = select({ + "//:native_requested": ["-march=native"], + "//conditions:default": [], + }) + + # 2. Main instruction set selection. + # We flatten the logic into a single select per target_level. + + if target_level == "basic": + main_select = select({ + "@platforms//os:windows": [], + "//conditions:default": [], + }) + elif target_level == "sse": + main_select = select({ + "@platforms//os:windows": [], + "//:sse_requested": SSE_COPTS, + "//:native_requested": [], + "//conditions:default": SSE_COPTS, + }) + elif target_level == "avx": + main_select = select({ + "@platforms//os:windows": AVX_COPTS, + "//:avx512_requested": AVX_COPTS, + "//:avx2_requested": AVX_COPTS, + "//:avx_requested": AVX_COPTS, + "//:native_requested": [], + "//conditions:default": AVX_COPTS, + }) + elif target_level == "avx2": + main_select = select({ + "@platforms//os:windows": AVX_COPTS, + "//:avx512_requested": AVX2_COPTS, + "//:avx2_requested": AVX2_COPTS, + "//:avx_requested": AVX_COPTS, + "//:native_requested": [], + "//conditions:default": AVX2_COPTS, + }) + elif target_level == "avx512": + main_select = select({ + "@platforms//os:windows": AVX_COPTS, + "//:avx512_requested": AVX512_COPTS, + "//:avx2_requested": AVX2_COPTS, + "//:avx_requested": AVX_COPTS, + "//:native_requested": [], + "//conditions:default": AVX512_COPTS, + }) + else: + fail("Invalid target_level: " + target_level) + + # 3. SSE is additive for AVX configurations. + sse_requested_val = SSE_COPTS if target_level != "sse" else [] + sse_select = select({ + "@platforms//os:windows": [], + "//:native_requested": [], + "//:sse_requested": sse_requested_val, + "//conditions:default": [], }) + # 4. BMI2 is additive to everything except Windows and Native. + bmi2_select = select({ + "@platforms//os:windows": [], + "//:native_requested": [], + "//conditions:default": BMI2_COPTS, + }) + + return native_part + main_select + sse_select + bmi2_select + linux_gsframe + def qsim_feature_compatibility(feature): """Returns a select block for target_compatible_with based on required feature. - Ensures SIMD tests are only built/run when the corresponding config is active - OR when the host supports it in native mode. + Ensures SIMD tests are only built/run when BOTH the corresponding config + is active AND the host supports it. Args: - feature: The feature name to check for ("avx" or "sse"). + 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. """ + + 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": - native_compatible = [] if HOST_HAS_AVX else ["@platforms//:incompatible"] return select({ - "//:avx_requested": [], - "//:avx_and_sse_requested": [], - "//:native_requested": native_compatible, + "//:avx_requested": avx_ok, + "//:avx2_requested": avx2_ok, + "//:avx512_requested": avx512_ok, + "//:avx_and_avx2_requested": avx_ok, + "//:avx_and_avx512_requested": avx_ok, + "//:avx512_and_avx2_requested": avx2_ok, + "//:avx_all_requested": avx_ok, + "//:avx_and_sse_requested": avx_ok, + "//:native_requested": avx_ok, + "//conditions:default": ["@platforms//:incompatible"], + }) + elif feature == "avx2": + return select({ + "//:avx2_requested": avx2_ok, + "//:avx512_requested": avx512_ok, + "//:avx512_and_avx2_requested": avx2_ok, + "//:native_requested": avx2_ok, + "//conditions:default": ["@platforms//:incompatible"], + }) + elif feature == "avx512": + return select({ + "//:avx512_requested": avx512_ok, + "//:avx512_and_avx2_requested": avx512_ok, + "//:native_requested": avx512_ok, "//conditions:default": ["@platforms//:incompatible"], }) elif feature == "sse": - native_compatible = [] if HOST_HAS_SSE else ["@platforms//:incompatible"] return select({ - "//:sse_requested": [], - "//:avx_and_sse_requested": [], - "//:native_requested": native_compatible, + "//:sse_requested": sse_ok, + "//:avx_and_sse_requested": sse_ok, + "//:native_requested": sse_ok, "//conditions:default": ["@platforms//:incompatible"], }) return [] diff --git a/dev_tools/compiler_probe.bzl b/dev_tools/compiler_probe.bzl index 2e88cb5da..0417f88c5 100644 --- a/dev_tools/compiler_probe.bzl +++ b/dev_tools/compiler_probe.bzl @@ -61,7 +61,17 @@ def _compiler_probe_impl(repo_ctx): features = get_cpu_features(os_name, cpu_info) avx_copts, sse_copts = get_compiler_flags(os_name, features) - has_avx, has_sse, cpu_features_str = get_feature_booleans(features) + has_avx, has_avx2, has_avx512, has_sse, 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"] + + bmi2_flags = ["-mbmi2"] if features.get("bmi2") else [] repo_ctx.file( "BUILD.bazel", @@ -72,22 +82,32 @@ def _compiler_probe_impl(repo_ctx): """# Generated by compiler_probe.bzl. Do not edit. SUPPORTS_GSFRAME = {gsframe} AVX_COPTS = {avx} +AVX2_COPTS = {avx2} +AVX512_COPTS = {avx512} SSE_COPTS = {sse} +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} """.format( gsframe = supports_gsframe, avx = avx_copts, + avx2 = avx2_flags, + avx512 = avx512_flags, sse = sse_copts, + bmi2 = bmi2_flags, cpu_features = cpu_features_str, has_avx = has_avx, + has_avx2 = has_avx2, + has_avx512 = has_avx512, has_sse = has_sse, ), ) # Print a message to inform the user what was found. - flags_str = " ".join(avx_copts) + " " + " ".join(sse_copts) + flags_str = " ".join(avx_copts) + " " + " ".join(sse_copts) + " " + " ".join(bmi2_flags) print("Host CPU features detected: " + cpu_features_str) # buildifier: disable=print print("Available host-optimized flags: " + flags_str) # buildifier: disable=print @@ -98,12 +118,14 @@ def get_feature_booleans(features): features: A dict of detected features (from get_cpu_features). Returns: - A tuple of (has_avx, has_sse, cpu_features_str). + A tuple of (has_avx, has_avx2, has_avx512, has_sse, cpu_features_str). """ cpu_features_str = " ".join([feat.upper() for feat, found in features.items() if found]) - has_avx = "AVX" in cpu_features_str + 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 - return has_avx, has_sse, cpu_features_str + return has_avx, has_avx2, has_avx512, has_sse, cpu_features_str def get_cpu_features(os_name, cpu_info): """Parses system command output to identify CPU features. @@ -164,9 +186,9 @@ def get_compiler_flags(os_name, features): avx_copts = ["/arch:AVX"] else: if features.get("avx512f"): - avx_copts = ["-mavx512f", "-mbmi2"] + avx_copts = ["-mavx512f"] elif features.get("avx2"): - avx_copts = ["-mavx2", "-mfma"] + (["-mbmi2"] if features.get("bmi2") else []) + avx_copts = ["-mavx2", "-mfma"] else: avx_copts = ["-mavx"] diff --git a/tests/BUILD b/tests/BUILD index c1158a42d..27fa45c8a 100644 --- a/tests/BUILD +++ b/tests/BUILD @@ -12,25 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@local_compiler_config//:compiler_config.bzl", "AVX_COPTS", "SSE_COPTS", "SUPPORTS_GSFRAME") load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load("//dev_tools:bazel_utils.bzl", "qsim_feature_compatibility", "qsim_select_copts") -gsframe_copts = ["-Wa,--gsframe=no"] if SUPPORTS_GSFRAME else [] - -# Options for testing different simulator types. -avx_copts = AVX_COPTS + gsframe_copts - -avx512_copts = AVX_COPTS + gsframe_copts - -sse_copts = SSE_COPTS + gsframe_copts - -native_copts = ["-march=native"] + gsframe_copts - -windows_copts = AVX_COPTS - -windows_avx512_copts = AVX_COPTS - config_setting( name = "windows", constraint_values = ["@platforms//os:windows"], @@ -40,12 +24,7 @@ cc_test( name = "bitstring_test", size = "small", srcs = ["bitstring_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:bitstring", "@com_google_googletest//:gtest_main", @@ -56,12 +35,7 @@ cc_test( name = "channel_test", size = "small", srcs = ["channel_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:channel", "//lib:formux", @@ -76,12 +50,7 @@ cc_test( name = "channels_cirq_test", size = "small", srcs = ["channels_cirq_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:channels_cirq", "//lib:circuit", @@ -100,12 +69,7 @@ cc_test( name = "circuit_qsim_parser_test", size = "small", srcs = ["circuit_qsim_parser_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:circuit_qsim_parser", "//lib:gates_qsim", @@ -117,12 +81,7 @@ cc_test( name = "expect_test", size = "small", srcs = ["expect_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:expect", "//lib:formux", @@ -139,12 +98,7 @@ cc_test( name = "fuser_basic_test", size = "small", srcs = ["fuser_basic_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:circuit_qsim_parser", "//lib:fuser_basic", @@ -157,12 +111,7 @@ cc_test( name = "fuser_mqubit_test", size = "small", srcs = ["fuser_mqubit_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:formux", "//lib:fuser_mqubit", @@ -189,12 +138,7 @@ cc_test( name = "gates_qsim_test", size = "small", srcs = ["gates_qsim_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:gates_qsim", "@com_google_googletest//:gtest_main", @@ -205,12 +149,7 @@ cc_library( name = "hybrid_testfixture", testonly = 1, hdrs = ["hybrid_testfixture.h"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:circuit_qsim_parser", "//lib:formux", @@ -226,13 +165,7 @@ cc_test( name = "hybrid_avx_test", size = "small", srcs = ["hybrid_avx_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - default = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "avx"), tags = ["avx"], target_compatible_with = qsim_feature_compatibility("avx"), deps = [ @@ -247,12 +180,7 @@ cc_test( name = "matrix_test", size = "small", srcs = ["matrix_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:matrix", "@com_google_googletest//:gtest_main", @@ -263,12 +191,7 @@ cc_library( name = "qtrajectory_testfixture", testonly = 1, hdrs = ["qtrajectory_testfixture.h"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:channel", "//lib:channels_cirq", @@ -287,13 +210,7 @@ cc_test( name = "qtrajectory_avx_test", size = "small", srcs = ["qtrajectory_avx_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - default = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "avx"), tags = ["avx"], target_compatible_with = qsim_feature_compatibility("avx"), deps = [ @@ -312,12 +229,7 @@ cc_test( name = "run_qsim_test", size = "small", srcs = ["run_qsim_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ ":gates_cirq_testfixture", "//lib:run_qsim_lib", @@ -329,12 +241,7 @@ cc_test( name = "run_qsimh_test", size = "small", srcs = ["run_qsimh_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ ":gates_cirq_testfixture", "//lib:run_qsimh_lib", @@ -346,12 +253,7 @@ cc_library( name = "simulator_testfixture", testonly = 1, hdrs = ["simulator_testfixture.h"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:expect", "//lib:fuser_mqubit", @@ -367,13 +269,7 @@ cc_test( name = "simulator_avx_test", size = "small", srcs = ["simulator_avx_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - default = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "avx"), tags = ["avx"], target_compatible_with = qsim_feature_compatibility("avx"), deps = [ @@ -389,15 +285,9 @@ cc_test( name = "simulator_avx512_test", size = "small", srcs = ["simulator_avx512_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - default = avx512_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_avx512_copts, - ), + copts = qsim_select_copts(target_level = "avx512"), tags = ["avx"], - target_compatible_with = qsim_feature_compatibility("avx"), + target_compatible_with = qsim_feature_compatibility("avx512"), deps = [ ":simulator_testfixture", "//lib:parfor", @@ -411,12 +301,7 @@ cc_test( name = "simulator_basic_test", size = "small", srcs = ["simulator_basic_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ ":simulator_testfixture", "//lib:parfor", @@ -430,13 +315,7 @@ cc_test( name = "simulator_sse_test", size = "small", srcs = ["simulator_sse_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - default = sse_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "sse"), tags = ["sse"], target_compatible_with = qsim_feature_compatibility("sse"), deps = [ @@ -452,12 +331,7 @@ cc_library( name = "statespace_testfixture", testonly = 1, hdrs = ["statespace_testfixture.h"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "sse"), deps = [ "//lib:circuit_qsim_parser", "//lib:fuser_basic", @@ -472,13 +346,7 @@ cc_test( name = "statespace_avx_test", size = "small", srcs = ["statespace_avx_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - default = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "avx"), tags = ["avx"], target_compatible_with = qsim_feature_compatibility("avx"), deps = [ @@ -495,15 +363,9 @@ cc_test( name = "statespace_avx512_test", size = "small", srcs = ["statespace_avx512_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - default = avx512_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_avx512_copts, - ), + copts = qsim_select_copts(target_level = "avx512"), tags = ["avx"], - target_compatible_with = qsim_feature_compatibility("avx"), + target_compatible_with = qsim_feature_compatibility("avx512"), deps = [ ":statespace_testfixture", "//lib:parfor", @@ -518,12 +380,7 @@ cc_test( name = "statespace_basic_test", size = "small", srcs = ["statespace_basic_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ ":statespace_testfixture", "//lib:parfor", @@ -538,13 +395,7 @@ cc_test( name = "statespace_sse_test", size = "small", srcs = ["statespace_sse_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - default = sse_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "sse"), tags = ["sse"], target_compatible_with = qsim_feature_compatibility("sse"), deps = [ @@ -561,12 +412,7 @@ cc_library( name = "unitaryspace_testfixture", testonly = 1, hdrs = ["unitaryspace_testfixture.h"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "sse"), deps = [ "@com_google_googletest//:gtest_main", ], @@ -576,13 +422,7 @@ cc_test( name = "unitaryspace_avx_test", size = "small", srcs = ["unitaryspace_avx_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - default = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "avx"), tags = ["avx"], target_compatible_with = qsim_feature_compatibility("avx"), deps = [ @@ -597,15 +437,9 @@ cc_test( name = "unitaryspace_avx512_test", size = "small", srcs = ["unitaryspace_avx512_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - default = avx512_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_avx512_copts, - ), + copts = qsim_select_copts(target_level = "avx512"), tags = ["avx"], - target_compatible_with = qsim_feature_compatibility("avx"), + target_compatible_with = qsim_feature_compatibility("avx512"), deps = [ ":unitaryspace_testfixture", "//lib:formux", @@ -618,12 +452,7 @@ cc_test( name = "unitaryspace_basic_test", size = "small", srcs = ["unitaryspace_basic_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ ":unitaryspace_testfixture", "//lib:formux", @@ -636,13 +465,7 @@ cc_test( name = "unitaryspace_sse_test", size = "small", srcs = ["unitaryspace_sse_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - default = sse_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "sse"), tags = ["sse"], target_compatible_with = qsim_feature_compatibility("sse"), deps = [ @@ -657,12 +480,7 @@ cc_library( name = "unitary_calculator_testfixture", testonly = 1, hdrs = ["unitary_calculator_testfixture.h"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "sse"), deps = [ "//lib:fuser", "//lib:gate_appl", @@ -675,13 +493,7 @@ cc_test( name = "unitary_calculator_avx_test", size = "small", srcs = ["unitary_calculator_avx_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - default = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "avx"), tags = ["avx"], target_compatible_with = qsim_feature_compatibility("avx"), deps = [ @@ -697,15 +509,9 @@ cc_test( name = "unitary_calculator_avx512_test", size = "small", srcs = ["unitary_calculator_avx512_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - default = avx512_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_avx512_copts, - ), + copts = qsim_select_copts(target_level = "avx512"), tags = ["avx"], - target_compatible_with = qsim_feature_compatibility("avx"), + target_compatible_with = qsim_feature_compatibility("avx512"), deps = [ ":unitary_calculator_testfixture", "//lib:formux", @@ -719,12 +525,7 @@ cc_test( name = "unitary_calculator_basic_test", size = "small", srcs = ["unitary_calculator_basic_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ ":unitary_calculator_testfixture", "//lib:formux", @@ -738,13 +539,7 @@ cc_test( name = "unitary_calculator_sse_test", size = "small", srcs = ["unitary_calculator_sse_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - default = sse_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "sse"), tags = ["sse"], target_compatible_with = qsim_feature_compatibility("sse"), deps = [ @@ -760,12 +555,7 @@ cc_test( name = "vectorspace_test", size = "small", srcs = ["vectorspace_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:formux", "//lib:vectorspace", @@ -777,12 +567,7 @@ cc_test( name = "mps_statespace_test", size = "small", srcs = ["mps_statespace_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:formux", "//lib:mps_statespace", @@ -794,12 +579,7 @@ cc_test( name = "mps_simulator_test", size = "small", srcs = ["mps_simulator_test.cc"], - copts = qsim_select_copts( - avx_copts = avx_copts, - native_copts = native_copts, - sse_copts = sse_copts, - windows_copts = windows_copts, - ), + copts = qsim_select_copts(target_level = "basic"), deps = [ "//lib:formux", "//lib:gate_appl", From 11d3cdd8c7f776fc9763afbe2d1138f55bd2b190 Mon Sep 17 00:00:00 2001 From: mhucka Date: Sun, 10 May 2026 05:35:57 +0000 Subject: [PATCH 09/18] Refactor dev_tools/test_libs.sh With the availability of the `--config=native` option, this can be simplified. --- dev_tools/test_libs.sh | 44 +++++++----------------------------------- 1 file changed, 7 insertions(+), 37 deletions(-) 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 From d7df1c709f8f6f86cbed3685da4ebe9f7ee2f4b5 Mon Sep 17 00:00:00 2001 From: mhucka Date: Sun, 10 May 2026 05:36:11 +0000 Subject: [PATCH 10/18] Remove no-longer-needed py-cpuinfo --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) 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", From 226318d27ce4d157bbfd94f572420982e55a2c22 Mon Sep 17 00:00:00 2001 From: mhucka Date: Sun, 10 May 2026 05:38:27 +0000 Subject: [PATCH 11/18] Add more hardware tests to ci.yaml --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 878817142..0d42da10c 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: [avx512, avx2, avx, sse, native, basic] # Optimizers for parallelism. parallel_opt: [openmp, nopenmp] steps: From 7843dc489585f4820044b6dd0ef460f004a64488 Mon Sep 17 00:00:00 2001 From: mhucka Date: Sun, 10 May 2026 06:08:00 +0000 Subject: [PATCH 12/18] Update comment --- .bazelrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bazelrc b/.bazelrc index bc2468179..71558c837 100644 --- a/.bazelrc +++ b/.bazelrc @@ -74,7 +74,7 @@ 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 --define=cpu_features=AVX From 942a85fd1e8b32c1538e7cdc1bbe591e4fe7a1e2 Mon Sep 17 00:00:00 2001 From: mhucka Date: Mon, 11 May 2026 04:16:19 +0000 Subject: [PATCH 13/18] Overhaul implementation Simplify code and fix behavioral problems. --- .bazelrc | 21 ++- BUILD | 57 ++----- dev_tools/bazel_utils.bzl | 293 ++++++++++++++++++++++------------- dev_tools/compiler_probe.bzl | 20 ++- lib/BUILD | 11 +- 5 files changed, 237 insertions(+), 165 deletions(-) diff --git a/.bazelrc b/.bazelrc index 71558c837..2955a059a 100644 --- a/.bazelrc +++ b/.bazelrc @@ -25,7 +25,6 @@ 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:macos --copt=-std=c++17 build:macos --cxxopt=-std=c++17 @@ -49,9 +48,12 @@ test --test_timeout=600 # Configs for verbose builds & tests common:verbose --announce_rc common:verbose --auto_output_filter=none +common:verbose --define=qsim_verbose=true build:verbose --show_progress_rate_limit=1 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) ~~~~ @@ -77,31 +79,38 @@ build:nosan -- # ~~~~ Instruction set options (can be combined) ~~~~ # Build with AVX -build:avx --define=qsim_avx=true --define=cpu_features=AVX +build:avx --define=qsim_avx=true build:avx --copt=-O3 build:avx --build_tag_filters= test:avx --test_tag_filters= # Build with AVX2 -build:avx2 --define=qsim_avx2=true --define=cpu_features=AVX2 +build:avx2 --define=qsim_avx2=true build:avx2 --copt=-O3 build:avx2 --build_tag_filters= test:avx2 --test_tag_filters= # Build with AVX512 -build:avx512 --define=qsim_avx512=true --define=cpu_features=AVX512 +build:avx512 --define=qsim_avx512=true build:avx512 --copt=-O3 build:avx512 --build_tag_filters= test:avx512 --test_tag_filters= # Build with SSE -build:sse --define=qsim_sse=true --define=cpu_features=SSE +build:sse --define=qsim_sse=true build:sse --copt=-O3 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 +build:bmi2 --copt=-O3 + # Let the compiler pick the best combination for the native architecture. -build:native --define=qsim_native=true --define=cpu_features=Native +build:native --define=qsim_native=true build:native --copt=-O3 build:native --build_tag_filters= test:native --test_tag_filters= diff --git a/BUILD b/BUILD index f176aaf5f..3cbb6113e 100644 --- a/BUILD +++ b/BUILD @@ -12,15 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//dev_tools:bazel_utils.bzl", "qsim_print_flags", "qsim_select_copts") +load("//dev_tools:bazel_utils.bzl", "qsim_print_config", "qsim_validate_host") -qsim_print_flags( - name = "show_flags", - flags = qsim_select_copts(target_level = "avx"), +qsim_validate_host( + name = "validate_host", visibility = ["//visibility:public"], ) -# Define configurations for build with AVX and/or SSE support. +qsim_print_config(name = "print_config") + +# Define configurations for build with AVX, SSE, and BMI support. config_setting( name = "avx_requested", @@ -38,52 +39,26 @@ config_setting( ) config_setting( - name = "avx_and_avx2_requested", - define_values = { - "qsim_avx": "true", - "qsim_avx2": "true", - }, -) - -config_setting( - name = "avx_and_avx512_requested", - define_values = { - "qsim_avx": "true", - "qsim_avx512": "true", - }, -) - -config_setting( - name = "avx512_and_avx2_requested", - define_values = { - "qsim_avx512": "true", - "qsim_avx2": "true", - }, + name = "sse_requested", + values = {"define": "qsim_sse=true"}, ) config_setting( - name = "avx_all_requested", - define_values = { - "qsim_avx": "true", - "qsim_avx2": "true", - "qsim_avx512": "true", - }, + name = "bmi_requested", + values = {"define": "qsim_bmi=true"}, ) config_setting( - name = "avx_and_sse_requested", - define_values = { - "qsim_avx": "true", - "qsim_sse": "true", - }, + name = "bmi2_requested", + values = {"define": "qsim_bmi2=true"}, ) config_setting( - name = "sse_requested", - values = {"define": "qsim_sse=true"}, + name = "native_requested", + values = {"define": "qsim_native=true"}, ) config_setting( - name = "native_requested", - values = {"define": "qsim_native=true"}, + name = "verbose_requested", + values = {"define": "qsim_verbose=true"}, ) diff --git a/dev_tools/bazel_utils.bzl b/dev_tools/bazel_utils.bzl index 6ccff656e..8deca8e2c 100644 --- a/dev_tools/bazel_utils.bzl +++ b/dev_tools/bazel_utils.bzl @@ -14,103 +14,188 @@ """Utility functions for qsim Bazel builds.""" -load("@local_compiler_config//:compiler_config.bzl", "AVX2_COPTS", "AVX512_COPTS", "AVX_COPTS", "BMI2_COPTS", "HOST_HAS_AVX", "HOST_HAS_AVX2", "HOST_HAS_AVX512", "HOST_HAS_SSE", "SSE_COPTS", "SUPPORTS_GSFRAME") +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 AVX variants and SSE combinations. + Handles additive combinations of AVX, SSE, and BMI. Args: - target_level: The instruction set level for this target. + target_level: The maximum instruction set level for this target. Options: "basic", "avx", "avx2", "avx512", "sse". - If "basic", SIMD flags are only added if --config=native is active. + If "basic", SIMD flags are only added if requested. Returns: - A select block containing the appropriate compiler flags. + A list of select blocks that sum to the appropriate compiler flags. """ - gsframe_flags = ["-Wa,--gsframe=no"] if SUPPORTS_GSFRAME else [] - linux_gsframe = select({ - "@platforms//os:linux": gsframe_flags, - "//conditions:default": [], - }) - - # 1. Native configuration: always uses host optimization. + # 1. Native configuration. native_part = select({ "//:native_requested": ["-march=native"], "//conditions:default": [], }) - # 2. Main instruction set selection. - # We flatten the logic into a single select per target_level. - - if target_level == "basic": - main_select = select({ - "@platforms//os:windows": [], - "//conditions:default": [], - }) - elif target_level == "sse": - main_select = select({ - "@platforms//os:windows": [], - "//:sse_requested": SSE_COPTS, - "//:native_requested": [], - "//conditions:default": SSE_COPTS, - }) - elif target_level == "avx": - main_select = select({ - "@platforms//os:windows": AVX_COPTS, - "//:avx512_requested": AVX_COPTS, - "//:avx2_requested": AVX_COPTS, - "//:avx_requested": AVX_COPTS, - "//:native_requested": [], - "//conditions:default": AVX_COPTS, - }) - elif target_level == "avx2": - main_select = select({ - "@platforms//os:windows": AVX_COPTS, - "//:avx512_requested": AVX2_COPTS, - "//:avx2_requested": AVX2_COPTS, - "//:avx_requested": AVX_COPTS, - "//:native_requested": [], - "//conditions:default": AVX2_COPTS, - }) - elif target_level == "avx512": - main_select = select({ - "@platforms//os:windows": AVX_COPTS, - "//:avx512_requested": AVX512_COPTS, - "//:avx2_requested": AVX2_COPTS, - "//:avx_requested": AVX_COPTS, - "//:native_requested": [], - "//conditions:default": AVX512_COPTS, - }) - else: - fail("Invalid target_level: " + target_level) + # 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 is additive for AVX configurations. - sse_requested_val = SSE_COPTS if target_level != "sse" else [] - sse_select = select({ - "@platforms//os:windows": [], + # 3. SSE part (additive) + sse_part = select({ "//:native_requested": [], - "//:sse_requested": sse_requested_val, + "//:sse_requested": SSE_COPTS, "//conditions:default": [], }) - # 4. BMI2 is additive to everything except Windows and Native. - bmi2_select = select({ - "@platforms//os:windows": [], + # 4. BMI part (additive) + bmi_part = select({ "//:native_requested": [], - "//conditions:default": BMI2_COPTS, + "//: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 + main_select + sse_select + bmi2_select + linux_gsframe + 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. - Ensures SIMD tests are only built/run when BOTH the corresponding config - is active AND the host supports it. - Args: feature: The feature name to check for ("avx", "avx2", "avx512" or "sse"). @@ -119,57 +204,51 @@ def qsim_feature_compatibility(feature): ["@platforms//:incompatible"] otherwise. """ - 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"] + # 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 select({ - "//:avx_requested": avx_ok, - "//:avx2_requested": avx2_ok, - "//:avx512_requested": avx512_ok, - "//:avx_and_avx2_requested": avx_ok, - "//:avx_and_avx512_requested": avx_ok, - "//:avx512_and_avx2_requested": avx2_ok, - "//:avx_all_requested": avx_ok, - "//:avx_and_sse_requested": avx_ok, - "//:native_requested": avx_ok, + return selects.with_or({ + ( + "//:avx_requested", + "//:avx2_requested", + "//:avx512_requested", + "//:native_requested", + ): avx_ok, "//conditions:default": ["@platforms//:incompatible"], }) elif feature == "avx2": - return select({ - "//:avx2_requested": avx2_ok, - "//:avx512_requested": avx512_ok, - "//:avx512_and_avx2_requested": avx2_ok, - "//:native_requested": avx2_ok, + return selects.with_or({ + ( + "//:avx2_requested", + "//:avx512_requested", + "//:native_requested", + ): avx2_ok, "//conditions:default": ["@platforms//:incompatible"], }) elif feature == "avx512": - return select({ - "//:avx512_requested": avx512_ok, - "//:avx512_and_avx2_requested": avx512_ok, - "//:native_requested": avx512_ok, + return selects.with_or({ + ( + "//:avx512_requested", + "//:native_requested", + ): avx512_ok, "//conditions:default": ["@platforms//:incompatible"], }) elif feature == "sse": - return select({ - "//:sse_requested": sse_ok, - "//:avx_and_sse_requested": sse_ok, - "//:native_requested": sse_ok, + return selects.with_or({ + ( + "//:sse_requested", + "//:native_requested", + ): sse_ok, "//conditions:default": ["@platforms//:incompatible"], }) return [] - -def _qsim_print_flags_impl(ctx): - if ctx.attr.flags: - print("Active qsim compiler flags: " + " ".join(ctx.attr.flags)) # buildifier: disable=print - return [CcInfo()] - -qsim_print_flags = rule( - implementation = _qsim_print_flags_impl, - attrs = { - "flags": attr.string_list(), - }, - provides = [CcInfo], -) diff --git a/dev_tools/compiler_probe.bzl b/dev_tools/compiler_probe.bzl index 0417f88c5..53a439f54 100644 --- a/dev_tools/compiler_probe.bzl +++ b/dev_tools/compiler_probe.bzl @@ -61,7 +61,7 @@ def _compiler_probe_impl(repo_ctx): 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, cpu_features_str = get_feature_booleans(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: @@ -71,7 +71,8 @@ def _compiler_probe_impl(repo_ctx): avx2_flags = ["-mavx2", "-mfma"] avx512_flags = ["-mavx512f", "-mavx2", "-mfma"] - bmi2_flags = ["-mbmi2"] if features.get("bmi2") else [] + bmi_flags = ["-mbmi"] if has_bmi and not has_bmi2 else [] + bmi2_flags = ["-mbmi2"] if has_bmi2 else [] repo_ctx.file( "BUILD.bazel", @@ -85,29 +86,35 @@ 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(bmi2_flags) + 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 @@ -118,14 +125,16 @@ def get_feature_booleans(features): features: A dict of detected features (from get_cpu_features). Returns: - A tuple of (has_avx, has_avx2, has_avx512, has_sse, cpu_features_str). + 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 - return has_avx, has_avx2, has_avx512, has_sse, 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. @@ -148,6 +157,7 @@ def get_cpu_features(os_name, cpu_info): "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"], diff --git a/lib/BUILD b/lib/BUILD index 1f0ab49b9..d7e637dfa 100644 --- a/lib/BUILD +++ b/lib/BUILD @@ -75,7 +75,7 @@ cc_library( "util_cpu.h", "vectorspace.h", ], - deps = ["//:show_flags"], + deps = ["//:validate_host"], ) cc_library( @@ -157,7 +157,7 @@ cuda_library( ], deps = [ ":cuda", - "//:show_flags", + "//:validate_host", "@local_config_cuda//cuda:cuda_headers", ], ) @@ -233,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", @@ -283,6 +284,7 @@ cc_library( "util_cpu.h", "vectorspace.h", ], + deps = ["//:validate_host"], ) # Library to run qsimh with qsim circuit parser and parallel `for` @@ -322,6 +324,7 @@ cc_library( "util_cpu.h", "vectorspace.h", ], + deps = ["//:validate_host"], ) ##### Basic libraries ##### @@ -332,13 +335,11 @@ cc_library( cc_library( name = "bitstring", hdrs = ["bitstring.h"], - deps = ["//:show_flags"], ) cc_library( name = "bits", hdrs = ["bits.h"], - deps = ["//:show_flags"], ) cc_library( @@ -346,14 +347,12 @@ cc_library( hdrs = ["matrix.h"], deps = [ ":bits", - "//:show_flags", ], ) cc_library( name = "util", hdrs = ["util.h"], - deps = ["//:show_flags"], ) cc_library( From 2fda88d0da897a1b74415879ea15cd67bfb5d634 Mon Sep 17 00:00:00 2001 From: mhucka Date: Mon, 11 May 2026 04:56:30 +0000 Subject: [PATCH 14/18] Update docs/bazel.md to explain new flags --- docs/bazel.md | 108 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 69 insertions(+), 39 deletions(-) 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. From e6de1412678203595ed9b129852a59927df83285 Mon Sep 17 00:00:00 2001 From: mhucka Date: Mon, 11 May 2026 04:56:44 +0000 Subject: [PATCH 15/18] Remove flag that is never used --- .bazelrc | 4 +--- BUILD | 5 ----- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/.bazelrc b/.bazelrc index 2955a059a..e750be949 100644 --- a/.bazelrc +++ b/.bazelrc @@ -15,7 +15,6 @@ # ~~~~ General flags ~~~~ # Common flags -common --announce_rc common --experimental_repo_remote_exec common --verbose_failures @@ -48,8 +47,7 @@ test --test_timeout=600 # Configs for verbose builds & tests common:verbose --announce_rc common:verbose --auto_output_filter=none -common:verbose --define=qsim_verbose=true -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. diff --git a/BUILD b/BUILD index 3cbb6113e..3fa93304e 100644 --- a/BUILD +++ b/BUILD @@ -57,8 +57,3 @@ config_setting( name = "native_requested", values = {"define": "qsim_native=true"}, ) - -config_setting( - name = "verbose_requested", - values = {"define": "qsim_verbose=true"}, -) From 60fb3b32f6b00016e4edc4781c743e17e0cf57f8 Mon Sep 17 00:00:00 2001 From: mhucka Date: Mon, 11 May 2026 04:57:25 +0000 Subject: [PATCH 16/18] Remove qsimh from bazel build & test targets --- apps/BUILD | 20 -------------------- tests/BUILD | 12 ------------ 2 files changed, 32 deletions(-) diff --git a/apps/BUILD b/apps/BUILD index 46608a3fc..f46c44bb1 100644 --- a/apps/BUILD +++ b/apps/BUILD @@ -47,23 +47,3 @@ cc_binary( "//lib:run_qsim_lib", ], ) - -cc_binary( - name = "qsimh_base", - srcs = ["qsimh_base.cc"], - copts = qsim_copts, - deps = [ - "//lib:bitstring", - "//lib:run_qsimh_lib", - ], -) - -cc_binary( - name = "qsimh_amplitudes", - srcs = ["qsimh_amplitudes.cc"], - copts = qsim_copts, - deps = [ - "//lib:bitstring", - "//lib:run_qsimh_lib", - ], -) diff --git a/tests/BUILD b/tests/BUILD index 27fa45c8a..693897f4c 100644 --- a/tests/BUILD +++ b/tests/BUILD @@ -237,18 +237,6 @@ cc_test( ], ) -cc_test( - name = "run_qsimh_test", - size = "small", - srcs = ["run_qsimh_test.cc"], - copts = qsim_select_copts(target_level = "basic"), - deps = [ - ":gates_cirq_testfixture", - "//lib:run_qsimh_lib", - "@com_google_googletest//:gtest_main", - ], -) - cc_library( name = "simulator_testfixture", testonly = 1, From 36c14839488ebc1ca93822736ff6f97f2e0db42d Mon Sep 17 00:00:00 2001 From: mhucka Date: Mon, 11 May 2026 05:17:43 +0000 Subject: [PATCH 17/18] Can't use avx512 on GitHub runners --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2a3008a46..d5a1aca14 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -308,7 +308,7 @@ jobs: strategy: matrix: # Hardware optimizers. - hardware_opt: [avx512, avx2, avx, sse, native, basic] + hardware_opt: [avx, sse, native, basic] # Optimizers for parallelism. parallel_opt: [openmp, nopenmp] steps: From 53bd3cd86543da6e367a1ddf6e10ea1314330d3e Mon Sep 17 00:00:00 2001 From: mhucka Date: Mon, 11 May 2026 05:25:38 +0000 Subject: [PATCH 18/18] Adjust for Windows differences --- .bazelrc | 11 ++++------- BUILD | 17 +++++++++++++++++ dev_tools/bazel_utils.bzl | 5 +++-- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/.bazelrc b/.bazelrc index e750be949..61306e8f6 100644 --- a/.bazelrc +++ b/.bazelrc @@ -24,12 +24,15 @@ common --enable_platform_specific_config build:linux --copt=-std=c++17 build:linux --cxxopt=-std=c++17 +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: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. @@ -78,25 +81,21 @@ build:nosan -- # Build with AVX build:avx --define=qsim_avx=true -build:avx --copt=-O3 build:avx --build_tag_filters= test:avx --test_tag_filters= # Build with AVX2 build:avx2 --define=qsim_avx2=true -build:avx2 --copt=-O3 build:avx2 --build_tag_filters= test:avx2 --test_tag_filters= # Build with AVX512 build:avx512 --define=qsim_avx512=true -build:avx512 --copt=-O3 build:avx512 --build_tag_filters= test:avx512 --test_tag_filters= # Build with SSE build:sse --define=qsim_sse=true -build:sse --copt=-O3 build:sse --build_tag_filters= test:sse --test_tag_filters= @@ -105,16 +104,14 @@ build:bmi --config=bmi2 # Build with BMI2 build:bmi2 --define=qsim_bmi2=true -build:bmi2 --copt=-O3 # Let the compiler pick the best combination for the native architecture. build:native --define=qsim_native=true -build:native --copt=-O3 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/BUILD b/BUILD index 3fa93304e..52d2ee1a6 100644 --- a/BUILD +++ b/BUILD @@ -57,3 +57,20 @@ 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/dev_tools/bazel_utils.bzl b/dev_tools/bazel_utils.bzl index 8deca8e2c..d96e7d7fc 100644 --- a/dev_tools/bazel_utils.bzl +++ b/dev_tools/bazel_utils.bzl @@ -47,8 +47,9 @@ def qsim_select_copts(target_level = "basic"): """ # 1. Native configuration. - native_part = select({ - "//:native_requested": ["-march=native"], + # Windows (MSVC) does not support -march=native. + native_part = selects.with_or({ + ("//:native_on_linux", "//:native_on_macos"): ["-march=native"], "//conditions:default": [], })