blob: 5240f633a304f463cd9a020aef2f50b23716fb1a [file] [edit]
"""Build definitions for YNNPACK.
"""
load("@bazel_skylib//lib:selects.bzl", "selects")
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("//:generated_file.bzl", "generated_file")
load("//:register_extension_info.bzl", "register_extension_info")
def define_build_option(name, default_all = [], default_any = []):
"""Defines a build flag `name` that is explicitly true or false, all(default_all), or any(default_any).
Args:
name: The name of the build flag to define.
default_all: A list of conditions that must all be true for the flag to be enabled by default.
default_any: A list of conditions for the flag to be enabled by default if any are true.
"""
explicit_true = name + "_explicit_true"
explicit_false = name + "_explicit_false"
default = explicit_true
if default_all or default_any:
default = name + "_enabled_by_default"
selects.config_setting_group(
name = default,
match_all = default_all,
match_any = default_any,
)
native.config_setting(
name = explicit_true,
define_values = {name: "true"},
)
native.config_setting(
name = explicit_false,
define_values = {name: "false"},
)
native.alias(
name = name,
actual = select({
explicit_true: ":" + explicit_true,
explicit_false: ":" + explicit_true,
"//conditions:default": ":" + default,
}),
)
def _map_arch_copts_to_msvc(copts):
"""Maps GNU-style target architecture compiler options to Microsoft Visual Studio compiler options."""
if any([c.startswith("-mavx512") or c.startswith("-mamx") for c in copts]):
return ["/arch:AVX512"]
elif any([c in ["-mavx2"] for c in copts]):
return ["/arch:AVX2"]
elif any([c in ["-mavx", "-mfma", "-mf16c"] for c in copts]):
return ["/arch:AVX"]
elif any([c in ["-msse2", "-mssse3", "-msse4.1"] for c in copts]):
return ["/arch:SSE2"]
else:
return []
_AVX512_COPTS = ["-mavx512f", "-mavx512bw", "-mavx512vl", "-mavx512dq"]
def _copts_for_compiler(copts):
return select({
"@rules_cc//cc/compiler:clang-cl": ["/clang:" + i for i in copts],
"@rules_cc//cc/compiler:msvc-cl": _map_arch_copts_to_msvc(copts),
"//conditions:default": copts,
})
_YNN_PARAMS_FOR_ARCH = {
"arm_neon": {
"cond": "//ynnpack:ynn_enable_arm_neon",
"arch_copts": select({
"//ynnpack:arm32": [
"-marm",
"-march=armv7-a",
"-mfpu=neon",
],
"//conditions:default": [],
}),
"arch_flag": "neon",
},
"arm_neondot": {
"cond": "//ynnpack:ynn_enable_arm_neondot",
"arch_copts": select({
"//ynnpack:arm32": [
"-marm",
"-march=armv8.2-a+dotprod",
"-mfpu=neon-fp-armv8",
],
"//ynnpack:arm64": ["-march=armv8.2-a+dotprod"],
"//conditions:default": [],
}),
"arch_flag": "neondot",
},
"arm_neonfma": {
"cond": "//ynnpack:ynn_enable_arm_neonfma",
"arch_copts": select({
"//ynnpack:arm32": [
"-marm",
"-march=armv7-a",
"-mfpu=neon-vfpv4",
],
"//conditions:default": [],
}),
"arch_flag": "neonfma",
},
"arm_neonfp16": {
"cond": "//ynnpack:ynn_enable_arm_neonfp16",
"arch_copts": select({
"//ynnpack:arm32": [
"-marm",
"-march=armv7-a",
"-mfpu=neon-fp16",
],
"//conditions:default": [],
}),
"arch_flag": "neonfp16",
},
"arm_neonfp16arith": {
"cond": "//ynnpack:ynn_enable_arm_neonfp16arith",
"arch_copts": select({
"//ynnpack:arm32": [
"-marm",
"-march=armv8.2-a+fp16",
"-mfpu=neon-fp-armv8",
],
"//ynnpack:arm64": ["-march=armv8.2-a+fp16"],
"//conditions:default": [],
}),
"arch_flag": "neonfp16arith",
},
"arm_neonbf16": {
"cond": "//ynnpack:ynn_enable_arm_neonbf16",
"arch_copts": select({
"//ynnpack:arm32": [
"-marm",
"-march=armv8.2-a+bf16",
"-mfpu=neon-fp-armv8",
],
"//ynnpack:arm64": ["-march=armv8.2-a+bf16"],
"//conditions:default": [],
}),
"arch_flag": "neonbf16",
},
"arm64_neoni8mm": {
"cond": "//ynnpack:ynn_enable_arm64_neoni8mm",
"arch_copts": ["-march=armv8.2-a+i8mm"],
"arch_flag": "neoni8mm",
},
"arm64": {
"cond": "//ynnpack:ynn_enable_arm64",
},
# TODO(dsharlet): This is the same as above, should we just assume neon exists for arm64?
"arm64_neon": {
"cond": "//ynnpack:ynn_enable_arm64_neon",
"arch_flag": "neon",
},
"arm64_sme": {
"cond": "//ynnpack:ynn_enable_arm64_sme",
"arch_copts": select({
# Apple's Clang generates code that crashes with -msve (and works without it), while
# other compilers can't compile this code without it.
"//ynnpack:apple_clang": ["-march=armv8.2-a+sme"],
"//conditions:default": ["-march=armv8.2-a+sve+sme"],
}),
"arch_flag": "sme",
},
"arm64_sme2": {
"cond": "//ynnpack:ynn_enable_arm64_sme2",
"arch_copts": select({
"//ynnpack:apple_clang": ["-march=armv8.2-a+sme2"],
"//conditions:default": ["-march=armv8.2-a+sve+sme2"],
}),
"arch_flag": "sme2",
},
"arm64_sve": {
"cond": "//ynnpack:ynn_enable_arm64_sve",
"arch_copts": ["-march=armv8.2-a+sve"],
"arch_flag": "sve",
},
"x86_sse2": {
"cond": "//ynnpack:ynn_enable_x86_sse2",
"arch_copts": _copts_for_compiler(["-msse2", "-mno-ssse3"]),
"arch_flag": "sse2",
},
"x86_ssse3": {
"cond": "//ynnpack:ynn_enable_x86_ssse3",
"arch_copts": _copts_for_compiler(["-mssse3", "-mno-sse4.1"]),
"arch_flag": "ssse3",
},
"x86_sse41": {
"cond": "//ynnpack:ynn_enable_x86_sse41",
"arch_copts": _copts_for_compiler(["-msse4.1", "-mno-sse4.2"]),
"arch_flag": "sse41",
},
"x86_avx": {
"cond": "//ynnpack:ynn_enable_x86_avx",
"arch_copts": _copts_for_compiler(["-mavx", "-mno-avx2", "-mno-f16c", "-mno-fma"]),
"arch_flag": "avx",
},
"x86_f16c": {
"cond": "//ynnpack:ynn_enable_x86_f16c",
"arch_copts": _copts_for_compiler(["-mf16c"]),
"arch_flag": "f16c",
},
"x86_f16c_fma3": {
"cond": "//ynnpack:ynn_enable_x86_f16c_fma3",
"arch_copts": _copts_for_compiler(["-mf16c", "-mavx", "-mfma", "-mno-avx2"]),
"arch_flag": "f16c_fma3",
},
"x86_avx2": {
"cond": "//ynnpack:ynn_enable_x86_avx2",
"arch_copts": _copts_for_compiler(["-mavx2"]),
"arch_flag": "avx2",
},
"x86_fma3": {
"cond": "//ynnpack:ynn_enable_x86_fma3",
"arch_copts": _copts_for_compiler(["-mavx", "-mfma", "-mno-avx2"]),
"arch_flag": "fma3",
},
"x86_avx2_fma3": {
"cond": "//ynnpack:ynn_enable_x86_avx2_fma3",
"arch_copts": _copts_for_compiler(["-mavx2", "-mfma"]),
"arch_flag": "avx2_fma3",
},
"x86_avx512": {
"cond": "//ynnpack:ynn_enable_x86_avx512",
"arch_copts": _copts_for_compiler(_AVX512_COPTS),
"arch_flag": "avx512",
},
"x86_avx512bf16": {
"cond": "//ynnpack:ynn_enable_x86_avx512bf16",
"arch_copts": _copts_for_compiler(_AVX512_COPTS + ["-mavx512bf16"]),
"arch_flag": "avx512bf16",
},
"x86_avx512fp16": {
"cond": "//ynnpack:ynn_enable_x86_avx512fp16",
"arch_copts": _copts_for_compiler(_AVX512_COPTS + ["-mavx512fp16"]),
"arch_flag": "avx512fp16",
},
"x86_avx512vnni": {
"cond": "//ynnpack:ynn_enable_x86_avx512vnni",
"arch_copts": _copts_for_compiler(_AVX512_COPTS + ["-mavx512vnni"]),
"arch_flag": "avx512vnni",
},
"x86_amxbf16": {
"cond": "//ynnpack:ynn_enable_x86_amxbf16",
"arch_copts": _copts_for_compiler(["-mamx-tile", "-mamx-bf16"]),
"arch_flag": "amxbf16",
},
"x86_amxfp16": {
"cond": "//ynnpack:ynn_enable_x86_amxfp16",
"arch_copts": _copts_for_compiler(["-mamx-tile", "-mamx-fp16"]),
"arch_flag": "amxfp16",
},
"x86_amxint8": {
"cond": "//ynnpack:ynn_enable_x86_amxint8",
"arch_copts": _copts_for_compiler(["-mamx-tile", "-mamx-int8"]),
"arch_flag": "amxint8",
},
"hexagon_hvx": {
"cond": "//ynnpack:ynn_enable_hvx",
"arch_copts": ["-mhvx"],
"arch_flag": "hvx",
},
}
def ynn_if_arch(arch, if_true, if_false = []):
return select({
_YNN_PARAMS_FOR_ARCH[arch]["cond"]: if_true,
"//conditions:default": if_false,
})
def ynn_arch_copts(arch):
return _YNN_PARAMS_FOR_ARCH[arch].get("arch_copts", [])
def ynn_arch_flag(arch):
return _YNN_PARAMS_FOR_ARCH[arch].get("arch_flag", "")
def ynn_kernel_copts(unroll_loops = True):
return select({
"//ynnpack:msvc": ["/O2"],
"//conditions:default": ["-O2"] + ([] if unroll_loops else ["-fno-unroll-loops"]),
})
def ynn_binary_linkopts():
return select({
"//ynnpack:hexagon": [
"-shared",
"-Wno-unused-command-line-argument",
],
"//conditions:default": [],
})
def ynn_binary_malloc():
return select({
"//ynnpack:hexagon": "@bazel_tools//tools/cpp:malloc",
"//conditions:default": "@bazel_tools//tools/cpp:malloc",
})
def ynn_test_deps():
return select({
"//ynnpack:hexagon": [
"@com_google_googletest//:gtest",
"//ynnpack/base/hexagon:test_main",
],
"//conditions:default": ["@com_google_googletest//:gtest_main"],
})
def ynn_benchmark_deps():
return select({
"//ynnpack:hexagon": [
"@com_google_benchmark//:benchmark",
"//ynnpack/base/hexagon:benchmark_main",
],
"//conditions:default": ["@com_google_benchmark//:benchmark_main"],
})
def ynn_cc_library(
name,
srcs = [],
per_arch_srcs = {},
copts = [],
defines = [],
local_defines = [],
deps = [],
**kwargs):
"""C/C++/assembly library with architecture-specific configuration.
Define a library with architecture- and instruction-specific source files and/or compiler flags.
Args:
name: The name of the library target to define.
srcs: The list of architecture-independent source files.
per_arch_srcs: A dictionary of architectures (as found in _YNN_PARAMS_FOR_ARCH) to
architecture-specific source files.
copts: A list of compiler options to use for all srcs and per_arch_srcs.
defines: A list of macros to define for all srcs and per_arch_srcs and dependencies.
local_defines: A list of macros to define for all srcs and per_arch_srcs.
deps: A list of dependencies to use for all srcs and per_arch_srcs.
**kwargs: Other arguments to pass to the cc_library rule.
"""
deps_plus_arch_deps = deps
for arch, arch_srcs in per_arch_srcs.items():
arch_params = _YNN_PARAMS_FOR_ARCH[arch]
arch_copts = ynn_arch_copts(arch)
cc_library(
name = name + "_" + arch,
srcs = ynn_if_arch(arch, arch_srcs, []),
defines = defines + ["YNN_ARCH_" + arch.upper()],
local_defines = local_defines + ["ARCH=" + arch],
copts = copts + arch_copts,
hdrs_check = "strict",
deps = deps,
features = [
# We can't use copts with header modules...?
"-use_header_modules",
] + kwargs.get("features", []),
# Don't build this target unless explicitly requested.
tags = ["manual"],
**kwargs
)
deps_plus_arch_deps += ynn_if_arch(arch, [":" + name + "_" + arch], [])
cc_library(
name = name,
srcs = srcs,
defines = defines,
copts = copts,
local_defines = local_defines,
hdrs_check = "strict",
deps = deps_plus_arch_deps,
**kwargs
)
def ynn_generate_src_hdr(
name,
output_src,
output_hdr,
generator,
generator_args = [],
**kwargs):
"""Generates a source file from a generator script."""
native.genrule(
name = name,
outs = [output_src, output_hdr],
cmd = "$(location " + generator + ") " + "$(location " + output_src + ") " + "$(location " + output_hdr + ") " + " ".join(generator_args),
tools = [generator],
**kwargs
)
generated_file(
scopes = ["presubmit", "codesearch"],
wrapped_target = name,
)
register_extension_info(
extension = ynn_cc_library,
label_regex_for_dep = "{extension_name}",
)