|  | # Copyright 2023 The IREE Authors | 
|  | # | 
|  | # Licensed under the Apache License v2.0 with LLVM Exceptions. | 
|  | # See https://llvm.org/LICENSE.txt for license information. | 
|  | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  |  | 
|  | """Rules for compiling with clang to produce bitcode libraries.""" | 
|  |  | 
|  | def iree_arch_to_llvm_arch( | 
|  | iree_arch = None): | 
|  | """Converts an IREE_ARCH value to the corresponding LLVM arch name. | 
|  |  | 
|  | Similar to the CMake function with the same name. | 
|  |  | 
|  | Args: | 
|  | iree_arch: IREE_ARCH string value. | 
|  |  | 
|  | Returns: | 
|  | The LLVM name for that architecture (first component of target triple). | 
|  | """ | 
|  |  | 
|  | if not iree_arch: | 
|  | return None | 
|  | if iree_arch == "arm_64": | 
|  | return "aarch64" | 
|  | if iree_arch == "arm_32": | 
|  | return "arm" | 
|  | if iree_arch == "x86_64": | 
|  | return "x86_64" | 
|  | if iree_arch == "x86_32": | 
|  | return "i386" | 
|  | if iree_arch == "riscv_64": | 
|  | return "riscv64" | 
|  | if iree_arch == "riscv_32": | 
|  | return "riscv32" | 
|  | if iree_arch == "wasm_64": | 
|  | return "wasm64" | 
|  | if iree_arch == "wasm_32": | 
|  | return "wasm32" | 
|  | fail("Unhandled IREE_ARCH value %s" % iree_arch) | 
|  |  | 
|  | def iree_bitcode_library( | 
|  | name, | 
|  | arch, | 
|  | srcs, | 
|  | internal_hdrs = [], | 
|  | copts = [], | 
|  | out = None, | 
|  | **kwargs): | 
|  | """Builds an LLVM bitcode library from an input file via clang. | 
|  |  | 
|  | Args: | 
|  | name: Name of the target. | 
|  | arch: Target architecture to compile for, in IREE_ARCH format. | 
|  | srcs: source files to pass to clang. | 
|  | internal_hdrs: all headers transitively included by the source files. | 
|  | Unlike typical Bazel `hdrs`, these are not exposed as | 
|  | interface headers. This would normally be part of `srcs`, | 
|  | but separating it was easier for `bazel_to_cmake`, as | 
|  | CMake does not need this, and making this explicitly | 
|  | Bazel-only allows using `filegroup` on the Bazel side. | 
|  | copts: additional flags to pass to clang. | 
|  | out: output file name (defaults to name.bc). | 
|  | **kwargs: any additional attributes to pass to the underlying rules. | 
|  | """ | 
|  |  | 
|  | clang_tool = "@llvm-project//clang:clang" | 
|  | link_tool = "@llvm-project//llvm:llvm-link" | 
|  | builtin_headers_dep = "@llvm-project//clang:builtin_headers_gen" | 
|  | builtin_headers_path = "external/llvm-project/clang/staging/include/" | 
|  |  | 
|  | base_copts = [ | 
|  | # Target architecture | 
|  | "-target", | 
|  | iree_arch_to_llvm_arch(arch), | 
|  |  | 
|  | # C17 with no system deps. | 
|  | "-std=c17", | 
|  | "-nostdinc", | 
|  | "-ffreestanding", | 
|  |  | 
|  | # Optimized and unstamped. | 
|  | "-O3", | 
|  | "-DNDEBUG", | 
|  | "-fno-ident", | 
|  | "-fdiscard-value-names", | 
|  |  | 
|  | # Set the size of wchar_t to 4 bytes (instead of 2 bytes). | 
|  | # This must match what the runtime is built with. | 
|  | "-fno-short-wchar", | 
|  |  | 
|  | # Enable inline asm. | 
|  | "-fasm", | 
|  |  | 
|  | # Object file only in bitcode format: | 
|  | "-c", | 
|  | "-emit-llvm", | 
|  |  | 
|  | # Force the library into standalone mode (not depending on build-directory | 
|  | # configuration). | 
|  | "-DIREE_DEVICE_STANDALONE=1", | 
|  | ] | 
|  |  | 
|  | if arch == "arm_32": | 
|  | # Silence "warning: unknown platform, assuming -mfloat-abi=soft" | 
|  | base_copts.append("-mfloat-abi=soft") | 
|  | elif arch == "riscv_32": | 
|  | # On RISC-V, linking LLVM modules requires matching target-abi. | 
|  | # https://lists.llvm.org/pipermail/llvm-dev/2020-January/138450.html | 
|  | # The choice of ilp32d is simply what we have in existing riscv_32 tests. | 
|  | # Open question - how do we scale to supporting all RISC-V ABIs? | 
|  | base_copts.append("-mabi=ilp32d") | 
|  | elif arch == "riscv_64": | 
|  | # Same comments as above riscv_32 case. | 
|  | base_copts.append("-mabi=lp64d") | 
|  |  | 
|  | bitcode_files = [] | 
|  | for src in srcs: | 
|  | bitcode_out = "%s_%s.bc" % (name, src) | 
|  | bitcode_files.append(bitcode_out) | 
|  | native.genrule( | 
|  | name = "gen_%s" % (bitcode_out), | 
|  | srcs = [src, builtin_headers_dep] + internal_hdrs, | 
|  | outs = [bitcode_out], | 
|  | cmd = " && ".join([ | 
|  | " ".join([ | 
|  | "$(location %s)" % (clang_tool), | 
|  | "-isystem $(BINDIR)/%s" % builtin_headers_path, | 
|  | " ".join(base_copts + copts), | 
|  | " ".join(["-I $(BINDIR)/runtime/src"]), | 
|  | " ".join(["-I runtime/src"]), | 
|  | "-o $(location %s)" % (bitcode_out), | 
|  | "$(location %s)" % (src), | 
|  | ]), | 
|  | ]), | 
|  | tools = [ | 
|  | clang_tool, | 
|  | ], | 
|  | message = "Compiling %s to %s..." % (src, bitcode_out), | 
|  | output_to_bindir = 1, | 
|  | **kwargs | 
|  | ) | 
|  |  | 
|  | if not out: | 
|  | out = "%s.bc" % (name) | 
|  |  | 
|  | native.genrule( | 
|  | name = name, | 
|  | srcs = bitcode_files, | 
|  | outs = [out], | 
|  | cmd = " && ".join([ | 
|  | " ".join([ | 
|  | "$(location %s)" % (link_tool), | 
|  | "-o $(location %s)" % (out), | 
|  | " ".join(["$(locations %s)" % (src) for src in bitcode_files]), | 
|  | ]), | 
|  | ]), | 
|  | tools = [link_tool], | 
|  | message = "Linking bitcode library %s to %s..." % (name, out), | 
|  | output_to_bindir = 1, | 
|  | **kwargs | 
|  | ) | 
|  |  | 
|  | def iree_cuda_bitcode_library( | 
|  | name, | 
|  | cuda_arch, | 
|  | srcs, | 
|  | internal_hdrs = [], | 
|  | copts = [], | 
|  | out = None, | 
|  | **kwargs): | 
|  | """Builds an LLVM bitcode library for CUDA from an input file via clang. | 
|  |  | 
|  | Args: | 
|  | name: Name of the target. | 
|  | cuda_arch: Target sm architecture to compile for. | 
|  | srcs: source files to pass to clang. | 
|  | internal_hdrs: all headers transitively included by the source files. | 
|  | Unlike typical Bazel `hdrs`, these are not exposed as | 
|  | interface headers. This would normally be part of `srcs`, | 
|  | but separating it was easier for `bazel_to_cmake`, as | 
|  | CMake does not need this, and making this explicitly | 
|  | Bazel-only allows using `filegroup` on the Bazel side. | 
|  | copts: additional flags to pass to clang. | 
|  | out: output file name (defaults to name.bc). | 
|  | **kwargs: any additional attributes to pass to the underlying rules. | 
|  | """ | 
|  |  | 
|  | clang_tool = "@llvm-project//clang:clang" | 
|  | link_tool = "@llvm-project//llvm:llvm-link" | 
|  | builtin_headers_dep = "@llvm-project//clang:builtin_headers_gen" | 
|  | builtin_headers_path = "external/llvm-project/clang/staging/include/" | 
|  |  | 
|  | base_copts = [ | 
|  | "-x", | 
|  | "cuda", | 
|  |  | 
|  | # Target architecture | 
|  | "--cuda-gpu-arch=%s" % (cuda_arch), | 
|  |  | 
|  | # Suppress warnings | 
|  | "-Wno-unknown-cuda-version", | 
|  | "-nocudalib", | 
|  | "--cuda-device-only", | 
|  |  | 
|  | # Optimized. | 
|  | "-O3", | 
|  |  | 
|  | # Object file only in bitcode format: | 
|  | "-c", | 
|  | "-emit-llvm", | 
|  | ] | 
|  |  | 
|  | bitcode_files = [] | 
|  | for src in srcs: | 
|  | bitcode_out = "%s_%s.bc" % (name, src) | 
|  | bitcode_files.append(bitcode_out) | 
|  | native.genrule( | 
|  | name = "gen_%s" % (bitcode_out), | 
|  | srcs = [src, builtin_headers_dep] + internal_hdrs, | 
|  | outs = [bitcode_out], | 
|  | cmd = " && ".join([ | 
|  | " ".join([ | 
|  | "$(location %s)" % (clang_tool), | 
|  | " ".join(base_copts + copts), | 
|  | "-o $(location %s)" % (bitcode_out), | 
|  | "$(location %s)" % (src), | 
|  | ]), | 
|  | ]), | 
|  | tools = [ | 
|  | clang_tool, | 
|  | ], | 
|  | message = "Compiling %s to %s..." % (src, bitcode_out), | 
|  | output_to_bindir = 1, | 
|  | **kwargs | 
|  | ) | 
|  |  | 
|  | if not out: | 
|  | out = "%s.bc" % (name) | 
|  |  | 
|  | native.genrule( | 
|  | name = name, | 
|  | srcs = bitcode_files, | 
|  | outs = [out], | 
|  | cmd = " && ".join([ | 
|  | " ".join([ | 
|  | "$(location %s)" % (link_tool), | 
|  | "-o $(location %s)" % (out), | 
|  | " ".join(["$(locations %s)" % (src) for src in bitcode_files]), | 
|  | ]), | 
|  | ]), | 
|  | tools = [link_tool], | 
|  | message = "Linking bitcode library %s to %s..." % (name, out), | 
|  | output_to_bindir = 1, | 
|  | **kwargs | 
|  | ) | 
|  |  | 
|  | def iree_link_bitcode( | 
|  | name, | 
|  | bitcode_files, | 
|  | out = None, | 
|  | link_tool = "@llvm-project//llvm:llvm-link", | 
|  | **kwargs): | 
|  | """Builds an LLVM bitcode library from an input file via clang. | 
|  |  | 
|  | Args: | 
|  | name: Name of the target. | 
|  | bitcode_files: bitcode files to link together. | 
|  | out: output file name (defaults to name.bc). | 
|  | link_tool: llvm-link tool used for linking bitcode files. | 
|  | **kwargs: any additional attributes to pass to the underlying rules. | 
|  | """ | 
|  |  | 
|  | bitcode_files_qualified = [("//" + native.package_name() + b) if b.startswith(":") else ("//" + native.package_name() + "/" + b) if b.count(":") else b for b in bitcode_files] | 
|  |  | 
|  | if not out: | 
|  | out = "%s.bc" % (name) | 
|  | native.genrule( | 
|  | name = name, | 
|  | srcs = bitcode_files_qualified, | 
|  | outs = [out], | 
|  | cmd = " && ".join([ | 
|  | " ".join([ | 
|  | "$(location %s)" % (link_tool), | 
|  | "-o $(location %s)" % (out), | 
|  | " ".join(["$(locations %s)" % (src) for src in bitcode_files_qualified]), | 
|  | ]), | 
|  | ]), | 
|  | tools = [link_tool], | 
|  | message = "Linking bitcode library %s to %s..." % (name, out), | 
|  | output_to_bindir = 1, | 
|  | **kwargs | 
|  | ) |