| """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"], |
| ) |