blob: 9a29b74f29398218453d1406955504a814e2157f [file]
# Copyright 2025 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 AMDGPU libraries."""
def iree_amdgpu_binary(
name,
target,
arch,
srcs,
internal_hdrs = [],
copts = [],
linkopts = [],
clang_tool = "@llvm-project//clang:clang",
link_tool = "@llvm-project//llvm:llvm-link",
lld_tool = "@llvm-project//lld:lld",
objcopy_tool = None,
builtin_headers_dep = "@llvm-project//clang:builtin_headers_gen",
builtin_headers_marker = None,
builtin_headers_include_flag = "-isystem $(BINDIR)/external/+_repo_rules+llvm-project/clang/staging/include/",
**kwargs):
"""Builds an LLVM shared library for AMDGPU from input files via clang.
Args:
name: Name of the target.
target: LLVM `-target` flag.
arch: LLVM `-march` flag.
srcs: source files or filegroups to pass to clang.
internal_hdrs: headers that should invalidate device compilation but
are not compiled as translation units or exposed as
interface headers.
copts: additional flags to pass to clang.
linkopts: additional flags to pass to lld.
clang_tool: clang/amdclang executable target.
link_tool: llvm-link executable target.
lld_tool: lld executable target.
objcopy_tool: optional llvm-objcopy executable target used to minimize
the linked ELF image.
builtin_headers_dep: target containing clang builtin headers.
builtin_headers_marker: optional single builtin header file used to
derive the builtin header include directory.
builtin_headers_include_flag: shell fragment adding the builtin header
include directory to clang.
**kwargs: any additional attributes to pass to the underlying rules.
"""
base_copts = [
# C configuration.
"-x c",
"-std=c23",
"-Xclang -finclude-default-header",
"-nogpulib",
"-fno-short-wchar",
# Target architecture/machine.
"-target %s" % (target),
"-march=%s" % (arch),
"-fgpu-rdc", # NOTE: may not be required for all targets
# Header paths for builtins and our own includes.
builtin_headers_include_flag,
"-I$(BINDIR)/runtime/src",
"-Iruntime/src",
# Avoid warnings about things we do that are not compatible across
# compilers but are fine because we're only ever compiling with clang.
"-Wno-gnu-pointer-arith",
# Optimized.
"-fno-ident",
"-fvisibility=hidden",
"-O3",
# Object file only in bitcode format.
"-c",
"-emit-llvm",
]
archive_out = "%s.a" % (name)
source_locations = " ".join(["$(locations %s)" % (src,) for src in srcs])
object_dir = "$(@D)/%s.objects" % (name,)
compile_srcs = srcs + [builtin_headers_dep] + internal_hdrs
if builtin_headers_marker != None:
compile_srcs.append(builtin_headers_marker)
native.genrule(
name = "archive_%s" % (name),
srcs = compile_srcs,
outs = [archive_out],
cmd = " && ".join([
"set -e",
"object_dir=\"%s\"" % (object_dir,),
"rm -rf \"$${object_dir}\"",
"mkdir -p \"$${object_dir}\"",
"object_index=0",
"for src in %s; do %s; object_index=$$((object_index + 1)); done" % (
source_locations,
" ".join([
"$(location %s)" % (clang_tool),
" ".join(base_copts + copts),
"-o \"$${object_dir}/$${object_index}.bc\"",
"\"$${src}\"",
]),
),
" ".join([
"$(location %s)" % (link_tool),
"\"$${object_dir}\"/*.bc",
"-o $(location %s)" % (archive_out),
]),
]),
tools = [
clang_tool,
link_tool,
],
message = "Compiling bitcode library %s to %s..." % (srcs, archive_out),
output_to_bindir = 1,
**kwargs
)
link_out = "%s.bc" % (name)
native.genrule(
name = "link_%s" % (name),
srcs = [archive_out],
outs = [link_out],
cmd = " && ".join([
" ".join([
"$(location %s)" % (link_tool),
"-internalize",
"-only-needed",
"$(locations %s)" % (archive_out),
"-o $(location %s)" % (link_out),
]),
]),
tools = [link_tool],
message = "Linking bitcode library %s to %s..." % (name, link_out),
output_to_bindir = 1,
**kwargs
)
base_linkopts = [
"-m elf64_amdgpu",
"--build-id=none",
"--no-undefined",
"-shared",
"-plugin-opt=mcpu=%s" % (arch),
"-plugin-opt=O3",
"--lto-CGO3",
"--no-whole-archive",
"--gc-sections",
"--strip-debug",
"--discard-all",
"--discard-locals",
]
out = "%s.so" % (name)
version_script = "$(@D)/%s.local.version" % (name,)
link_output = "$(location %s)" % (out)
lld_linkopts = base_linkopts + linkopts
objcopy_command = None
if objcopy_tool != None:
link_output = "$(@D)/%s.linked.so" % (name,)
lld_linkopts = lld_linkopts + [
"--version-script=\"%s\"" % (version_script,),
]
objcopy_command = " ".join([
"$(location %s)" % (objcopy_tool),
"-R .comment",
"-R .AMDGPU.gpr_maximums",
"--discard-all",
"-N _DYNAMIC",
"\"%s\"" % (link_output,),
"$(location %s)" % (out),
])
cmd = []
if objcopy_tool != None:
cmd.append("printf '{\\n local:\\n *;\\n};\\n' > \"%s\"" % (version_script,))
cmd.append(" ".join([
"$(location %s)" % (lld_tool),
"-flavor gnu",
" ".join(lld_linkopts),
"$(location %s)" % (link_out),
"-o \"%s\"" % (link_output,),
]))
if objcopy_command:
cmd.append(objcopy_command)
native.genrule(
name = name,
srcs = [link_out],
outs = [out],
cmd = " && ".join(cmd),
tools = [tool for tool in [lld_tool, objcopy_tool] if tool != None],
message = "Generating OpenCL binary %s to %s..." % (name, out),
output_to_bindir = 1,
**kwargs
)