Skip to content

Commit 95d926a

Browse files
committed
[lto] Only build host libraries using LTO.
At some point in the future, we may consider using LTO on the runtime/standard library, but right now is not that time. We are just trying to use LTO to improve the compile time performance of the compiler itself. rdar://24717107
1 parent 61df461 commit 95d926a

10 files changed

+342
-24
lines changed

CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,10 @@ set(SWIFT_NATIVE_CLANG_TOOLS_PATH "" CACHE STRING
140140
set(SWIFT_NATIVE_SWIFT_TOOLS_PATH "" CACHE STRING
141141
"Path to the directory that contains Swift tools that are executable on the build machine")
142142

143-
option(SWIFT_TOOLS_ENABLE_LTO
144-
"If set to true, build the swift compiler with link time optimization enabled" FALSE)
143+
set(SWIFT_TOOLS_ENABLE_LTO OFF CACHE STRING "Build Swift tools with LTO. One
144+
must specify the form of LTO by setting this to one of: 'full', 'thin'. This
145+
option only affects the tools that run on the host (the compiler), and has
146+
no effect on the target libraries (the standard library and the runtime).")
145147

146148
# The following only works with the Ninja generator in CMake >= 3.0.
147149
set(SWIFT_PARALLEL_LINK_JOBS "" CACHE STRING

cmake/modules/AddSwift.cmake

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,15 @@ function(compute_library_subdir result_var_name sdk arch)
5353
set("${result_var_name}" "${SWIFT_SDK_${sdk}_LIB_SUBDIR}/${arch}" PARENT_SCOPE)
5454
endfunction()
5555

56+
function(_compute_lto_flag option out_var)
57+
string(TOLOWER "${option}" lowercase_option)
58+
if (lowercase_option STREQUAL "full")
59+
set(${out_var} "-flto=full" PARENT_SCOPE)
60+
elseif (lowercase_option STREQUAL "thin")
61+
set(${out_var} "-flto=thin" PARENT_SCOPE)
62+
endif()
63+
endfunction()
64+
5665
# Usage:
5766
# _add_variant_c_compile_link_flags(
5867
# SDK sdk
@@ -110,7 +119,8 @@ function(_add_variant_c_compile_link_flags)
110119
endif()
111120

112121
if(CFLAGS_ENABLE_LTO)
113-
list(APPEND result "-flto")
122+
_compute_lto_flag(${CFLAGS_ENABLE_LTO} _lto_flag_out)
123+
list(APPEND result "${_lto_flag_out}")
114124
endif()
115125

116126
set("${CFLAGS_RESULT_VAR_NAME}" "${result}" PARENT_SCOPE)
@@ -150,7 +160,8 @@ function(_add_variant_c_compile_flags)
150160

151161
is_build_type_with_debuginfo("${CFLAGS_BUILD_TYPE}" debuginfo)
152162
if(debuginfo)
153-
if(SWIFT_TOOLS_ENABLE_LTO)
163+
_compute_lto_flag("${CFLAGS_ENABLE_LTO}" _lto_flag_out)
164+
if(_lto_flag_out)
154165
list(APPEND result "-gline-tables-only")
155166
else()
156167
list(APPEND result "-g")
@@ -797,13 +808,18 @@ function(_add_swift_library_single target name)
797808
set(enable_assertions "${LLVM_ENABLE_ASSERTIONS}")
798809
set(analyze_code_coverage "${SWIFT_ANALYZE_CODE_COVERAGE}")
799810
endif()
811+
812+
if (NOT SWIFTLIB_SINGLE_TARGET_LIBRARY)
813+
set(lto_type "${SWIFT_TOOLS_ENABLE_LTO}")
814+
endif()
815+
800816
_add_variant_c_compile_flags(
801817
SDK "${SWIFTLIB_SINGLE_SDK}"
802818
ARCH "${SWIFTLIB_SINGLE_ARCHITECTURE}"
803819
BUILD_TYPE "${build_type}"
804820
ENABLE_ASSERTIONS "${enable_assertions}"
805821
ANALYZE_CODE_COVERAGE "${analyze_code_coverage}"
806-
ENABLE_LTO "${SWIFT_TOOLS_ENABLE_LTO}"
822+
ENABLE_LTO "${lto_type}"
807823
DEPLOYMENT_VERSION_IOS "${SWIFTLIB_DEPLOYMENT_VERSION_IOS}"
808824
RESULT_VAR_NAME c_compile_flags
809825
)
@@ -813,7 +829,7 @@ function(_add_swift_library_single target name)
813829
BUILD_TYPE "${build_type}"
814830
ENABLE_ASSERTIONS "${enable_assertions}"
815831
ANALYZE_CODE_COVERAGE "${analyze_code_coverage}"
816-
ENABLE_LTO "${SWIFT_TOOLS_ENABLE_LTO}"
832+
ENABLE_LTO "${lto_type}"
817833
DEPLOYMENT_VERSION_IOS "${SWIFTLIB_DEPLOYMENT_VERSION_IOS}"
818834
RESULT_VAR_NAME link_flags
819835
)

test/lit.cfg

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ if platform.system() == 'Darwin':
191191
config.test_format = SwiftTest(coverage_mode=config.coverage_mode)
192192

193193
# suffixes: A list of file extensions to treat as test files.
194-
config.suffixes = ['.swift', '.ll', '.sil', '.gyb', '.m']
194+
config.suffixes = ['.swift', '.ll', '.sil', '.gyb', '.m', '.test-sh']
195195

196196
# excludes: A list of directories to exclude from the testsuite. The 'Inputs'
197197
# subdirectories contain auxiliary inputs for various tests in their parent
@@ -333,6 +333,7 @@ completion_cache_path = tempfile.mkdtemp(prefix="swift-testsuite-completion-cach
333333
ccp_opt = "-completion-cache-path %r" % completion_cache_path
334334
lit_config.note("Using code completion cache: " + completion_cache_path)
335335

336+
config.substitutions.append( ('%swift_obj_root', config.swift_obj_root) )
336337
config.substitutions.append( ('%{python}', sys.executable) )
337338
config.substitutions.append( ('%mcp_opt', mcp_opt) )
338339
config.substitutions.append( ('%swift_driver_plain', "%r" % config.swift) )

test/lit.site.cfg.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ if "@SWIFT_ASAN_BUILD@" == "TRUE":
2626
else:
2727
config.available_features.add('no_asan')
2828

29-
if '@SWIFT_TOOLS_ENABLE_LTO@' == 'TRUE':
29+
if '@SWIFT_TOOLS_ENABLE_LTO@'.lower() in ['full', 'thin']:
3030
config.available_features.add('lto')
3131
else:
3232
config.available_features.add('no_lto')

utils/build-script

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -709,10 +709,10 @@ class BuildScriptInvocation(object):
709709
pipes.quote(opt) for opt in args.extra_cmake_options)
710710
]
711711

712-
if args.lto:
712+
if args.lto_type is not None:
713713
impl_args += [
714-
"--llvm-enable-lto",
715-
"--swift-tools-enable-lto"
714+
"--llvm-enable-lto=%s" % args.lto_type,
715+
"--swift-tools-enable-lto=%s" % args.lto_type
716716
]
717717
if args.llvm_max_parallel_lto_link_jobs is not None:
718718
impl_args += [
@@ -1707,12 +1707,15 @@ details of the setups of other systems or automated environments.""")
17071707
parser.add_argument(
17081708
"--lto",
17091709
help="use lto optimization on llvm/swift tools. This does not "
1710-
"imply using lto on the swift standard library or runtime",
1711-
metavar="BOOL",
1710+
"imply using lto on the swift standard library or runtime. "
1711+
"Options: thin, full. If no optional arg is provided, full is "
1712+
"chosen by default",
1713+
metavar="LTO_TYPE",
17121714
nargs='?',
1713-
type=arguments.type.bool,
1714-
default=False,
1715-
const=True)
1715+
choices=['thin', 'full'],
1716+
default=None,
1717+
const='full',
1718+
dest='lto_type')
17161719

17171720
default_max_lto_link_job_counts = host.max_lto_link_job_counts()
17181721
parser.add_argument(

utils/build-script-impl

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ KNOWN_SETTINGS=(
7474
swift-build-type "Debug" "the CMake build variant for Swift"
7575
swift-enable-assertions "1" "enable assertions in Swift"
7676
swift-analyze-code-coverage "not-merged" "Code coverage analysis mode for Swift (false, not-merged, merged). Defaults to false if the argument is not present, and not-merged if the argument is present without a modifier."
77-
swift-tools-enable-lto "0" "enable LTO compilation of Swift tools. *NOTE* This does not include the swift standard library and runtime."
78-
llvm-enable-lto "0" "enable LTO compilation of LLVM/Clang."
77+
swift-tools-enable-lto "" "enable LTO compilation of Swift tools. *NOTE* This does not include the swift standard library and runtime. Must be set to one of 'thin' or 'full'"
78+
llvm-enable-lto "" "Must be set to one of 'thin' or 'full'"
7979
swift-tools-num-parallel-lto-link-jobs "" "The number of parallel link jobs to use when compiling swift tools"
8080
llvm-num-parallel-lto-link-jobs "" "The number of parallel link jobs to use when compiling llvm"
8181
swift-stdlib-build-type "Debug" "the CMake build variant for Swift"
@@ -289,6 +289,24 @@ function set_lldb_build_mode() {
289289
LLDB_BUILD_MODE="CustomSwift-${LLDB_BUILD_TYPE}"
290290
}
291291

292+
function is_llvm_lto_enabled() {
293+
if [[ "${LLVM_ENABLE_LTO}" == "thin" ]] ||
294+
[[ "${LLVM_ENABLE_LTO}" == "full" ]]; then
295+
echo "TRUE"
296+
else
297+
echo "FALSE"
298+
fi
299+
}
300+
301+
function is_swift_lto_enabled() {
302+
if [[ "${SWIFT_TOOLS_ENABLE_LTO}" == "thin" ]] ||
303+
[[ "${SWIFT_TOOLS_ENABLE_LTO}" == "full" ]]; then
304+
echo "TRUE"
305+
else
306+
echo "FALSE"
307+
fi
308+
}
309+
292310
# Support for performing isolated actions.
293311
#
294312
# This is part of refactoring more work to be done or controllable via
@@ -567,8 +585,8 @@ function set_build_options_for_host() {
567585
-DCOMPILER_RT_ENABLE_TVOS:BOOL=FALSE
568586
-DSANITIZER_MIN_OSX_VERSION="${cmake_osx_deployment_target}"
569587
)
570-
if [[ $(true_false "${LLVM_ENABLE_LTO}") = "TRUE" ]]; then
571-
if [[ $(cmake_needs_to_specify_standard_computed_defaults) = "TRUE" ]]; then
588+
if [[ $(is_llvm_lto_enabled) == "TRUE" ]]; then
589+
if [[ $(cmake_needs_to_specify_standard_computed_defaults) == "TRUE" ]]; then
572590
llvm_cmake_options+=(
573591
"-DCMAKE_C_STANDARD_COMPUTED_DEFAULT=AppleClang"
574592
"-DCMAKE_CXX_STANDARD_COMPUTED_DEFAULT=AppleClang"
@@ -580,7 +598,7 @@ function set_build_options_for_host() {
580598
)
581599
fi
582600

583-
if [[ $(true_false "${SWIFT_TOOLS_ENABLE_LTO}") = "TRUE" ]]; then
601+
if [[ $(is_swift_lto_enabled) == "TRUE" ]]; then
584602
if [[ $(cmake_needs_to_specify_standard_computed_defaults) = "TRUE" ]]; then
585603
swift_cmake_options+=(
586604
"-DCMAKE_C_STANDARD_COMPUTED_DEFAULT=AppleClang"
@@ -1442,7 +1460,7 @@ function llvm_c_flags() {
14421460
if [[ $(is_cmake_release_build_type "${LLVM_BUILD_TYPE}") ]] ; then
14431461
echo -n " -fno-stack-protector"
14441462
fi
1445-
if [[ $(true_false "${LLVM_ENABLE_LTO}") = "TRUE" ]] ; then
1463+
if [[ $(is_llvm_lto_enabled) == "TRUE" ]] ; then
14461464
echo -n " -gline-tables-only"
14471465
fi
14481466
}
@@ -1761,7 +1779,7 @@ for host in "${ALL_HOSTS[@]}"; do
17611779
-DLLVM_TARGETS_TO_BUILD="${LLVM_TARGETS_TO_BUILD}"
17621780
-DLLVM_INCLUDE_TESTS:BOOL=$(true_false "${SOURCE_TREE_INCLUDES_TESTS}")
17631781
-DLLVM_INCLUDE_DOCS:BOOL=TRUE
1764-
-DLLVM_ENABLE_LTO=$(true_false "${LLVM_ENABLE_LTO}")
1782+
-DLLVM_ENABLE_LTO:STRING="${LLVM_ENABLE_LTO}"
17651783
"${llvm_cmake_options[@]}"
17661784
)
17671785
if [[ $(is_cross_tools_host ${host}) ]] ; then
@@ -1876,7 +1894,7 @@ for host in "${ALL_HOSTS[@]}"; do
18761894
-DSWIFT_INCLUDE_TESTS:BOOL=$(true_false "${build_tests_this_time}")
18771895
-DSWIFT_INSTALL_COMPONENTS:STRING="${SWIFT_INSTALL_COMPONENTS}"
18781896
-DSWIFT_EMBED_BITCODE_SECTION:BOOL=$(true_false "${EMBED_BITCODE_SECTION}")
1879-
-DSWIFT_TOOLS_ENABLE_LTO:BOOL=$(true_false "${SWIFT_TOOLS_ENABLE_LTO}")
1897+
-DSWIFT_TOOLS_ENABLE_LTO:STRING="${SWIFT_TOOLS_ENABLE_LTO}"
18801898
-DSWIFT_BUILD_RUNTIME_WITH_HOST_COMPILER:BOOL=$(true_false "${BUILD_RUNTIME_WITH_HOST_COMPILER}")
18811899
"${swift_cmake_options[@]}"
18821900
)
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
#!/usr/bin/env bash
2+
3+
# This test makes sure that if lto is enabled and that all host libraries
4+
# contain only bitcode.
5+
#
6+
# *NOTE* This will not trigger for embedded bitcode sections since to file those
7+
# are still mach-o files and come up as such.
8+
9+
set -e
10+
set -u
11+
12+
# REQUIRES: lto
13+
# REQUIRES: macosx
14+
# RUN: %s %swift_obj_root %t
15+
16+
function check_thin_archive_for_bitcode() {
17+
set -e
18+
set -u
19+
set -o pipefail
20+
21+
pushd . 1>/dev/null
22+
23+
local BASE_TEMPDIR=$1
24+
local ARCHIVE=$2
25+
26+
local LIB_NAME=$(basename ${ARCHIVE})
27+
local LIB_ARCH=$(basename $(dirname ${ARCHIVE}))
28+
local LIB_PLATFORM=$(basename $(dirname $(dirname ${ARCHIVE})))
29+
30+
LIB_TEMP_DIR="${BASE_TEMPDIR}/${LIB_PLATFORM}-${LIB_ARCH}-${LIB_NAME}"
31+
mkdir -p "${LIB_TEMP_DIR}"
32+
cd "${LIB_TEMP_DIR}"
33+
ar -x ${ARCHIVE}
34+
if [[ -n "$(find ./ -iname '*.o' -exec file {} \; | grep bit-code)" ]]; then
35+
echo "Found bitcode file in thin archive: ${ARCHIVE}"
36+
else
37+
echo "No bitcode in thin archive: ${ARCHIVE}"
38+
exit 1
39+
fi
40+
popd 1>/dev/null
41+
42+
set +o pipefail
43+
set +u
44+
set +e
45+
}
46+
export -f check_thin_archive_for_bitcode
47+
48+
function check_thick_archive_for_bitcode() {
49+
set -e
50+
set -u
51+
set -o pipefail
52+
53+
pushd . 1>/dev/null
54+
55+
local BASE_TEMPDIR=$1
56+
local ARCHIVE=$2
57+
58+
local LIB_NAME=$(basename ${ARCHIVE})
59+
local LIB_PLATFORM=$(basename $(dirname ${ARCHIVE}))
60+
61+
LIB_TEMP_DIR="${BASE_TEMPDIR}/${LIB_PLATFORM}-thick-${LIB_NAME}"
62+
LIB_ARCHIVE_DIR="${LIB_TEMP_DIR}/archive"
63+
LIB_OBJECT_DIR="${LIB_TEMP_DIR}/object"
64+
65+
mkdir -p "${LIB_TEMP_DIR}"
66+
mkdir -p "${LIB_ARCHIVE_DIR}"
67+
mkdir -p "${LIB_OBJECT_DIR}"
68+
69+
ARCHS=( $(lipo -info ${ARCHIVE} | cut -f 3 -d ":" ) )
70+
cd ${LIB_OBJECT_DIR}
71+
for arch in "${ARCHS[@]}"; do
72+
pushd . 1>/dev/null
73+
local THIN_ARCHIVE="${LIB_NAME}.${arch}"
74+
lipo -thin "${arch}" -output "${LIB_ARCHIVE_DIR}/${THIN_ARCHIVE}" "${ARCHIVE}"
75+
mkdir ${arch}
76+
cd ${arch}
77+
ar -x "${LIB_ARCHIVE_DIR}/${THIN_ARCHIVE}"
78+
79+
if [[ -n "$(find ./ -iname '*.o' -exec file {} \; | grep bit-code)" ]]; then
80+
echo "Found bitcode file in thin archive: ${THIN_ARCHIVE}. Taken from thick archive: ${ARCHIVE}"
81+
else
82+
echo "No bitcode in thin archive: ${THIN_ARCHIVE}. Taken from thick archive: ${ARCHIVE}"
83+
exit 1
84+
fi
85+
86+
popd 1>/dev/null
87+
done
88+
popd 1>/dev/null
89+
90+
set +o pipefail
91+
set +u
92+
set +e
93+
}
94+
export -f check_thick_archive_for_bitcode
95+
96+
OBJROOT=$(cd ${1} && pwd)
97+
TEMPDIR=${2}
98+
99+
rm -rf $TEMPDIR
100+
mkdir -p $TEMPDIR
101+
102+
THIN_ARCHIVES=( \
103+
$(find ${OBJROOT}/lib -depth 1 -iname '*.a' -exec lipo -info {} \; | grep "Non-fat file" | cut -f 3 -d " ") \
104+
)
105+
106+
if [[ ${#THIN_ARCHIVES[@]} -gt 0 ]]; then
107+
echo "${THIN_ARCHIVES[@]}" | xargs -n 1 -P 8 bash -c "check_thin_archive_for_bitcode \"${TEMPDIR}\" \${1}" --
108+
fi
109+
110+
THICK_ARCHIVES=( \
111+
$(find ${OBJROOT}/lib -depth 1 -iname '*.a' -exec lipo -info {} \; | grep "Architectures in the fat file" | cut -f 6 -d " ") \
112+
)
113+
114+
if [[ ${#THICK_ARCHIVES[@]} -gt 0 ]]; then
115+
echo "${THICK_ARCHIVES[@]}" | xargs -n 1 -P 8 bash -c "check_thick_archive_for_bitcode \"${TEMPDIR}\" \${1}" --
116+
fi
117+
118+
set +o pipefail
119+
set +u
120+
set +e
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env bash
2+
3+
# This test makes sure that if lto is enabled and that all host libraries
4+
# contain only bitcode.
5+
#
6+
# *NOTE* This will not trigger for embedded bitcode sections since to file those
7+
# are still mach-o files and come up as such.
8+
9+
set -e
10+
set -u
11+
12+
# REQUIRES: lto
13+
# RUN: %s %swift_obj_root
14+
15+
if [[ -n "$(find $1/lib -iname '*.cpp.o' -type f -exec file {} \; | grep -v bit-code)" ]]; then
16+
echo "Found a ./lib non-bitcode object file!"
17+
exit 1
18+
else
19+
echo "All ./lib object files are bit-code files!"
20+
fi
21+
22+
if [[ -n "$(find $1/unittests -iname '*.cpp.o' -type f -exec file {} \; | grep -v bit-code)" ]]; then
23+
echo "Found a ./unittests non-bitcode object file!"
24+
exit 1
25+
else
26+
echo "All ./unittests object files are bit-code files!"
27+
fi
28+
29+
set +u
30+
set +e

0 commit comments

Comments
 (0)