Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 11 additions & 13 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ option(
the tools every time you update llvm-project."
ON
)
option(
APPLY_LLVM_PERFORMANCE_PATCHES
"During checkout, apply optional downstream patches to
llvm-project to improve performance."
)
Comment on lines +137 to +141
Copy link
Collaborator

@VladiKrapp-Arm VladiKrapp-Arm Oct 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This option should probably be described in the comment block on top of the file.

Should this really be off by default? Users would probably want to get the perf improvements.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The aim is that the default configuration should work out of the box. Downstream changes are additional points of failure (we would like to remove patches we already have), so I would prefer to prioritize the toolchain building first.

Release branches might be a different matter, since they use a defined and therefore stable version of LLVM.

set(
FVP_INSTALL_DIR
"${CMAKE_CURRENT_SOURCE_DIR}/fvp/install" CACHE STRING
Expand Down Expand Up @@ -280,24 +285,17 @@ if(NOT (LLVM_TOOLCHAIN_C_LIBRARY STREQUAL llvmlibc)) # libc in a separate repo?
read_repo_version(${LLVM_TOOLCHAIN_C_LIBRARY} ${LLVM_TOOLCHAIN_C_LIBRARY})
endif()

# The patches are generated from custom branch, with followin command:
# git format-patch -k origin/main
# The patches apply cleanly against llvm-project commit
# 327124ece7d59de56ca0f9faa2cd82af68c011b9.
set(
llvm_project_patches
${CMAKE_CURRENT_SOURCE_DIR}/patches/llvm-project/0001-libc-tests-with-picolibc-xfail-one-remaining-test.patch
${CMAKE_CURRENT_SOURCE_DIR}/patches/llvm-project/0002-libc-tests-with-picolibc-disable-large-tests.patch
${CMAKE_CURRENT_SOURCE_DIR}/patches/llvm-project/0003-Disable-failing-compiler-rt-test.patch
${CMAKE_CURRENT_SOURCE_DIR}/patches/llvm-project/0004-libc-tests-with-picolibc-XFAIL-uses-of-atomics.patch
${CMAKE_CURRENT_SOURCE_DIR}/patches/llvm-project/0005-libc-tests-with-picolibc-mark-two-more-large-tests.patch
)
set(LLVM_PATCH_COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/patch_llvm.py ${CMAKE_CURRENT_SOURCE_DIR}/patches/llvm-project)
if(APPLY_LLVM_PERFORMANCE_PATCHES)
set(LLVM_PATCH_COMMAND ${LLVM_PATCH_COMMAND} && ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/patch_llvm.py ${CMAKE_CURRENT_SOURCE_DIR}/patches/llvm-project-perf)
endif()

FetchContent_Declare(llvmproject
GIT_REPOSITORY https://github.com/llvm/llvm-project.git
GIT_TAG "${llvmproject_TAG}"
GIT_SHALLOW "${llvmproject_SHALLOW}"
GIT_PROGRESS TRUE
PATCH_COMMAND git reset --quiet --hard && git clean --quiet --force -dx && git am -k --ignore-whitespace --3way ${llvm_project_patches}
PATCH_COMMAND ${LLVM_PATCH_COMMAND}
# Add the llvm subdirectory later to ensure that
# LLVMEmbeddedToolchainForArm is the first project declared.
# Otherwise CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
Expand Down
134 changes: 134 additions & 0 deletions cmake/patch_llvm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#!/usr/bin/env python3

"""
Script to apply a set of patches to llvm-project sources.
"""

import argparse
import os
import pathlib
import subprocess
import sys


def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"patchdir",
help="Set of patches to apply. This should be a directory containing one or more ordered *.patch files.",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code as currently written requires this to be provided as an absolute path. We should either ease this requirement, or document it here.

I'm considering the scenario where the user wants to run this script to apply patches manually. The scenario as described in CMakeLists.txt has them in the root of LLVM-embedded-toolchain-for-Arm.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see how the paths can get muddled since the git commands need to run in the llvm-project location, whereas the patch paths will be specified relative to the script. So I've adjusted the git arguments to use -C and convert the patch paths to absolute automatically.

)
parser.add_argument(
"--llvm_dir",
help="Directory of the llvm-project git checkout, if not the current directory.",
)
parser.add_argument(
"--method",
choices=["am", "apply"],
default="apply",
help="Git command to use. git am will add each patch as a commit, whereas git apply will leave patched changes staged.",
)
parser.add_argument(
"--reset",
help="Clean and hard reset the repo to a specified commit before patching.",
)
parser.add_argument(
"--restore_on_fail",
action="store_true",
help="If a patch in a series cannot be applied, restore the original state instead of leaving patches missing. Return code will be 2 instead of 1.",
)
args = parser.parse_args()

if args.llvm_dir:
git_cmd = ["git", "-C", args.llvm_dir]
else:
git_cmd = ["git"]

if args.reset:
reset_args = git_cmd + ["reset", "--quiet", "--hard", args.reset]
subprocess.check_output(reset_args)
clean_args = git_cmd + ["clean", "--quiet", "--force", "-dx", args.reset]
subprocess.check_output(clean_args)

abs_patch_dir = os.path.abspath(args.patchdir)
patch_list = list(pathlib.Path(abs_patch_dir).glob("*.patch"))
patch_list.sort()

print(f"Found {len(patch_list)} patches to apply:")
print("\n".join(p.name for p in patch_list))

if args.method == "am":
merge_args = git_cmd + ["am", "-k", "--ignore-whitespace", "--3way"]
for patch in patch_list:
merge_args.append(str(patch))
p = subprocess.run(merge_args, capture_output=True, text=True)
print(p.stdout)
print(p.stderr)

if p.returncode == 0:
print(f"All patches applied.")
sys.exit(0)
if args.restore_on_fail:
# Check that the operation can be aborted.
# git am doesn't give any specific return codes,
# so check for unresolved working files.
rebase_apply_path = os.path.join(".git", "rebase-apply")
if args.llvm_dir:
rebase_apply_path = os.path.join(args.llvm_dir, rebase_apply_path)
if os.path.isdir(rebase_apply_path):
print("Aborting git am...")
subprocess.run(git_cmd + ["am", "--abort"], check=True)
print(f"Abort successful.")
sys.exit(2)
else:
print("Unable to abort.")
sys.exit(1)
else:
applied_patches = []
for current_patch in patch_list:
print(f"Checking {current_patch.name}...")
# Check that the patch applies before trying to apply it.
apply_check_args = git_cmd + [
"apply",
"--ignore-whitespace",
"--3way",
"--check",
str(current_patch),
]
p_check = subprocess.run(apply_check_args)

if p_check.returncode == 0:
# Patch will apply.
print(f"Applying {current_patch.name}...")
apply_args = git_cmd + [
"apply",
"--ignore-whitespace",
"--3way",
str(current_patch),
]
apply_args = subprocess.run(apply_args, check=True)
applied_patches.append(current_patch)
else:
# Patch won't apply.
print(f"Unable to apply {current_patch.name}")
if args.restore_on_fail:
# Remove any patches that have already been applied.
while len(applied_patches) > 0:
previous_patch = applied_patches.pop()
print(f"Reversing {previous_patch.name}...")
reverse_args = git_cmd + [
"apply",
"--ignore-whitespace",
"--3way",
"--reverse",
str(previous_patch),
]
p_check = subprocess.run(reverse_args, check=True)
print(
f"Rollback successful, failure occured on {current_patch.name}"
)
sys.exit(2)
sys.exit(1)
print(f"All patches applied.")


main()
9 changes: 9 additions & 0 deletions docs/building-from-source.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,12 @@ The same build directory can be used for both native and MinGW toolchains.

See [patches](https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/tree/main/patches)
directory for the current set of differences from upstream.

The patches for llvm-project are split between two folders, llvm-project and
llvm-project-perf. The former are generally required for building and
successfully running all tests. The patches in llvm-project-perf are optional,
and designed to improve performance in certain circumstances.

To reduce divergence from upstream and potential patch conflicts, the
performance patches are not applied by default, but can be enabled for an
automatic checkout with the APPLY_LLVM_PERFORMANCE_PATCHES option.
22 changes: 22 additions & 0 deletions patches/llvm-project-perf/0000-Placeholder-commit.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
From e79697a54cba9bfc1a755ed048e42054d679de61 Mon Sep 17 00:00:00 2001
From: David Candler <[email protected]>
Date: Wed, 2 Oct 2024 14:13:31 +0100
Subject: [PATCH] Placeholder commit

---
.gitignore | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore
index 0e7c6c790013..dfa0b8da0ccd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-#==============================================================================#
+#==============================================================================#
# This file specifies intentionally untracked files that git should ignore.
# See: http://www.kernel.org/pub/software/scm/git/docs/gitignore.html
#
--
2.34.1

Loading