blob: 0faa537dfe9124ee432710fb830c1060fd7dc350 [file] [log] [blame] [edit]
"""Build extensions for //third_party/gmp.
Architectures: Several macros in this file refer to "architecture names". These
are the names for architectures used by GMP, not the names for architectures
used at Google. Available names are defined by directories in
third_party/gmp/mpn.
"""
def gmp_assembly(src, out, architectures, operation = None, included_srcs = []):
"""Converts a GMP .asm file into architecture-specific .s files.
GMP's assembly code is not written directly in assembly (files ending in .s)
but rather in a slightly higher-level mixture of assembly and M4 (files
ending in .asm). The M4 is really just for configuration tweaks and some
quality-of-life improvements; it doesn't make the assembly any less
architecture-specific. This Starlark macro creates genrules to preprocess
the .asm files with M4.
Args:
src: The path to the input .asm file.
out: The path to the output .s file.
architectures: The list of architecture names (strings) for which .s files
should be generated.
operation: Optional. The name of the function defined in the .asm file. If
specified, M4 will be invoked with `-DOPERATION_{operation}`. (This is
necessary because GMP can generate multiple functions from the same
assembly skeleton.)
included_srcs: Optional. A list of all .asm files that are included (via
M4 inclusion) by the .asm file in `src`. Files in this list are copied
into the genrule sandbox but are not passed on the command line to M4.
Specify this if .s generation fails with M4 complaining about missing
files.
Example:
gmp_assembly(
src = "mpn/{architecture}/aors_n.asm",
out = "mpn/{architecture}/add_n.s",
architectures = [
"arm",
"arm64",
"x86",
"x86_64",
],
operation = "add_n",
)
"""
for architecture in architectures:
full_src = src.format(architecture = architecture)
native.genrule(
name = out.format(architecture = architecture).replace("/", "_").replace(".", "_"),
srcs = [
full_src,
"google-config-%s/config.m4" % architecture,
"mpn/asm-defs.m4",
"mpn/%s/%s-defs.m4" % (architecture, architecture),
] + [src.format(architecture = architecture) for src in included_srcs],
outs = [out.format(architecture = architecture)],
tools = ["//third_party/m4"],
cmd = """
$(location //third_party/m4) -DHAVE_CONFIG_H -D__GMP_WITHIN_GMP {operation} -DPIC -I $(RULEDIR)/mpn/{architecture} -I third_party/gmp/mpn/{architecture} -I $(RULEDIR)/mpn -I third_party/gmp/mpn -I $(RULEDIR)/google-config-{architecture} {full_src} >$@
""".format(
architecture = architecture,
full_src = full_src,
operation = "-DOPERATION_" + operation if operation else "",
) + select({
# Add noexec stack note to the generated assembly
"//third_party/bazel_platforms/cpu:armv7": """printf '\t.section\t.note.GNU-stack,"",%%progbits\n' >>$@""",
"//conditions:default": """printf '\t.section\t.note.GNU-stack,"",@progbits\n' >>$@""",
}),
)
def gmp_mpn_assembly(src, out, architectures, included_srcs = []):
"""Converts a GMP MPN .asm file into architecture-specific .s files.
MPN is GMP's architecture-specific layer and where most of its assembly code
exists. This macro is a convenience macro for invoking `gmp_assembly` on MPN
files. It allows you to simply specify the basenames of the .asm and .s
files, and it infers the desired operation from the output file name.
Args:
src: The basename of the input .asm file (inside `mpn/{architecture}`).
out: The basename of the output .s file (inside `mpn/{architecture}`).
architectures: The list of architecture names (strings) for which .s files
should be generated.
included_srcs: Optional. Basenames of all .asm files (inside
`mpn/{architecture}`) that are included (via M4 inclusion) by the .asm
file in `src`. Files in this list are copied into the genrule sandbox
but are not passed on the command line to M4. Specify this if .s
generation fails with M4 complaining about missing files.
Example:
gmp_mpn_assembly(
src = "aors_n.asm",
out = "add_n.s",
architectures = [
"arm",
"arm64",
"x86",
"x86_64",
],
)
"""
gmp_assembly(
src = "mpn/{architecture}/%s" % src,
out = "mpn/{architecture}/%s" % out,
architectures = architectures,
operation = out[:out.rfind(".")],
included_srcs = ["mpn/{architecture}/%s" % src for src in included_srcs],
)
def gmp_mpn_library(name, srcs, operation, deps = []):
"""Runs the C++ compiler to generate a GMP MPN object.
MPN is GMP's architecture-specific layer. MPN libraries require some special
compiler flags; this macro wraps `cc_library` to add them. Use it instead of
`cc_library` to compile libraries inside third_party/gmp/mpn.
Args:
name: A unique name for this target.
srcs: The list of C and assembly files that are processed to create the
library target.
operation: The name of the function defined in the C or assembly file. The
C preprocessor will be invoked with `-DOPERATION_{operation}`. (This is
necessary because GMP can generate multiple functions from the same
skeleton.)
deps: The list of other libraries that the library target depends on.
"""
native.cc_library(
name = name,
srcs = [
"longlong.h",
] + srcs,
local_defines = [
"HAVE_CONFIG_H",
"__GMP_WITHIN_GMP",
"OPERATION_" + operation,
],
deps = [":gmp-stage2"] + deps,
includes = [
"",
"mpn",
],
copts = ["-w"],
)