75 changes: 42 additions & 33 deletions libcxx/modules/std.cppm.in
Original file line number Diff line number Diff line change
Expand Up @@ -168,39 +168,48 @@ module;
#include <version>

// *** Headers not yet available ***
#if __has_include(<debugging>)
# error "please update the header information for <debugging> in headers_not_available in utils/libcxx/header_information.py"
#endif // __has_include(<debugging>)
#if __has_include(<flat_map>)
# error "please update the header information for <flat_map> in headers_not_available in utils/libcxx/header_information.py"
#endif // __has_include(<flat_map>)
#if __has_include(<flat_set>)
# error "please update the header information for <flat_set> in headers_not_available in utils/libcxx/header_information.py"
#endif // __has_include(<flat_set>)
#if __has_include(<generator>)
# error "please update the header information for <generator> in headers_not_available in utils/libcxx/header_information.py"
#endif // __has_include(<generator>)
#if __has_include(<hazard_pointer>)
# error "please update the header information for <hazard_pointer> in headers_not_available in utils/libcxx/header_information.py"
#endif // __has_include(<hazard_pointer>)
#if __has_include(<linalg>)
# error "please update the header information for <linalg> in headers_not_available in utils/libcxx/header_information.py"
#endif // __has_include(<linalg>)
#if __has_include(<rcu>)
# error "please update the header information for <rcu> in headers_not_available in utils/libcxx/header_information.py"
#endif // __has_include(<rcu>)
#if __has_include(<spanstream>)
# error "please update the header information for <spanstream> in headers_not_available in utils/libcxx/header_information.py"
#endif // __has_include(<spanstream>)
#if __has_include(<stacktrace>)
# error "please update the header information for <stacktrace> in headers_not_available in utils/libcxx/header_information.py"
#endif // __has_include(<stacktrace>)
#if __has_include(<stdfloat>)
# error "please update the header information for <stdfloat> in headers_not_available in utils/libcxx/header_information.py"
#endif // __has_include(<stdfloat>)
#if __has_include(<text_encoding>)
# error "please update the header information for <text_encoding> in headers_not_available in utils/libcxx/header_information.py"
#endif // __has_include(<text_encoding>)
//
// This validation is mainly to aid libc++ developers to add modules for new
// headers. On Windows the Windows SDK can be in the include path. This SDK
// contains the MSVC STL headers. This may give false positives when MSVC STL
// provides a header libc++ has not implemented yet. Therefore this validation
// is not done on Windows.
//
#ifndef _WIN32
# if __has_include(<debugging>)
# error "please update the header information for <debugging> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<debugging>)
# if __has_include(<flat_map>)
# error "please update the header information for <flat_map> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<flat_map>)
# if __has_include(<flat_set>)
# error "please update the header information for <flat_set> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<flat_set>)
# if __has_include(<generator>)
# error "please update the header information for <generator> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<generator>)
# if __has_include(<hazard_pointer>)
# error "please update the header information for <hazard_pointer> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<hazard_pointer>)
# if __has_include(<linalg>)
# error "please update the header information for <linalg> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<linalg>)
# if __has_include(<rcu>)
# error "please update the header information for <rcu> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<rcu>)
# if __has_include(<spanstream>)
# error "please update the header information for <spanstream> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<spanstream>)
# if __has_include(<stacktrace>)
# error "please update the header information for <stacktrace> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<stacktrace>)
# if __has_include(<stdfloat>)
# error "please update the header information for <stdfloat> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<stdfloat>)
# if __has_include(<text_encoding>)
# error "please update the header information for <text_encoding> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<text_encoding>)
#endif // _WIN32

export module std;

Expand Down
4 changes: 2 additions & 2 deletions libcxx/test/configs/apple-libc++-backdeployment.cfg.in
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ config.substitutions.append(('%{flags}',
'-isysroot {}'.format('@CMAKE_OSX_SYSROOT@') if '@CMAKE_OSX_SYSROOT@' else ''
))
config.substitutions.append(('%{compile_flags}',
'-nostdinc++ -I %{include} -I %{libcxx}/test/support'
'-nostdinc++ -I %{include-dir} -I %{libcxx-dir}/test/support'
))
config.substitutions.append(('%{link_flags}',
'-nostdlib++ -L %{lib} -lc++'
'-nostdlib++ -L %{lib-dir} -lc++'
))
config.substitutions.append(('%{exec}',
'%{executor} --execdir %T --env DYLD_LIBRARY_PATH="%{cxx-runtime-root}:%{abi-runtime-root}:%{unwind-runtime-root}" -- '
Expand Down
6 changes: 3 additions & 3 deletions libcxx/test/configs/apple-libc++-shared.cfg.in
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ config.substitutions.append(('%{flags}',
'-isysroot {}'.format('@CMAKE_OSX_SYSROOT@') if '@CMAKE_OSX_SYSROOT@' else ''
))
config.substitutions.append(('%{compile_flags}',
'-nostdinc++ -I %{include} -I %{libcxx}/test/support'
'-nostdinc++ -I %{include-dir} -I %{libcxx-dir}/test/support'
))
config.substitutions.append(('%{link_flags}',
'-nostdlib++ -L %{lib} -lc++'
'-nostdlib++ -L %{lib-dir} -lc++'
))
config.substitutions.append(('%{exec}',
'%{executor} --execdir %T --env DYLD_LIBRARY_PATH=%{lib} -- '
'%{executor} --execdir %T --env DYLD_LIBRARY_PATH=%{lib-dir} -- '
))

config.stdlib = 'apple-libc++'
Expand Down
4 changes: 2 additions & 2 deletions libcxx/test/configs/armv7m-picolibc-libc++.cfg.in
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ libc_linker_script = '@CMAKE_INSTALL_PREFIX@/lib/picolibcpp.ld'
config.substitutions.append(('%{flags}', '--sysroot=@CMAKE_INSTALL_PREFIX@'))

config.substitutions.append(('%{compile_flags}',
'-nostdinc++ -I %{include} -I %{target-include} -I %{libcxx}/test/support'
'-nostdinc++ -I %{include-dir} -I %{target-include-dir} -I %{libcxx-dir}/test/support'

# Disable warnings in cxx_atomic_impl.h:
# "large atomic operation may incur significant performance penalty; the
Expand All @@ -17,7 +17,7 @@ config.substitutions.append(('%{compile_flags}',
' -include picolibc.h'
))
config.substitutions.append(('%{link_flags}',
'-nostdlib -nostdlib++ -L %{lib} -lc++ -lc++abi'
'-nostdlib -nostdlib++ -L %{lib-dir} -lc++ -lc++abi'
' -lc -lm -lclang_rt.builtins -lsemihost -lcrt0-semihost' +
' -T {}'.format(libc_linker_script) +
' -Wl,--defsym=__flash=0x0'
Expand Down
12 changes: 6 additions & 6 deletions libcxx/test/configs/cmake-bridge.cfg.in
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ config.test_exec_root = os.path.join('@CMAKE_BINARY_DIR@', 'test')
# Add substitutions for bootstrapping the test suite configuration
import shlex
config.substitutions.append(('%{cxx}', shlex.quote('@CMAKE_CXX_COMPILER@')))
config.substitutions.append(('%{libcxx}', '@LIBCXX_SOURCE_DIR@'))
config.substitutions.append(('%{include}', '@LIBCXX_GENERATED_INCLUDE_DIR@'))
config.substitutions.append(('%{target-include}', '@LIBCXX_GENERATED_INCLUDE_TARGET_DIR@'))
config.substitutions.append(('%{lib}', '@LIBCXX_LIBRARY_DIR@'))
config.substitutions.append(('%{module}', '@LIBCXX_GENERATED_MODULE_DIR@'))
config.substitutions.append(('%{test-tools}', '@LIBCXX_TEST_TOOLS_PATH@'))
config.substitutions.append(('%{libcxx-dir}', '@LIBCXX_SOURCE_DIR@'))
config.substitutions.append(('%{include-dir}', '@LIBCXX_GENERATED_INCLUDE_DIR@'))
config.substitutions.append(('%{target-include-dir}', '@LIBCXX_GENERATED_INCLUDE_TARGET_DIR@'))
config.substitutions.append(('%{lib-dir}', '@LIBCXX_LIBRARY_DIR@'))
config.substitutions.append(('%{module-dir}', '@LIBCXX_GENERATED_MODULE_DIR@'))
config.substitutions.append(('%{test-tools-dir}', '@LIBCXX_TEST_TOOLS_PATH@'))
6 changes: 3 additions & 3 deletions libcxx/test/configs/ibm-libc++-shared.cfg.in
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ if lit.util.isAIXTriple(config.target_triple):

config.substitutions.append(('%{flags}', '-pthread'))
config.substitutions.append(('%{compile_flags}',
'-nostdinc++ -D__LIBC_NO_CPP_MATH_OVERLOADS__ -I %{include} -I %{libcxx}/test/support'
'-nostdinc++ -D__LIBC_NO_CPP_MATH_OVERLOADS__ -I %{include-dir} -I %{libcxx-dir}/test/support'
))
config.substitutions.append(('%{link_flags}',
'-nostdlib++ -L %{lib} -lc++ -lc++abi -latomic -Wl,-bbigtoc'
'-nostdlib++ -L %{lib-dir} -lc++ -lc++abi -latomic -Wl,-bbigtoc'
))
config.substitutions.append(('%{exec}',
'%{executor} --execdir %T --env LIBPATH=%{lib} -- '
'%{executor} --execdir %T --env LIBPATH=%{lib-dir} -- '
))

# LIBCXX-AIX-FIXME is the feature name used to XFAIL the
Expand Down
4 changes: 2 additions & 2 deletions libcxx/test/configs/llvm-libc++-android-ndk.cfg.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ config.substitutions.append(('%{flags}',
'--sysroot @CMAKE_SYSROOT@' if '@CMAKE_SYSROOT@' else ''
))

compile_flags = '-nostdinc++ -I %{include} -I %{target-include} -I %{libcxx}/test/support'
compile_flags = '-nostdinc++ -I %{include-dir} -I %{target-include-dir} -I %{libcxx-dir}/test/support'
if re.match(r'i686-linux-android(21|22|23)$', config.target_triple):
# 32-bit x86 Android has a bug where the stack is sometimes misaligned.
# The problem appears limited to versions before Android N (API 24) and only
Expand All @@ -31,7 +31,7 @@ config.substitutions.append(('%{compile_flags}', compile_flags))
# libc++_shared.so because older Bionic dynamic loaders don't support rpath
# lookup.
config.substitutions.append(('%{link_flags}',
'-nostdlib++ -L %{lib} -lc++_shared'
'-nostdlib++ -L %{lib-dir} -lc++_shared'
))
config.substitutions.append(('%{exec}',
'%{executor}' +
Expand Down
6 changes: 3 additions & 3 deletions libcxx/test/configs/llvm-libc++-mingw.cfg.in
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ lit_config.load_config(config, '@CMAKE_CURRENT_BINARY_DIR@/cmake-bridge.cfg')

config.substitutions.append(('%{flags}', ''))
config.substitutions.append(('%{compile_flags}',
'-nostdinc++ -I %{include} -I %{target-include} -I %{libcxx}/test/support'
'-nostdinc++ -I %{include-dir} -I %{target-include-dir} -I %{libcxx-dir}/test/support'
))
config.substitutions.append(('%{link_flags}',
'-nostdlib++ -L %{lib} -lc++'
'-nostdlib++ -L %{lib-dir} -lc++'
))
config.substitutions.append(('%{exec}',
'%{executor} --execdir %T --prepend_env PATH=%{lib} -- '
'%{executor} --execdir %T --prepend_env PATH=%{lib-dir} -- '
))

import os, site
Expand Down
6 changes: 3 additions & 3 deletions libcxx/test/configs/llvm-libc++-shared-clangcl.cfg.in
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ lit_config.load_config(config, '@CMAKE_CURRENT_BINARY_DIR@/cmake-bridge.cfg')

config.substitutions.append(('%{flags}', '--driver-mode=g++'))
config.substitutions.append(('%{compile_flags}',
'-fms-runtime-lib=' + config.fms_runtime_lib + ' -nostdinc++ -I %{include} -I %{target-include} -I %{libcxx}/test/support -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_STDIO_ISO_WIDE_SPECIFIERS -DNOMINMAX' + config.dbg_include
'-fms-runtime-lib=' + config.fms_runtime_lib + ' -nostdinc++ -I %{include-dir} -I %{target-include-dir} -I %{libcxx-dir}/test/support -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_STDIO_ISO_WIDE_SPECIFIERS -DNOMINMAX' + config.dbg_include
))
config.substitutions.append(('%{link_flags}',
'-nostdlib -L %{lib} -lc++ -l' + config.cxx_lib
'-nostdlib -L %{lib-dir} -lc++ -l' + config.cxx_lib
))
config.substitutions.append(('%{exec}',
'%{executor} --execdir %T --prepend_env PATH=%{lib} -- '
'%{executor} --execdir %T --prepend_env PATH=%{lib-dir} -- '
))

import os, site
Expand Down
4 changes: 2 additions & 2 deletions libcxx/test/configs/llvm-libc++-shared-gcc.cfg.in
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ lit_config.load_config(config, '@CMAKE_CURRENT_BINARY_DIR@/cmake-bridge.cfg')

config.substitutions.append(('%{flags}', '-pthread'))
config.substitutions.append(('%{compile_flags}',
'-nostdinc++ -I %{include} -I %{target-include} -I %{libcxx}/test/support'
'-nostdinc++ -I %{include-dir} -I %{target-include-dir} -I %{libcxx-dir}/test/support'
))
config.substitutions.append(('%{link_flags}',
'-nostdlib++ -L %{lib} -Wl,-rpath,%{lib} -lc++ -lm'
'-nostdlib++ -L %{lib-dir} -Wl,-rpath,%{lib-dir} -lc++ -lm'
))
config.substitutions.append(('%{exec}',
'%{executor} --execdir %T -- '
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ lit_config.load_config(config, '@CMAKE_CURRENT_BINARY_DIR@/cmake-bridge.cfg')

config.substitutions.append(('%{flags}', '--driver-mode=g++'))
config.substitutions.append(('%{compile_flags}',
'-fms-runtime-lib=' + config.fms_runtime_lib + ' -nostdinc++ -I %{include} -I %{target-include} -I %{libcxx}/test/support -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_STDIO_ISO_WIDE_SPECIFIERS -DNOMINMAX -D_HAS_EXCEPTIONS=0' + config.dbg_include
'-fms-runtime-lib=' + config.fms_runtime_lib + ' -nostdinc++ -I %{include-dir} -I %{target-include-dir} -I %{libcxx-dir}/test/support -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_STDIO_ISO_WIDE_SPECIFIERS -DNOMINMAX -D_HAS_EXCEPTIONS=0' + config.dbg_include
))
config.substitutions.append(('%{link_flags}',
'-nostdlib -L %{lib} -lc++ -l' + config.cxx_lib
'-nostdlib -L %{lib-dir} -lc++ -l' + config.cxx_lib
))
config.substitutions.append(('%{exec}',
'%{executor} --execdir %T --prepend_env PATH=%{lib} -- '
'%{executor} --execdir %T --prepend_env PATH=%{lib-dir} -- '
))

import os, site
Expand Down
4 changes: 2 additions & 2 deletions libcxx/test/configs/llvm-libc++-shared.cfg.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ config.substitutions.append(('%{flags}',
'-pthread' + (' -isysroot {}'.format('@CMAKE_OSX_SYSROOT@') if '@CMAKE_OSX_SYSROOT@' else '')
))
config.substitutions.append(('%{compile_flags}',
'-nostdinc++ -I %{include} -I %{target-include} -I %{libcxx}/test/support'
'-nostdinc++ -I %{include-dir} -I %{target-include-dir} -I %{libcxx-dir}/test/support'
))
config.substitutions.append(('%{link_flags}',
'-nostdlib++ -L %{lib} -Wl,-rpath,%{lib} -lc++'
'-nostdlib++ -L %{lib-dir} -Wl,-rpath,%{lib-dir} -lc++'
))
config.substitutions.append(('%{exec}',
'%{executor} --execdir %T -- '
Expand Down
4 changes: 2 additions & 2 deletions libcxx/test/configs/llvm-libc++-static-clangcl.cfg.in
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ lit_config.load_config(config, '@CMAKE_CURRENT_BINARY_DIR@/cmake-bridge.cfg')

config.substitutions.append(('%{flags}', '--driver-mode=g++'))
config.substitutions.append(('%{compile_flags}',
'-fms-runtime-lib=' + config.fms_runtime_lib + ' -nostdinc++ -I %{include} -I %{target-include} -I %{libcxx}/test/support -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_STDIO_ISO_WIDE_SPECIFIERS -DNOMINMAX' + config.dbg_include
'-fms-runtime-lib=' + config.fms_runtime_lib + ' -nostdinc++ -I %{include-dir} -I %{target-include-dir} -I %{libcxx-dir}/test/support -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_STDIO_ISO_WIDE_SPECIFIERS -DNOMINMAX' + config.dbg_include
))
config.substitutions.append(('%{link_flags}',
'-nostdlib -L %{lib} -llibc++ -l' + config.cxx_lib
'-nostdlib -L %{lib-dir} -llibc++ -l' + config.cxx_lib
))
config.substitutions.append(('%{exec}',
'%{executor} --execdir %T -- '
Expand Down
4 changes: 2 additions & 2 deletions libcxx/test/configs/llvm-libc++-static.cfg.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ config.substitutions.append(('%{flags}',
'-pthread' + (' -isysroot {}'.format('@CMAKE_OSX_SYSROOT@') if '@CMAKE_OSX_SYSROOT@' else '')
))
config.substitutions.append(('%{compile_flags}',
'-nostdinc++ -I %{include} -I %{target-include} -I %{libcxx}/test/support'
'-nostdinc++ -I %{include-dir} -I %{target-include-dir} -I %{libcxx-dir}/test/support'
))
config.substitutions.append(('%{link_flags}',
'-nostdlib++ -L %{lib} -lc++ -lc++abi'
'-nostdlib++ -L %{lib-dir} -lc++ -lc++abi'
))
config.substitutions.append(('%{exec}',
'%{executor} --execdir %T -- '
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# is required for users to be able to include any public header and then override
# the function using a strong definition.

# RUN: %{python} %s %{libcxx}/utils
# RUN: %{python} %s %{libcxx-dir}/utils

import sys
sys.path.append(sys.argv[1])
Expand Down
2 changes: 1 addition & 1 deletion libcxx/test/libcxx/clang_modules_include.gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# This is important notably because the LLDB data formatters use
# libc++ headers with modules enabled.

# RUN: %{python} %s %{libcxx}/utils
# RUN: %{python} %s %{libcxx-dir}/utils

import sys
sys.path.append(sys.argv[1])
Expand Down
6 changes: 3 additions & 3 deletions libcxx/test/libcxx/clang_tidy.gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

# Run our custom libc++ clang-tidy checks on all public headers.

# RUN: %{python} %s %{libcxx}/utils
# RUN: %{python} %s %{libcxx-dir}/utils

import sys
sys.path.append(sys.argv[1])
Expand All @@ -27,8 +27,8 @@
{lit_header_restrictions.get(header, '')}
// TODO: run clang-tidy with modules enabled once they are supported
// RUN{BLOCKLIT}: %{{clang-tidy}} %s --warnings-as-errors=* -header-filter=.* --checks='-*,libcpp-*' --load=%{{test-tools}}/clang_tidy_checks/libcxx-tidy.plugin -- %{{compile_flags}} -fno-modules
// RUN{BLOCKLIT}: %{{clang-tidy}} %s --warnings-as-errors=* -header-filter=.* --config-file=%{{libcxx}}/.clang-tidy -- -Wweak-vtables %{{compile_flags}} -fno-modules
// RUN{BLOCKLIT}: %{{clang-tidy}} %s --warnings-as-errors=* -header-filter=.* --checks='-*,libcpp-*' --load=%{{test-tools-dir}}/clang_tidy_checks/libcxx-tidy.plugin -- %{{compile_flags}} -fno-modules
// RUN{BLOCKLIT}: %{{clang-tidy}} %s --warnings-as-errors=* -header-filter=.* --config-file=%{{libcxx-dir}}/.clang-tidy -- -Wweak-vtables %{{compile_flags}} -fno-modules
#include <{header}>
""")
2 changes: 1 addition & 1 deletion libcxx/test/libcxx/double_include.gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

# Test that we can include each header in two TU's and link them together.

# RUN: %{python} %s %{libcxx}/utils
# RUN: %{python} %s %{libcxx-dir}/utils

import sys
sys.path.append(sys.argv[1])
Expand Down
2 changes: 1 addition & 1 deletion libcxx/test/libcxx/header_inclusions.gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# Test that all headers include all the other headers they're supposed to, as
# prescribed by the Standard.

# RUN: %{python} %s %{libcxx}/utils
# RUN: %{python} %s %{libcxx-dir}/utils

import sys
sys.path.append(sys.argv[1])
Expand Down
2 changes: 1 addition & 1 deletion libcxx/test/libcxx/headers_in_modulemap.sh.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# RUN: %{python} %s %{libcxx}/utils %{include}
# RUN: %{python} %s %{libcxx-dir}/utils %{include-dir}

import sys

Expand Down
2 changes: 1 addition & 1 deletion libcxx/test/libcxx/libcpp_version.gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

# Test that all headers define the _LIBCPP_VERSION macro.

# RUN: %{python} %s %{libcxx}/utils
# RUN: %{python} %s %{libcxx-dir}/utils

import sys
sys.path.append(sys.argv[1])
Expand Down
6 changes: 3 additions & 3 deletions libcxx/test/libcxx/module_std.gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# to be one monolitic test. Since the test doesn't take very long it's
# not a huge issue.

# RUN: %{python} %s %{libcxx}/utils
# RUN: %{python} %s %{libcxx-dir}/utils

import sys

Expand All @@ -25,9 +25,9 @@

generator = module_test_generator(
"%t",
"%{module}",
"%{module-dir}",
"%{clang-tidy}",
"%{test-tools}/clang_tidy_checks/libcxx-tidy.plugin",
"%{test-tools-dir}/clang_tidy_checks/libcxx-tidy.plugin",
"%{cxx}",
"%{flags} %{compile_flags}",
"std",
Expand Down
6 changes: 3 additions & 3 deletions libcxx/test/libcxx/module_std_compat.gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# to be one monolitic test. Since the test doesn't take very long it's
# not a huge issue.

# RUN: %{python} %s %{libcxx}/utils
# RUN: %{python} %s %{libcxx-dir}/utils

import sys

Expand All @@ -26,9 +26,9 @@

generator = module_test_generator(
"%t",
"%{module}",
"%{module-dir}",
"%{clang-tidy}",
"%{test-tools}/clang_tidy_checks/libcxx-tidy.plugin",
"%{test-tools-dir}/clang_tidy_checks/libcxx-tidy.plugin",
"%{cxx}",
"%{flags} %{compile_flags}",
"std.compat",
Expand Down
2 changes: 1 addition & 1 deletion libcxx/test/libcxx/no_assert_include.gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# Ensure that none of the standard C++ headers implicitly include cassert or
# assert.h (because assert() is implemented as a macro).

# RUN: %{python} %s %{libcxx}/utils
# RUN: %{python} %s %{libcxx-dir}/utils

import sys
sys.path.append(sys.argv[1])
Expand Down
2 changes: 1 addition & 1 deletion libcxx/test/libcxx/system_reserved_names.gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# alphabetic macros. Also ensure that we don't swallow the definition of user
# provided macros (in other words, ensure that we push/pop correctly everywhere).

# RUN: %{python} %s %{libcxx}/utils
# RUN: %{python} %s %{libcxx-dir}/utils

import sys
sys.path.append(sys.argv[1])
Expand Down
8 changes: 4 additions & 4 deletions libcxx/test/libcxx/transitive_includes.gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# forever, however we do try to group removals for a couple of releases
# to avoid breaking users at every release.

# RUN: %{python} %s %{libcxx}/utils
# RUN: %{python} %s %{libcxx-dir}/utils

import sys
sys.path.append(sys.argv[1])
Expand Down Expand Up @@ -48,7 +48,7 @@
all_traces.append(f'%t/trace-includes.{normalized_header}.txt')

print(f"""\
// RUN{BLOCKLIT}: %{{python}} %{{libcxx}}/test/libcxx/transitive_includes_to_csv.py {' '.join(all_traces)} > %{{libcxx}}/test/libcxx/transitive_includes/%{{cxx_std}}.csv
// RUN{BLOCKLIT}: %{{python}} %{{libcxx-dir}}/test/libcxx/transitive_includes_to_csv.py {' '.join(all_traces)} > %{{libcxx-dir}}/test/libcxx/transitive_includes/%{{cxx_std}}.csv
""")

else:
Expand Down Expand Up @@ -83,8 +83,8 @@
// RUN{BLOCKLIT}: mkdir %t
// RUN{BLOCKLIT}: %{{cxx}} %s %{{flags}} %{{compile_flags}} --trace-includes -fshow-skipped-includes --preprocess > /dev/null 2> %t/trace-includes.txt
// RUN{BLOCKLIT}: %{{python}} %{{libcxx}}/test/libcxx/transitive_includes_to_csv.py %t/trace-includes.txt > %t/actual_transitive_includes.csv
// RUN{BLOCKLIT}: cat %{{libcxx}}/test/libcxx/transitive_includes/%{{cxx_std}}.csv | awk '/^{escaped_header} / {{ print }}' > %t/expected_transitive_includes.csv
// RUN{BLOCKLIT}: %{{python}} %{{libcxx-dir}}/test/libcxx/transitive_includes_to_csv.py %t/trace-includes.txt > %t/actual_transitive_includes.csv
// RUN{BLOCKLIT}: cat %{{libcxx-dir}}/test/libcxx/transitive_includes/%{{cxx_std}}.csv | awk '/^{escaped_header} / {{ print }}' > %t/expected_transitive_includes.csv
// RUN{BLOCKLIT}: diff -w %t/expected_transitive_includes.csv %t/actual_transitive_includes.csv
#include <{header}>
""")
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ void test() {
e.transform_error(return_unexpected<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
// expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
// expected-error-re@*:* {{static assertion failed {{.*}}A program that instantiates expected<T, E> with a E that is not a valid argument for unexpected<E> is ill-formed}}
// expected-error-re@*:* {{call to deleted constructor of {{.*}}}}
// expected-error-re@*:* 0-1 {{call to deleted constructor of {{.*}}}}
// expected-error-re@*:* {{union member {{.*}} has reference type {{.*}}}}

e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
Expand Down
18 changes: 9 additions & 9 deletions libcxx/test/libcxx/vendor/apple/system-install-properties.sh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@

// Make sure we install the libc++ headers in the right location.
//
// RUN: stat "%{include}/__config"
// RUN: stat "%{include-dir}/__config"

// Make sure we install libc++.1.dylib and libc++experimental.a in the right location.
//
// RUN: stat "%{lib}/libc++.1.dylib"
// RUN: stat "%{lib}/libc++experimental.a"
// RUN: stat "%{lib-dir}/libc++.1.dylib"
// RUN: stat "%{lib-dir}/libc++experimental.a"

// Make sure we install a symlink from libc++.dylib to libc++.1.dylib.
//
// RUN: stat "%{lib}/libc++.dylib"
// RUN: readlink "%{lib}/libc++.dylib" | grep "libc++.1.dylib"
// RUN: stat "%{lib-dir}/libc++.dylib"
// RUN: readlink "%{lib-dir}/libc++.dylib" | grep "libc++.1.dylib"

// Make sure the install_name is /usr/lib.
//
Expand All @@ -34,15 +34,15 @@
//
// TODO: We currently don't do that correctly in the CMake build.
//
// XRUNX: otool -L "%{lib}/libc++.1.dylib" | grep '/usr/lib/libc++.1.dylib'
// XRUNX: ! otool -l "%{lib}/libc++.1.dylib" | grep -E "LC_RPATH|@loader_path|@rpath"
// XRUNX: otool -L "%{lib-dir}/libc++.1.dylib" | grep '/usr/lib/libc++.1.dylib'
// XRUNX: ! otool -l "%{lib-dir}/libc++.1.dylib" | grep -E "LC_RPATH|@loader_path|@rpath"

// Make sure the compatibility_version of libc++ is 1.0.0.
// Failure to respect this can result in applications not being able to find libc++
// when they are loaded by dyld, if the compatibility version was bumped.
//
// RUN: otool -L "%{lib}/libc++.1.dylib" | grep "libc++.1.dylib" | grep "compatibility version 1.0.0"
// RUN: otool -L "%{lib-dir}/libc++.1.dylib" | grep "libc++.1.dylib" | grep "compatibility version 1.0.0"

// Make sure we use the libdispatch backend for the PSTL.
//
// RUN: grep "%{include}/__config_site" -e '#define _LIBCPP_PSTL_CPU_BACKEND_LIBDISPATCH'
// RUN: grep "%{include-dir}/__config_site" -e '#define _LIBCPP_PSTL_CPU_BACKEND_LIBDISPATCH'
4 changes: 2 additions & 2 deletions libcxx/test/libcxx/vendor/clang-cl/static-lib-exports.sh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
// This file checks that the built static libraries don't contain dllexport
// directives in clang-cl builds.

// RUN: llvm-readobj --coff-directives "%{lib}/libc++.lib" | not grep -i "export:" > /dev/null
// RUN: llvm-readobj --coff-directives "%{lib-dir}/libc++.lib" | not grep -i "export:" > /dev/null

// RUN: llvm-readobj --coff-directives "%{lib}/libc++experimental.lib" | not grep -i "export:" > /dev/null
// RUN: llvm-readobj --coff-directives "%{lib-dir}/libc++experimental.lib" | not grep -i "export:" > /dev/null
4 changes: 2 additions & 2 deletions libcxx/test/libcxx/vendor/mingw/static-lib-exports.sh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
// This file checks that the built static libraries don't contain dllexport
// directives in MinGW builds.

// RUN: llvm-readobj --coff-directives "%{lib}/libc++.a" | not grep -i "export:" > /dev/null
// RUN: llvm-readobj --coff-directives "%{lib-dir}/libc++.a" | not grep -i "export:" > /dev/null

// RUN: llvm-readobj --coff-directives "%{lib}/libc++experimental.a" | not grep -i "export:" > /dev/null
// RUN: llvm-readobj --coff-directives "%{lib-dir}/libc++experimental.a" | not grep -i "export:" > /dev/null
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ constexpr bool test() {
{
std::from_chars_result value{nullptr, std::errc{}};
assert(bool(value) == true);
static_assert(noexcept(bool(true)) == true);
static_assert(noexcept(bool(value)) == true);
}
// False
{
std::from_chars_result value{nullptr, std::errc::value_too_large};
assert(bool(value) == false);
static_assert(noexcept(bool(true)) == true);
static_assert(noexcept(bool(value)) == true);
}

return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ constexpr bool test() {
{
std::to_chars_result value{nullptr, std::errc{}};
assert(bool(value) == true);
static_assert(noexcept(bool(true)) == true);
static_assert(noexcept(bool(value)) == true);
}
// False
{
std::to_chars_result value{nullptr, std::errc::value_too_large};
assert(bool(value) == false);
static_assert(noexcept(bool(true)) == true);
static_assert(noexcept(bool(value)) == true);
}

return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,50 +69,18 @@ header_exportable_declarations::header_exportable_declarations(
}

std::optional<llvm::StringRef> list = Options.get("SkipDeclarations");
// TODO(LLVM-17) Remove clang 15 work-around.
#if defined(__clang_major__) && __clang_major__ < 16
if (list) {
std::string_view s = *list;
auto b = s.begin();
auto e = std::find(b, s.end(), ' ');
while (b != e) {
skip_decls_.emplace(b, e);
if (e == s.end())
break;
b = e + 1;
e = std::find(b, s.end(), ' ');
}
}
#else // defined(__clang_major__) && __clang_major__ < 16
if (list)
for (auto decl : std::views::split(*list, ' ')) {
std::string s;
std::ranges::copy(decl, std::back_inserter(s)); // use range based constructor
skip_decls_.emplace(std::move(s));
}
#endif // defined(__clang_major__) && __clang_major__ < 16
decls_ = skip_decls_;

list = Options.get("ExtraDeclarations");
// TODO(LLVM-17) Remove clang 15 work-around.
#if defined(__clang_major__) && __clang_major__ < 16
if (list) {
std::string_view s = *list;
auto b = s.begin();
auto e = std::find(b, s.end(), ' ');
while (b != e) {
std::cout << "using ::" << std::string_view{b, e} << ";\n";
if (e == s.end())
break;
b = e + 1;
e = std::find(b, s.end(), ' ');
}
}
#else // defined(__clang_major__) && __clang_major__ < 16
if (list)
for (auto decl : std::views::split(*list, ' '))
std::cout << "using ::" << std::string_view{decl.data(), decl.size()} << ";\n";
#endif // defined(__clang_major__) && __clang_major__ < 16
}

header_exportable_declarations::~header_exportable_declarations() {
Expand Down
23 changes: 18 additions & 5 deletions libcxx/utils/generate_libcxx_cppm_in.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,31 @@ def write_file(module):
else:
module_cpp_in.write(f"#include <{header}>\n")

module_cpp_in.write("\n// *** Headers not yet available ***\n")
module_cpp_in.write(
"""
// *** Headers not yet available ***
//
// This validation is mainly to catch when a new header is added but adding the
// corresponding .inc file is forgotten. However, the check based on __has_include
// alone doesn't work on Windows because the Windows SDK is on the include path,
// and that means the MSVC STL headers can be found as well, tricking __has_include
// into thinking that libc++ provides the header.
//
#ifndef _WIN32
"""
)
for header in sorted(headers_not_available):
module_cpp_in.write(
f"""\
#if __has_include(<{header}>)
# error "please update the header information for <{header}> in headers_not_available in utils/libcxx/header_information.py"
#endif // __has_include(<{header}>)
# if __has_include(<{header}>)
# error "please update the header information for <{header}> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<{header}>)
"""
)

module_cpp_in.write(
f"""
f"""#endif // _WIN32
export module {module};
{'export import std;' if module == 'std.compat' else ''}
Expand Down
103 changes: 96 additions & 7 deletions libcxx/utils/libcxx/test/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
def _getSuitableClangTidy(cfg):
try:
# If we didn't build the libcxx-tidy plugin via CMake, we can't run the clang-tidy tests.
if runScriptExitCode(cfg, ["stat %{test-tools}/clang_tidy_checks/libcxx-tidy.plugin"]) != 0:
if runScriptExitCode(cfg, ["stat %{test-tools-dir}/clang_tidy_checks/libcxx-tidy.plugin"]) != 0:
return None

# TODO MODULES require ToT due module specific fixes.
Expand Down Expand Up @@ -526,36 +526,118 @@ def check_gdb(cfg):
# target that doesn't support it will fail at compile time, not at runtime. This can
# be achieved by creating a `.verify.cpp` test that checks for the right errors, and
# mark that test as requiring `stdlib=<vendor>-libc++ && target=<target>`.
#
# Since it is not always known which deployment target to pick there are
# short-hands based on the LLVM version like using-built-library-before-llvm-xx.
# These short-hands make it easy for libc++ developers to select the proper
# version the feature will be available in and allows vendors to set the proper
# target information.
DEFAULT_FEATURES += [
# Backdeployment short-hands
Feature(
name="using-built-library-before-llvm-11",
when=lambda cfg: BooleanExpression.evaluate(
"stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0)(.0)?}}",
cfg.available_features,
),
),
Feature(
name="using-built-library-before-llvm-12",
when=lambda cfg: BooleanExpression.evaluate(
"using-built-library-before-llvm-11 || (stdlib=apple-libc++ && target={{.+}}-apple-macosx12.{{(0|1|2)}}.0)",
cfg.available_features,
),
),

Feature(
name="using-built-library-before-llvm-13",
when=lambda cfg: BooleanExpression.evaluate(
"using-built-library-before-llvm-12 || (stdlib=apple-libc++ && target={{.+}}-apple-macosx{{((12.(3|4|5|6|7))|(13.(0|1|2|3)))}}.0)",
cfg.available_features,
),
),

Feature(
name="using-built-library-before-llvm-14",
when=lambda cfg: BooleanExpression.evaluate(
"using-built-library-before-llvm-13",
cfg.available_features,
),
),

Feature(
name="using-built-library-before-llvm-15",
when=lambda cfg: BooleanExpression.evaluate(
"using-built-library-before-llvm-14 || (stdlib=apple-libc++ && target={{.+}}-apple-macosx13.{{(4|5|6)}}.0)",
cfg.available_features,
),
),

Feature(
name="using-built-library-before-llvm-16",
when=lambda cfg: BooleanExpression.evaluate(
"using-built-library-before-llvm-15 || (stdlib=apple-libc++ && target={{.+}}-apple-macosx14.{{(0|1|2|3)}}.0)",
cfg.available_features,
),
),

Feature(
name="using-built-library-before-llvm-17",
when=lambda cfg: BooleanExpression.evaluate(
"using-built-library-before-llvm-16",
cfg.available_features,
),
),

Feature(
name="using-built-library-before-llvm-18",
when=lambda cfg: BooleanExpression.evaluate(
# For now, no released version of macOS contains LLVM 18
# TODO(ldionne) Please provide the correct value.
"using-built-library-before-llvm-17 || stdlib=apple-libc++ && target={{.+}}-apple-macosx{{.+}}",
cfg.available_features,
),
),

Feature(
name="using-built-library-before-llvm-19",
when=lambda cfg: BooleanExpression.evaluate(
# For now, no released version of macOS contains LLVM 19
# TODO(ldionne) Please provide the correct value.
"using-built-library-before-llvm-18 || stdlib=apple-libc++ && target={{.+}}-apple-macosx{{.+}}",
cfg.available_features,
),
),

# Tests that require std::to_chars(floating-point) in the built library
Feature(
name="availability-fp_to_chars-missing",
when=lambda cfg: BooleanExpression.evaluate(
"stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.13|10.14|10.15|11.0|12.0|13.0)(.0)?}}",
"using-built-library-before-llvm-13",
cfg.available_features,
),
),
# Tests that require https://wg21.link/P0482 support in the built library
Feature(
name="availability-char8_t_support-missing",
when=lambda cfg: BooleanExpression.evaluate(
"stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.13|10.14|10.15|11.0)(.0)?}}",
"using-built-library-before-llvm-11",
cfg.available_features,
),
),
# Tests that require __libcpp_verbose_abort support in the built library
Feature(
name="availability-verbose_abort-missing",
when=lambda cfg: BooleanExpression.evaluate(
"stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.13|10.14|10.15|11.0|12.0|13.0)(.0)?}}",
"using-built-library-before-llvm-13",
cfg.available_features,
),
),
# Tests that require std::pmr support in the built library
Feature(
name="availability-pmr-missing",
when=lambda cfg: BooleanExpression.evaluate(
"stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.13|10.14|10.15|11.0|12.0|13.0)(.0)?}}",
"using-built-library-before-llvm-13",
cfg.available_features,
),
),
Expand All @@ -579,8 +661,15 @@ def check_gdb(cfg):
Feature(
name="availability-tzdb-missing",
when=lambda cfg: BooleanExpression.evaluate(
# TODO(ldionne) Please provide the correct value.
"(stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.13|10.14|10.15|11.0|12.0|13.0)(.0)?}})",
"using-built-library-before-llvm-19",
cfg.available_features,
),
),
# Tests that require support for <print> and std::print in <ostream> in the built library.
Feature(
name="availability-print-missing",
when=lambda cfg: BooleanExpression.evaluate(
"using-built-library-before-llvm-18",
cfg.available_features,
),
),
Expand Down
4 changes: 2 additions & 2 deletions libcxx/utils/libcxx/test/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def parseScript(test, preamble):
f"{compileFlags} "
"-Wno-reserved-module-identifier -Wno-reserved-user-defined-literal "
"-fmodule-file=std=%T/std.pcm " # The std.compat module imports std.
"--precompile -o %T/std.compat.pcm -c %{module}/std.compat.cppm",
"--precompile -o %T/std.compat.pcm -c %{module-dir}/std.compat.cppm",
)
moduleCompileFlags.extend(
["-fmodule-file=std.compat=%T/std.compat.pcm", "%T/std.compat.pcm"]
Expand All @@ -188,7 +188,7 @@ def parseScript(test, preamble):
"%dbg(MODULE std) %{cxx} %{flags} "
f"{compileFlags} "
"-Wno-reserved-module-identifier -Wno-reserved-user-defined-literal "
"--precompile -o %T/std.pcm -c %{module}/std.cppm",
"--precompile -o %T/std.pcm -c %{module-dir}/std.cppm",
)
moduleCompileFlags.extend(["-fmodule-file=std=%T/std.pcm", "%T/std.pcm"])

Expand Down
10 changes: 5 additions & 5 deletions lld/ELF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2446,8 +2446,8 @@ SmallVector<PhdrEntry *, 0> Writer<ELFT>::createPhdrs(Partition &part) {
// Segments are contiguous memory regions that has the same attributes
// (e.g. executable or writable). There is one phdr for each segment.
// Therefore, we need to create a new phdr when the next section has
// compatible flags or is loaded at a discontiguous address or memory region
// using AT or AT> linker script command, respectively.
// incompatible flags or is loaded at a discontiguous address or memory
// region using AT or AT> linker script command, respectively.
//
// As an exception, we don't create a separate load segment for the ELF
// headers, even if the first "real" output has an AT or AT> attribute.
Expand All @@ -2461,10 +2461,10 @@ SmallVector<PhdrEntry *, 0> Writer<ELFT>::createPhdrs(Partition &part) {
// needed to create a new LOAD)
uint64_t newFlags = computeFlags(sec->getPhdrFlags());
// When --no-rosegment is specified, RO and RX sections are compatible.
uint32_t diff = flags ^ newFlags;
uint32_t incompatible = flags ^ newFlags;
if (config->singleRoRx && !(newFlags & PF_W))
diff &= ~PF_X;
if (diff)
incompatible &= ~PF_X;
if (incompatible)
load = nullptr;

bool sameLMARegion =
Expand Down
25 changes: 13 additions & 12 deletions lld/test/ELF/riscv-section-layout.s
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@

# RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.32.o
# RUN: ld.lld -pie %t.32.o -o %t.32
# RUN: llvm-readelf -S -s %t.32 | FileCheck %s --check-prefix=NOSDATA
# RUN: llvm-readelf -S -sX %t.32 | FileCheck %s --check-prefix=NOSDATA
# RUN: llvm-mc -filetype=obj -triple=riscv32 --defsym=SDATA=1 %s -o %t.32s.o
# RUN: ld.lld -pie %t.32s.o -o %t.32s
# RUN: llvm-readelf -S -s %t.32s | FileCheck %s
# RUN: llvm-readelf -S -sX %t.32s | FileCheck %s

# RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.64.o
# RUN: ld.lld -pie %t.64.o -o %t.64
# RUN: llvm-readelf -S -s %t.64 | FileCheck %s --check-prefix=NOSDATA
# RUN: llvm-readelf -S -sX %t.64 | FileCheck %s --check-prefix=NOSDATA
# RUN: llvm-mc -filetype=obj -triple=riscv64 --defsym=SDATA=1 %s -o %t.64s.o
# RUN: ld.lld -pie %t.64s.o -o %t.64s
# RUN: llvm-readelf -S -s %t.64s | FileCheck %s
# RUN: llvm-readelf -S -sX %t.64s | FileCheck %s

# NOSDATA: .text
# NOSDATA-NEXT: .tdata
# NOSDATA-NEXT: .tdata PROGBITS [[#%x,TDATA:]]
# NOSDATA-NEXT: .tbss
# NOSDATA-NEXT: .dynamic
# NOSDATA-NEXT: .got
Expand All @@ -28,9 +28,10 @@
## exist, define __global_pointer$ and set its st_shndx arbitrarily to 1.
## The symbol value should not be used by the program.

# NOSDATA-DAG: [[#]]: {{0*}}[[#BSS]] 0 NOTYPE GLOBAL DEFAULT [[#]] _edata
# NOSDATA-DAG: [[#]]: {{0*}}[[#BSS]] 0 NOTYPE GLOBAL DEFAULT [[#]] __bss_start
# NOSDATA-DAG: [[#]]: {{0*}}800 0 NOTYPE GLOBAL DEFAULT 1 __global_pointer$
# NOSDATA-DAG: [[#]]: {{.*}} 0 NOTYPE GLOBAL DEFAULT [[#]] (.text) _etext
# NOSDATA-DAG: [[#]]: {{0*}}[[#BSS]] 0 NOTYPE GLOBAL DEFAULT [[#]] (.data) _edata
# NOSDATA-DAG: [[#]]: {{0*}}[[#BSS]] 0 NOTYPE GLOBAL DEFAULT [[#]] (.bss) __bss_start
# NOSDATA-DAG: [[#]]: {{0*}}800 0 NOTYPE GLOBAL DEFAULT 1 (.dynsym) __global_pointer$

# CHECK: .text
# CHECK-NEXT: .tdata
Expand All @@ -43,11 +44,11 @@
# CHECK-NEXT: .sbss NOBITS [[#%x,SBSS:]]
# CHECK-NEXT: .bss

# CHECK-DAG: [[#]]: {{0*}}[[#SBSS]] 0 NOTYPE GLOBAL DEFAULT [[#]] _edata
# CHECK-DAG: [[#]]: {{0*}}[[#SBSS]] 0 NOTYPE GLOBAL DEFAULT [[#]] __bss_start
# CHECK-DAG: [[#]]: {{0*}}[[#SDATA+0x800]] 0 NOTYPE GLOBAL DEFAULT [[#]] __global_pointer$
# CHECK-DAG: [[#]]: {{0*}}[[#SBSS]] 0 NOTYPE GLOBAL DEFAULT [[#]] (.sdata) _edata
# CHECK-DAG: [[#]]: {{0*}}[[#SBSS]] 0 NOTYPE GLOBAL DEFAULT [[#]] (.sbss) __bss_start
# CHECK-DAG: [[#]]: {{0*}}[[#SDATA+0x800]] 0 NOTYPE GLOBAL DEFAULT [[#]] (.sdata) __global_pointer$

.globl _edata, __bss_start
.globl _etext, _edata, __bss_start
lla gp, __global_pointer$

.section .data,"aw",@progbits; .long _GLOBAL_OFFSET_TABLE_ - .
Expand Down
54 changes: 32 additions & 22 deletions lld/test/ELF/x86-64-section-layout.s
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,31 @@

# RUN: llvm-mc -filetype=obj -triple=x86_64 --defsym=BSS=1 a.s -o a.o
# RUN: ld.lld --section-start=.note=0x200300 a.o -o a
# RUN: llvm-readelf -S -l a | FileCheck %s
# RUN: llvm-readelf -S -l -sX a | FileCheck %s

# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a1.o
# RUN: ld.lld --section-start=.note=0x200300 a1.o -o a1
# RUN: llvm-readelf -S a1 | FileCheck %s --check-prefix=CHECK1
# RUN: llvm-readelf -S -sX a1 | FileCheck %s --check-prefix=CHECK1

# RUN: ld.lld -T b.lds -z norelro a.o -o b
# RUN: llvm-readelf -S -l b | FileCheck %s --check-prefix=CHECK2

# CHECK: Name Type Address Off Size ES Flg Lk Inf Al
# CHECK-NEXT: NULL 0000000000000000 000000 000000 00 0 0 0
# CHECK-NEXT: .note NOTE 0000000000200300 000300 000001 00 A 0 0 1
# CHECK-NEXT: .lrodata PROGBITS 0000000000200301 000301 000002 00 Al 0 0 1
# CHECK-NEXT: .rodata PROGBITS 0000000000200303 000303 000001 00 A 0 0 1
# CHECK-NEXT: .text PROGBITS 0000000000201304 000304 000001 00 AX 0 0 4
# CHECK-NEXT: .tdata PROGBITS 0000000000202305 000305 000001 00 WAT 0 0 1
# CHECK-NEXT: .tbss NOBITS 0000000000202306 000306 000002 00 WAT 0 0 1
# CHECK-NEXT: .relro_padding NOBITS 0000000000202306 000306 000cfa 00 WA 0 0 1
# CHECK-NEXT: .data PROGBITS 0000000000203306 000306 000001 00 WA 0 0 1
# CHECK-NEXT: .bss NOBITS 0000000000203307 000307 001800 00 WA 0 0 1
# CHECK: Name Type Address Off Size ES Flg Lk Inf Al
# CHECK-NEXT: NULL 0000000000000000 000000 000000 00 0 0 0
# CHECK-NEXT: .note NOTE 0000000000200300 000300 000001 00 A 0 0 1
# CHECK-NEXT: .lrodata PROGBITS 0000000000200301 000301 000002 00 Al 0 0 1
# CHECK-NEXT: .rodata PROGBITS 0000000000200303 000303 000001 00 A 0 0 1
# CHECK-NEXT: .text PROGBITS 0000000000201304 000304 000001 00 AX 0 0 4
# CHECK-NEXT: .tdata PROGBITS 0000000000202305 000305 000001 00 WAT 0 0 1
# CHECK-NEXT: .tbss NOBITS 0000000000202306 000306 000002 00 WAT 0 0 1
# CHECK-NEXT: .relro_padding NOBITS 0000000000202306 000306 000cfa 00 WA 0 0 1
# CHECK-NEXT: .data PROGBITS 0000000000203306 000306 000001 00 WA 0 0 1
# CHECK-NEXT: .bss NOBITS 0000000000203307 000307 001800 00 WA 0 0 1
## We spend size(.bss) % MAXPAGESIZE bytes for .bss.
# CHECK-NEXT: .ldata PROGBITS 0000000000205b07 000b07 000002 00 WAl 0 0 1
# CHECK-NEXT: .ldata2 PROGBITS 0000000000205b09 000b09 000001 00 WAl 0 0 1
# CHECK-NEXT: .lbss NOBITS 0000000000205b0a 000b0a 000002 00 WAl 0 0 1
# CHECK-NEXT: .comment PROGBITS 0000000000000000 000b0a {{.*}} 01 MS 0 0 1
# CHECK-NEXT: .ldata PROGBITS 0000000000205b07 000b07 000002 00 WAl 0 0 1
# CHECK-NEXT: .ldata2 PROGBITS 0000000000205b09 000b09 000001 00 WAl 0 0 1
# CHECK-NEXT: .lbss NOBITS 0000000000205b0a 000b0a 001201 00 WAl 0 0 1
# CHECK-NEXT: .comment PROGBITS 0000000000000000 000b0a {{.*}} 01 MS 0 0 1

# CHECK: Program Headers:
# CHECK-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
Expand All @@ -39,13 +39,23 @@
# CHECK-NEXT: LOAD 0x000304 0x0000000000201304 0x0000000000201304 0x000001 0x000001 R E 0x1000
# CHECK-NEXT: LOAD 0x000305 0x0000000000202305 0x0000000000202305 0x000001 0x000cfb RW 0x1000
# CHECK-NEXT: LOAD 0x000306 0x0000000000203306 0x0000000000203306 0x000001 0x001801 RW 0x1000
# CHECK-NEXT: LOAD 0x000b07 0x0000000000205b07 0x0000000000205b07 0x000003 0x000005 RW 0x1000
# CHECK-NEXT: LOAD 0x000b07 0x0000000000205b07 0x0000000000205b07 0x000003 0x001204 RW 0x1000

# CHECK: 0000000000201304 0 NOTYPE GLOBAL DEFAULT [[#]] (.text) _start
# CHECK-NEXT: 0000000000201305 0 NOTYPE GLOBAL DEFAULT [[#]] (.text) _etext
# CHECK-NEXT: 0000000000205b0a 0 NOTYPE GLOBAL DEFAULT [[#]] (.ldata2) _edata
# CHECK-NEXT: 0000000000206d0b 0 NOTYPE GLOBAL DEFAULT [[#]] (.lbss) _end

# CHECK1: .data PROGBITS 0000000000203306 000306 000001 00 WA 0 0 1
# CHECK1-NEXT: .ldata PROGBITS 0000000000203307 000307 000002 00 WAl 0 0 1
# CHECK1-NEXT: .ldata2 PROGBITS 0000000000203309 000309 000001 00 WAl 0 0 1
# CHECK1-NEXT: .comment PROGBITS 0000000000000000 00030a {{.*}} 01 MS 0 0 1

# CHECK1: 0000000000201304 0 NOTYPE GLOBAL DEFAULT [[#]] (.text) _start
# CHECK1-NEXT: 0000000000201305 0 NOTYPE GLOBAL DEFAULT [[#]] (.text) _etext
# CHECK1-NEXT: 000000000020330a 0 NOTYPE GLOBAL DEFAULT [[#]] (.ldata2) _edata
# CHECK1-NEXT: 000000000020330a 0 NOTYPE GLOBAL DEFAULT [[#]] (.ldata2) _end

# CHECK2: .note NOTE 0000000000200300 000300 000001 00 A 0 0 1
# CHECK2-NEXT: .lrodata PROGBITS 0000000000200301 000301 000001 00 Al 0 0 1
## With a SECTIONS command, we suppress the default rule placing .lrodata.* into .lrodata.
Expand All @@ -59,19 +69,19 @@
# CHECK2-NEXT: .bss NOBITS 0000000000200307 000307 001800 00 WA 0 0 1
# CHECK2-NEXT: .ldata PROGBITS 0000000000201b07 001b07 000002 00 WAl 0 0 1
# CHECK2-NEXT: .ldata2 PROGBITS 0000000000201b09 001b09 000001 00 WAl 0 0 1
# CHECK2-NEXT: .lbss NOBITS 0000000000201b0a 001b0a 000002 00 WAl 0 0 1
# CHECK2-NEXT: .lbss NOBITS 0000000000201b0a 001b0a 001201 00 WAl 0 0 1
# CHECK2-NEXT: .comment PROGBITS 0000000000000000 001b0a {{.*}} 01 MS 0 0 1

# CHECK2: Program Headers:
# CHECK2-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
# CHECK2-NEXT: PHDR 0x000040 0x0000000000200040 0x0000000000200040 {{.*}} {{.*}} R 0x8
# CHECK2-NEXT: LOAD 0x000000 0x0000000000200000 0x0000000000200000 0x000304 0x000304 R 0x1000
# CHECK2-NEXT: LOAD 0x000304 0x0000000000200304 0x0000000000200304 0x000001 0x000001 R E 0x1000
# CHECK2-NEXT: LOAD 0x000305 0x0000000000200305 0x0000000000200305 0x001805 0x001807 RW 0x1000
# CHECK2-NEXT: LOAD 0x000305 0x0000000000200305 0x0000000000200305 0x001805 0x002a06 RW 0x1000
# CHECK2-NEXT: TLS 0x000305 0x0000000000200305 0x0000000000200305 0x000001 0x000003 R 0x1

#--- a.s
.globl _start
.globl _start, _etext, _edata, _end
_start:
ret

Expand All @@ -92,7 +102,7 @@ _start:
## Input .ldata.rel.ro sections are placed in the output .ldata section.
.section .ldata.rel.ro,"awl"; .space 1
.ifdef BSS
.section .lbss,"awl",@nobits; .space 1
.section .lbss,"awl",@nobits; .space 0x1200
## Input .lbss.rel.ro sections are placed in the output .lbss section.
.section .lbss.rel.ro,"awl",@nobits; .space 1
.endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

class LibcxxChronoDataFormatterTestCase(TestBase):
@add_test_categories(["libc++"])
@skipIf(compiler="clang", compiler_version=["<", "11.0"])
@skipIf(compiler="clang", compiler_version=["<", "17.0"])
def test_with_run_command(self):
"""Test that that file and class static variables display correctly."""
self.build()
Expand Down
20 changes: 8 additions & 12 deletions llvm/docs/AMDGPUUsage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -357,12 +357,12 @@ Every processor supports every OS ABI (see :ref:`amdgpu-os`) with the following
Add product
names.

``gfx90a`` ``amdgcn`` dGPU - sramecc - Absolute - *rocm-amdhsa* *TBA*
- tgsplit flat
- xnack scratch .. TODO::
``gfx90a`` ``amdgcn`` dGPU - sramecc - Absolute - *rocm-amdhsa* - AMD Instinct MI210 Accelerator
- tgsplit flat - *rocm-amdhsa* - AMD Instinct MI250 Accelerator
- xnack scratch - *rocm-amdhsa* - AMD Instinct MI250X Accelerator
- kernarg preload - Packed
work-item Add product
IDs names.
work-item
IDs

``gfx90c`` ``amdgcn`` APU - xnack - Absolute - *pal-amdpal* - Ryzen 7 4700G
flat - Ryzen 7 4700GE
Expand Down Expand Up @@ -5530,13 +5530,9 @@ If the *Target Properties* column of :ref:`amdgpu-processor-table` specifies
Instead the flat SCRATCH instructions are used.

Otherwise, Private Segment Buffer SGPR register is used to initialize 4 SGPRs
that are used as a V# to access scratch.
The compiler synthesizes the initialization value for the Private Segment
Buffer in the kernel prologue, using the Flat Scratch Init to initialize low
64-bit and a known constant for the high ones. If the Flat Scratch Init is not
available, CP uses the value provided by the runtime. It is used, together with
Scratch Wavefront Offset as an offset, to access the private memory space using
a segment address. See
that are used as a V# to access scratch. CP uses the value provided by the
runtime. It is used, together with Scratch Wavefront Offset as an offset, to
access the private memory space using a segment address. See
:ref:`amdgpu-amdhsa-initial-kernel-execution-state`.

The scratch V# is a four-aligned SGPR and always selected for the kernel as
Expand Down
9 changes: 7 additions & 2 deletions llvm/docs/CommandGuide/llvm-objcopy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -544,8 +544,13 @@ options. For GNU :program:`objcopy` compatibility, the values are all bfdnames.
- `elf32-sparc`
- `elf32-sparcel`

Additionally, all targets except `binary` and `ihex` can have `-freebsd` as a
suffix.
The following formats are suppoprted by :program:`llvm-objcopy` for the
:option:`--output-target` only:

- `srec`

Additionally, all targets except `binary`, `ihex`, and `srec` can have
`-freebsd` as a suffix.

BINARY INPUT AND OUTPUT
-----------------------
Expand Down
3 changes: 1 addition & 2 deletions llvm/docs/NVPTXUsage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,7 @@ input IR module ``module.bc``, the following compilation flow is recommended:

The ``NVVMReflect`` pass will attempt to remove dead code even without
optimizations. This allows potentially incompatible instructions to be avoided
at all optimizations levels. This currently only works for simple conditionals
like the above example.
at all optimizations levels by using the ``__CUDA_ARCH`` argument.

1. Save list of external functions in ``module.bc``
2. Link ``module.bc`` with ``libdevice.compute_XX.YY.bc``
Expand Down
12 changes: 8 additions & 4 deletions llvm/include/llvm/MC/MCRegisterInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -572,9 +572,10 @@ class MCSubRegIndexIterator {
bool isValid() const { return SRIter.isValid(); }

/// Moves to the next position.
void operator++() {
MCSubRegIndexIterator &operator++() {
++SRIter;
++SRIndex;
return *this;
}
};

Expand Down Expand Up @@ -688,9 +689,10 @@ class MCRegUnitMaskIterator {
bool isValid() const { return RUIter.isValid(); }

/// Moves to the next position.
void operator++() {
MCRegUnitMaskIterator &operator++() {
++MaskListIter;
++RUIter;
return *this;
}
};

Expand Down Expand Up @@ -728,10 +730,11 @@ class MCRegUnitRootIterator {
}

/// Preincrement to move to the next root register.
void operator++() {
MCRegUnitRootIterator &operator++() {
assert(isValid() && "Cannot move off the end of the list.");
Reg0 = Reg1;
Reg1 = 0;
return *this;
}
};

Expand Down Expand Up @@ -788,10 +791,11 @@ class MCRegAliasIterator {
}
}

void operator++() {
MCRegAliasIterator &operator++() {
assert(isValid() && "Cannot move off the end of the list.");
do advance();
while (!IncludeSelf && isValid() && *SI == Reg);
return *this;
}
};

Expand Down
7 changes: 1 addition & 6 deletions llvm/include/llvm/ObjCopy/CommonConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,7 @@
namespace llvm {
namespace objcopy {

enum class FileFormat {
Unspecified,
ELF,
Binary,
IHex,
};
enum class FileFormat { Unspecified, ELF, Binary, IHex, SREC };

// This type keeps track of the machine info for various architectures. This
// lets us map architecture names to ELF types and the e_machine value of the
Expand Down
5 changes: 1 addition & 4 deletions llvm/include/llvm/TargetParser/Triple.h
Original file line number Diff line number Diff line change
Expand Up @@ -1035,10 +1035,7 @@ class Triple {

/// True if the target supports both general-dynamic and TLSDESC, and TLSDESC
/// is enabled by default.
bool hasDefaultTLSDESC() const {
// TODO: Improve check for other platforms, like Android, and RISC-V
return false;
}
bool hasDefaultTLSDESC() const { return isAndroid() && isRISCV64(); }

/// Tests whether the target uses -data-sections as default.
bool hasDefaultDataSections() const {
Expand Down
25 changes: 0 additions & 25 deletions llvm/include/llvm/Transforms/Scalar/LoopReroll.h

This file was deleted.

2 changes: 1 addition & 1 deletion llvm/lib/Analysis/BasicAliasAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1187,7 +1187,7 @@ AliasResult BasicAAResult::aliasGEP(
// so noalias still holds so long as the dependency distance is at least as
// big as the typesize.
if (VLeftSize.hasValue() &&
Scale.uge(VLeftSize.getValue().getKnownMinValue()))
Scale.abs().uge(VLeftSize.getValue().getKnownMinValue()))
return AliasResult::NoAlias;
}

Expand Down
27 changes: 22 additions & 5 deletions llvm/lib/CodeGen/RegisterCoalescer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,8 @@ namespace {
/// was successfully coalesced away. If it is not currently possible to
/// coalesce this interval, but it may be possible if other things get
/// coalesced, then it returns true by reference in 'Again'.
bool joinCopy(MachineInstr *CopyMI, bool &Again);
bool joinCopy(MachineInstr *CopyMI, bool &Again,
SmallPtrSetImpl<MachineInstr *> &CurrentErasedInstrs);

/// Attempt to join these two intervals. On failure, this
/// returns false. The output "SrcInt" will not have been modified, so we
Expand Down Expand Up @@ -1964,7 +1965,9 @@ void RegisterCoalescer::setUndefOnPrunedSubRegUses(LiveInterval &LI,
LIS->shrinkToUses(&LI);
}

bool RegisterCoalescer::joinCopy(MachineInstr *CopyMI, bool &Again) {
bool RegisterCoalescer::joinCopy(
MachineInstr *CopyMI, bool &Again,
SmallPtrSetImpl<MachineInstr *> &CurrentErasedInstrs) {
Again = false;
LLVM_DEBUG(dbgs() << LIS->getInstructionIndex(*CopyMI) << '\t' << *CopyMI);

Expand Down Expand Up @@ -2156,7 +2159,9 @@ bool RegisterCoalescer::joinCopy(MachineInstr *CopyMI, bool &Again) {
// CopyMI has been erased by joinIntervals at this point. Remove it from
// ErasedInstrs since copyCoalesceWorkList() won't add a successful join back
// to the work list. This keeps ErasedInstrs from growing needlessly.
ErasedInstrs.erase(CopyMI);
if (ErasedInstrs.erase(CopyMI))
// But we may encounter the instruction again in this iteration.
CurrentErasedInstrs.insert(CopyMI);

// Rewrite all SrcReg operands to DstReg.
// Also update DstReg operands to include DstIdx if it is set.
Expand Down Expand Up @@ -3982,21 +3987,33 @@ void RegisterCoalescer::lateLiveIntervalUpdate() {
bool RegisterCoalescer::
copyCoalesceWorkList(MutableArrayRef<MachineInstr*> CurrList) {
bool Progress = false;
SmallPtrSet<MachineInstr *, 4> CurrentErasedInstrs;
for (MachineInstr *&MI : CurrList) {
if (!MI)
continue;
// Skip instruction pointers that have already been erased, for example by
// dead code elimination.
if (ErasedInstrs.count(MI)) {
if (ErasedInstrs.count(MI) || CurrentErasedInstrs.count(MI)) {
MI = nullptr;
continue;
}
bool Again = false;
bool Success = joinCopy(MI, Again);
bool Success = joinCopy(MI, Again, CurrentErasedInstrs);
Progress |= Success;
if (Success || !Again)
MI = nullptr;
}
// Clear instructions not recorded in `ErasedInstrs` but erased.
if (!CurrentErasedInstrs.empty()) {
for (MachineInstr *&MI : CurrList) {
if (MI && CurrentErasedInstrs.count(MI))
MI = nullptr;
}
for (MachineInstr *&MI : WorkList) {
if (MI && CurrentErasedInstrs.count(MI))
MI = nullptr;
}
}
return Progress;
}

Expand Down
40 changes: 40 additions & 0 deletions llvm/lib/CodeGen/TargetLoweringBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,46 @@ void TargetLoweringBase::InitLibcalls(const Triple &TT) {
for (int LC = 0; LC < RTLIB::UNKNOWN_LIBCALL; ++LC)
setLibcallCallingConv((RTLIB::Libcall)LC, CallingConv::C);

// Use the f128 variants of math functions on x86_64
if (TT.getArch() == Triple::ArchType::x86_64) {
setLibcallName(RTLIB::REM_F128, "fmodf128");
setLibcallName(RTLIB::FMA_F128, "fmaf128");
setLibcallName(RTLIB::SQRT_F128, "sqrtf128");
setLibcallName(RTLIB::CBRT_F128, "cbrtf128");
setLibcallName(RTLIB::LOG_F128, "logf128");
setLibcallName(RTLIB::LOG_FINITE_F128, "__logf128_finite");
setLibcallName(RTLIB::LOG2_F128, "log2f128");
setLibcallName(RTLIB::LOG2_FINITE_F128, "__log2f128_finite");
setLibcallName(RTLIB::LOG10_F128, "log10f128");
setLibcallName(RTLIB::LOG10_FINITE_F128, "__log10f128_finite");
setLibcallName(RTLIB::EXP_F128, "expf128");
setLibcallName(RTLIB::EXP_FINITE_F128, "__expf128_finite");
setLibcallName(RTLIB::EXP2_F128, "exp2f128");
setLibcallName(RTLIB::EXP2_FINITE_F128, "__exp2f128_finite");
setLibcallName(RTLIB::EXP10_F128, "exp10f128");
setLibcallName(RTLIB::SIN_F128, "sinf128");
setLibcallName(RTLIB::COS_F128, "cosf128");
setLibcallName(RTLIB::SINCOS_F128, "sincosf128");
setLibcallName(RTLIB::POW_F128, "powf128");
setLibcallName(RTLIB::POW_FINITE_F128, "__powf128_finite");
setLibcallName(RTLIB::CEIL_F128, "ceilf128");
setLibcallName(RTLIB::TRUNC_F128, "truncf128");
setLibcallName(RTLIB::RINT_F128, "rintf128");
setLibcallName(RTLIB::NEARBYINT_F128, "nearbyintf128");
setLibcallName(RTLIB::ROUND_F128, "roundf128");
setLibcallName(RTLIB::ROUNDEVEN_F128, "roundevenf128");
setLibcallName(RTLIB::FLOOR_F128, "floorf128");
setLibcallName(RTLIB::COPYSIGN_F128, "copysignf128");
setLibcallName(RTLIB::FMIN_F128, "fminf128");
setLibcallName(RTLIB::FMAX_F128, "fmaxf128");
setLibcallName(RTLIB::LROUND_F128, "lroundf128");
setLibcallName(RTLIB::LLROUND_F128, "llroundf128");
setLibcallName(RTLIB::LRINT_F128, "lrintf128");
setLibcallName(RTLIB::LLRINT_F128, "llrintf128");
setLibcallName(RTLIB::LDEXP_F128, "ldexpf128");
setLibcallName(RTLIB::FREXP_F128, "frexpf128");
}

// For IEEE quad-precision libcall names, PPC uses "kf" instead of "tf".
if (TT.isPPC()) {
setLibcallName(RTLIB::ADD_F128, "__addkf3");
Expand Down
4 changes: 3 additions & 1 deletion llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,9 @@ static std::unique_ptr<Writer> createWriter(const CommonConfig &Config,
case FileFormat::Binary:
return std::make_unique<BinaryWriter>(Obj, Out, Config);
case FileFormat::IHex:
return std::make_unique<IHexWriter>(Obj, Out);
return std::make_unique<IHexWriter>(Obj, Out, Config.OutputFilename);
case FileFormat::SREC:
return std::make_unique<SRECWriter>(Obj, Out, Config.OutputFilename);
default:
return createELFWriter(Config, Obj, Out, OutputElfType);
}
Expand Down
280 changes: 239 additions & 41 deletions llvm/lib/ObjCopy/ELF/ELFObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2707,10 +2707,52 @@ Error BinaryWriter::finalize() {
return Error::success();
}

bool IHexWriter::SectionCompare::operator()(const SectionBase *Lhs,
const SectionBase *Rhs) const {
return (sectionPhysicalAddr(Lhs) & 0xFFFFFFFFU) <
(sectionPhysicalAddr(Rhs) & 0xFFFFFFFFU);
Error ASCIIHexWriter::checkSection(const SectionBase &S) const {
if (addressOverflows32bit(S.Addr) ||
addressOverflows32bit(S.Addr + S.Size - 1))
return createStringError(
errc::invalid_argument,
"section '%s' address range [0x%llx, 0x%llx] is not 32 bit",
S.Name.c_str(), S.Addr, S.Addr + S.Size - 1);
return Error::success();
}

Error ASCIIHexWriter::finalize() {
// We can't write 64-bit addresses.
if (addressOverflows32bit(Obj.Entry))
return createStringError(errc::invalid_argument,
"entry point address 0x%llx overflows 32 bits",
Obj.Entry);

for (const SectionBase &S : Obj.sections()) {
if ((S.Flags & ELF::SHF_ALLOC) && S.Type != ELF::SHT_NOBITS && S.Size > 0) {
if (Error E = checkSection(S))
return E;
Sections.push_back(&S);
}
}

llvm::sort(Sections, [](const SectionBase *A, const SectionBase *B) {
return sectionPhysicalAddr(A) < sectionPhysicalAddr(B);
});

std::unique_ptr<WritableMemoryBuffer> EmptyBuffer =
WritableMemoryBuffer::getNewMemBuffer(0);
if (!EmptyBuffer)
return createStringError(errc::not_enough_memory,
"failed to allocate memory buffer of 0 bytes");

Expected<size_t> ExpTotalSize = getTotalSize(*EmptyBuffer);
if (!ExpTotalSize)
return ExpTotalSize.takeError();
TotalSize = *ExpTotalSize;

Buf = WritableMemoryBuffer::getNewMemBuffer(TotalSize);
if (!Buf)
return createStringError(errc::not_enough_memory,
"failed to allocate memory buffer of 0x" +
Twine::utohexstr(TotalSize) + " bytes");
return Error::success();
}

uint64_t IHexWriter::writeEntryPointRecord(uint8_t *Buf) {
Expand Down Expand Up @@ -2740,6 +2782,20 @@ uint64_t IHexWriter::writeEndOfFileRecord(uint8_t *Buf) {
return HexData.size();
}

Expected<size_t>
IHexWriter::getTotalSize(WritableMemoryBuffer &EmptyBuffer) const {
IHexSectionWriterBase LengthCalc(EmptyBuffer);
for (const SectionBase *Sec : Sections)
if (Error Err = Sec->accept(LengthCalc))
return std::move(Err);

// We need space to write section records + StartAddress record
// (if start adress is not zero) + EndOfFile record.
return LengthCalc.getBufferOffset() +
(Obj.Entry ? IHexRecord::getLineLength(4) : 0) +
IHexRecord::getLineLength(0);
}

Error IHexWriter::write() {
IHexSectionWriter Writer(*Buf);
// Write sections.
Expand All @@ -2762,54 +2818,196 @@ Error IHexWriter::write() {
return Error::success();
}

Error IHexWriter::checkSection(const SectionBase &Sec) {
uint64_t Addr = sectionPhysicalAddr(&Sec);
if (addressOverflows32bit(Addr) || addressOverflows32bit(Addr + Sec.Size - 1))
return createStringError(
errc::invalid_argument,
"Section '%s' address range [0x%llx, 0x%llx] is not 32 bit",
Sec.Name.c_str(), Addr, Addr + Sec.Size - 1);
Error SRECSectionWriterBase::visit(const StringTableSection &Sec) {
// Check that the sizer has already done its work.
assert(Sec.Size == Sec.StrTabBuilder.getSize() &&
"Expected section size to have been finalized");
// We don't need to write anything here because the real writer has already
// done it.
return Error::success();
}

Error IHexWriter::finalize() {
// We can't write 64-bit addresses.
if (addressOverflows32bit(Obj.Entry))
return createStringError(errc::invalid_argument,
"Entry point address 0x%llx overflows 32 bits",
Obj.Entry);
Error SRECSectionWriterBase::visit(const Section &Sec) {
writeSection(Sec, Sec.Contents);
return Error::success();
}

for (const SectionBase &Sec : Obj.sections())
if ((Sec.Flags & ELF::SHF_ALLOC) && Sec.Type != ELF::SHT_NOBITS &&
Sec.Size > 0) {
if (Error E = checkSection(Sec))
return E;
Sections.insert(&Sec);
}
Error SRECSectionWriterBase::visit(const OwnedDataSection &Sec) {
writeSection(Sec, Sec.Data);
return Error::success();
}

std::unique_ptr<WritableMemoryBuffer> EmptyBuffer =
WritableMemoryBuffer::getNewMemBuffer(0);
if (!EmptyBuffer)
return createStringError(errc::not_enough_memory,
"failed to allocate memory buffer of 0 bytes");
Error SRECSectionWriterBase::visit(const DynamicRelocationSection &Sec) {
writeSection(Sec, Sec.Contents);
return Error::success();
}

void SRECSectionWriter::writeRecord(SRecord &Record, uint64_t Off) {
SRecLineData Data = Record.toString();
memcpy(Out.getBufferStart() + Off, Data.data(), Data.size());
}

IHexSectionWriterBase LengthCalc(*EmptyBuffer);
void SRECSectionWriterBase::writeRecords(uint32_t Entry) {
// The ELF header could contain an entry point outside of the sections we have
// seen that does not fit the current record Type.
Type = std::max(Type, SRecord::getType(Entry));
uint64_t Off = HeaderSize;
for (SRecord &Record : Records) {
Record.Type = Type;
writeRecord(Record, Off);
Off += Record.getSize();
}
Offset = Off;
}

void SRECSectionWriterBase::writeSection(const SectionBase &S,
ArrayRef<uint8_t> Data) {
const uint32_t ChunkSize = 16;
uint32_t Address = sectionPhysicalAddr(&S);
uint32_t EndAddr = Address + S.Size - 1;
Type = std::max(SRecord::getType(EndAddr), Type);
while (!Data.empty()) {
uint64_t DataSize = std::min<uint64_t>(Data.size(), ChunkSize);
SRecord Record{Type, Address, Data.take_front(DataSize)};
Records.push_back(Record);
Data = Data.drop_front(DataSize);
Address += DataSize;
}
}

Error SRECSectionWriter::visit(const StringTableSection &Sec) {
assert(Sec.Size == Sec.StrTabBuilder.getSize() &&
"Section size does not match the section's string table builder size");
std::vector<uint8_t> Data(Sec.Size);
Sec.StrTabBuilder.write(Data.data());
writeSection(Sec, Data);
return Error::success();
}

SRecLineData SRecord::toString() const {
SRecLineData Line(getSize());
auto *Iter = Line.begin();
*Iter++ = 'S';
*Iter++ = '0' + Type;
// Write 1 byte (2 hex characters) record count.
Iter = toHexStr(getCount(), Iter, 2);
// Write the address field with length depending on record type.
Iter = toHexStr(Address, Iter, getAddressSize());
// Write data byte by byte.
for (uint8_t X : Data)
Iter = toHexStr(X, Iter, 2);
// Write the 1 byte checksum.
Iter = toHexStr(getChecksum(), Iter, 2);
*Iter++ = '\r';
*Iter++ = '\n';
assert(Iter == Line.end());
return Line;
}

uint8_t SRecord::getChecksum() const {
uint32_t Sum = getCount();
Sum += (Address >> 24) & 0xFF;
Sum += (Address >> 16) & 0xFF;
Sum += (Address >> 8) & 0xFF;
Sum += Address & 0xFF;
for (uint8_t Byte : Data)
Sum += Byte;
return 0xFF - (Sum & 0xFF);
}

size_t SRecord::getSize() const {
// Type, Count, Checksum, and CRLF are two characters each.
return 2 + 2 + getAddressSize() + Data.size() * 2 + 2 + 2;
}

uint8_t SRecord::getAddressSize() const {
switch (Type) {
case Type::S2:
return 6;
case Type::S3:
return 8;
case Type::S7:
return 8;
case Type::S8:
return 6;
default:
return 4;
}
}

uint8_t SRecord::getCount() const {
uint8_t DataSize = Data.size();
uint8_t ChecksumSize = 1;
return getAddressSize() / 2 + DataSize + ChecksumSize;
}

uint8_t SRecord::getType(uint32_t Address) {
if (isUInt<16>(Address))
return SRecord::S1;
if (isUInt<24>(Address))
return SRecord::S2;
return SRecord::S3;
}

SRecord SRecord::getHeader(StringRef FileName) {
// Header is a record with Type S0, Address 0, and Data that is a
// vendor-specific text comment. For the comment we will use the output file
// name truncated to 40 characters to match the behavior of GNU objcopy.
StringRef HeaderContents = FileName.slice(0, 40);
ArrayRef<uint8_t> Data(
reinterpret_cast<const uint8_t *>(HeaderContents.data()),
HeaderContents.size());
return {SRecord::S0, 0, Data};
}

size_t SRECWriter::writeHeader(uint8_t *Buf) {
SRecLineData Record = SRecord::getHeader(OutputFileName).toString();
memcpy(Buf, Record.data(), Record.size());
return Record.size();
}

size_t SRECWriter::writeTerminator(uint8_t *Buf, uint8_t Type) {
assert(Type >= SRecord::S7 && Type <= SRecord::S9 &&
"Invalid record type for terminator");
uint32_t Entry = Obj.Entry;
SRecLineData Data = SRecord{Type, Entry, {}}.toString();
memcpy(Buf, Data.data(), Data.size());
return Data.size();
}

Expected<size_t>
SRECWriter::getTotalSize(WritableMemoryBuffer &EmptyBuffer) const {
SRECSizeCalculator SizeCalc(EmptyBuffer, 0);
for (const SectionBase *Sec : Sections)
if (Error Err = Sec->accept(LengthCalc))
if (Error Err = Sec->accept(SizeCalc))
return Err;

// We need space to write section records + StartAddress record
// (if start adress is not zero) + EndOfFile record.
TotalSize = LengthCalc.getBufferOffset() +
(Obj.Entry ? IHexRecord::getLineLength(4) : 0) +
IHexRecord::getLineLength(0);
SizeCalc.writeRecords(Obj.Entry);
// We need to add the size of the Header and Terminator records.
SRecord Header = SRecord::getHeader(OutputFileName);
uint8_t TerminatorType = 10 - SizeCalc.getType();
SRecord Terminator = {TerminatorType, static_cast<uint32_t>(Obj.Entry), {}};
return Header.getSize() + SizeCalc.getBufferOffset() + Terminator.getSize();
}

Buf = WritableMemoryBuffer::getNewMemBuffer(TotalSize);
if (!Buf)
return createStringError(errc::not_enough_memory,
"failed to allocate memory buffer of " +
Twine::utohexstr(TotalSize) + " bytes");
Error SRECWriter::write() {
uint32_t HeaderSize =
writeHeader(reinterpret_cast<uint8_t *>(Buf->getBufferStart()));
SRECSectionWriter Writer(*Buf, HeaderSize);
for (const SectionBase *S : Sections) {
if (Error E = S->accept(Writer))
return E;
}
Writer.writeRecords(Obj.Entry);
uint64_t Offset = Writer.getBufferOffset();

// An S1 record terminates with an S9 record, S2 with S8, and S3 with S7.
uint8_t TerminatorType = 10 - Writer.getType();
Offset += writeTerminator(
reinterpret_cast<uint8_t *>(Buf->getBufferStart() + Offset),
TerminatorType);
assert(Offset == TotalSize);
Out.write(Buf->getBufferStart(), Buf->getBufferSize());
return Error::success();
}

Expand Down
134 changes: 125 additions & 9 deletions llvm/lib/ObjCopy/ELF/ELFObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ template <class ELFT> class ELFSectionSizer : public MutableSectionVisitor {
friend class SectionWriter; \
friend class IHexSectionWriterBase; \
friend class IHexSectionWriter; \
friend class SRECSectionWriter; \
friend class SRECSectionWriterBase; \
friend class SRECSizeCalculator; \
template <class ELFT> friend class ELFSectionWriter; \
template <class ELFT> friend class ELFSectionSizer;

Expand Down Expand Up @@ -371,23 +374,136 @@ class BinaryWriter : public Writer {
: Writer(Obj, Out), GapFill(Config.GapFill), PadTo(Config.PadTo) {}
};

class IHexWriter : public Writer {
struct SectionCompare {
bool operator()(const SectionBase *Lhs, const SectionBase *Rhs) const;
};
// A base class for writing ascii hex formats such as srec and ihex.
class ASCIIHexWriter : public Writer {
public:
ASCIIHexWriter(Object &Obj, raw_ostream &OS, StringRef OutputFile)
: Writer(Obj, OS), OutputFileName(OutputFile) {}
Error finalize() override;

std::set<const SectionBase *, SectionCompare> Sections;
protected:
StringRef OutputFileName;
size_t TotalSize = 0;
std::vector<const SectionBase *> Sections;

Error checkSection(const SectionBase &S) const;
virtual Expected<size_t>
getTotalSize(WritableMemoryBuffer &EmptyBuffer) const = 0;
};

class IHexWriter : public ASCIIHexWriter {
public:
Error write() override;
IHexWriter(Object &Obj, raw_ostream &Out, StringRef OutputFile)
: ASCIIHexWriter(Obj, Out, OutputFile) {}

Error checkSection(const SectionBase &Sec);
private:
uint64_t writeEntryPointRecord(uint8_t *Buf);
uint64_t writeEndOfFileRecord(uint8_t *Buf);
Expected<size_t>
getTotalSize(WritableMemoryBuffer &EmptyBuffer) const override;
};

class SRECWriter : public ASCIIHexWriter {
public:
~IHexWriter() {}
Error finalize() override;
SRECWriter(Object &Obj, raw_ostream &OS, StringRef OutputFile)
: ASCIIHexWriter(Obj, OS, OutputFile) {}
Error write() override;
IHexWriter(Object &Obj, raw_ostream &Out) : Writer(Obj, Out) {}

private:
size_t writeHeader(uint8_t *Buf);
size_t writeTerminator(uint8_t *Buf, uint8_t Type);
Expected<size_t>
getTotalSize(WritableMemoryBuffer &EmptyBuffer) const override;
};

using SRecLineData = SmallVector<char, 64>;
struct SRecord {
uint8_t Type;
uint32_t Address;
ArrayRef<uint8_t> Data;
SRecLineData toString() const;
uint8_t getCount() const;
// Get address size in characters.
uint8_t getAddressSize() const;
uint8_t getChecksum() const;
size_t getSize() const;
static SRecord getHeader(StringRef FileName);
static uint8_t getType(uint32_t Address);

enum Type : uint8_t {
// Vendor specific text comment.
S0 = 0,
// Data that starts at a 16 bit address.
S1 = 1,
// Data that starts at a 24 bit address.
S2 = 2,
// Data that starts at a 32 bit address.
S3 = 3,
// Reserved.
S4 = 4,
// 16 bit count of S1/S2/S3 records (optional).
S5 = 5,
// 32 bit count of S1/S2/S3 records (optional).
S6 = 6,
// Terminates a series of S3 records.
S7 = 7,
// Terminates a series of S2 records.
S8 = 8,
// Terminates a series of S1 records.
S9 = 9
};
};

class SRECSectionWriterBase : public BinarySectionWriter {
public:
explicit SRECSectionWriterBase(WritableMemoryBuffer &Buf,
uint64_t StartOffset)
: BinarySectionWriter(Buf), Offset(StartOffset), HeaderSize(StartOffset) {
}

using BinarySectionWriter::visit;

void writeRecords(uint32_t Entry);
uint64_t getBufferOffset() const { return Offset; }
Error visit(const Section &S) override;
Error visit(const OwnedDataSection &S) override;
Error visit(const StringTableSection &S) override;
Error visit(const DynamicRelocationSection &S) override;
uint8_t getType() const { return Type; };

protected:
// Offset in the output buffer.
uint64_t Offset;
// Sections start after the header.
uint64_t HeaderSize;
// Type of records to write.
uint8_t Type = SRecord::S1;
std::vector<SRecord> Records;

void writeSection(const SectionBase &S, ArrayRef<uint8_t> Data);
virtual void writeRecord(SRecord &Record, uint64_t Off) = 0;
};

// An SRECSectionWriterBase that visits sections but does not write anything.
// This class is only used to calculate the size of the output file.
class SRECSizeCalculator : public SRECSectionWriterBase {
public:
SRECSizeCalculator(WritableMemoryBuffer &EmptyBuffer, uint64_t Offset)
: SRECSectionWriterBase(EmptyBuffer, Offset) {}

protected:
void writeRecord(SRecord &Record, uint64_t Off) override {}
};

class SRECSectionWriter : public SRECSectionWriterBase {
public:
SRECSectionWriter(WritableMemoryBuffer &Buf, uint64_t Offset)
: SRECSectionWriterBase(Buf, Offset) {}
Error visit(const StringTableSection &Sec) override;

protected:
void writeRecord(SRecord &Record, uint64_t Off) override;
};

class SectionBase {
Expand Down
232 changes: 145 additions & 87 deletions llvm/lib/ObjectYAML/XCOFFEmitter.cpp

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion llvm/lib/Passes/PassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,6 @@
#include "llvm/Transforms/Scalar/LoopLoadElimination.h"
#include "llvm/Transforms/Scalar/LoopPassManager.h"
#include "llvm/Transforms/Scalar/LoopPredication.h"
#include "llvm/Transforms/Scalar/LoopReroll.h"
#include "llvm/Transforms/Scalar/LoopRotation.h"
#include "llvm/Transforms/Scalar/LoopSimplifyCFG.h"
#include "llvm/Transforms/Scalar/LoopSink.h"
Expand Down
1 change: 0 additions & 1 deletion llvm/lib/Passes/PassRegistry.def
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,6 @@ LOOP_PASS("loop-idiom", LoopIdiomRecognizePass())
LOOP_PASS("loop-instsimplify", LoopInstSimplifyPass())
LOOP_PASS("loop-predication", LoopPredicationPass())
LOOP_PASS("loop-reduce", LoopStrengthReducePass())
LOOP_PASS("loop-reroll", LoopRerollPass())
LOOP_PASS("loop-simplifycfg", LoopSimplifyCFGPass())
LOOP_PASS("loop-unroll-full", LoopFullUnrollPass())
LOOP_PASS("loop-versioning-licm", LoopVersioningLICMPass())
Expand Down
87 changes: 40 additions & 47 deletions llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,39 @@ bool AArch64ExpandPseudo::expandSVESpillFill(MachineBasicBlock &MBB,
return true;
}

// Create a call to CallTarget, copying over all the operands from *MBBI,
// starting at the regmask.
static MachineInstr *createCall(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
const AArch64InstrInfo *TII,
MachineOperand &CallTarget,
unsigned RegMaskStartIdx) {
unsigned Opc = CallTarget.isGlobal() ? AArch64::BL : AArch64::BLR;
MachineInstr *Call =
BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(Opc)).getInstr();

assert((CallTarget.isGlobal() || CallTarget.isReg()) &&
"invalid operand for regular call");
Call->addOperand(CallTarget);

// Register arguments are added during ISel, but cannot be added as explicit
// operands of the branch as it expects to be B <target> which is only one
// operand. Instead they are implicit operands used by the branch.
while (!MBBI->getOperand(RegMaskStartIdx).isRegMask()) {
auto MOP = MBBI->getOperand(RegMaskStartIdx);
assert(MOP.isReg() && "can only add register operands");
Call->addOperand(MachineOperand::CreateReg(
MOP.getReg(), /*Def=*/false, /*Implicit=*/true, /*isKill=*/false,
/*isDead=*/false, /*isUndef=*/MOP.isUndef()));
RegMaskStartIdx++;
}
for (const MachineOperand &MO :
llvm::drop_begin(MBBI->operands(), RegMaskStartIdx))
Call->addOperand(MO);

return Call;
}

bool AArch64ExpandPseudo::expandCALL_RVMARKER(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) {
// Expand CALL_RVMARKER pseudo to:
Expand All @@ -782,31 +815,12 @@ bool AArch64ExpandPseudo::expandCALL_RVMARKER(
// - another branch, to the runtime function
// Mark the sequence as bundle, to avoid passes moving other code in between.
MachineInstr &MI = *MBBI;

MachineInstr *OriginalCall;
MachineOperand &RVTarget = MI.getOperand(0);
MachineOperand &CallTarget = MI.getOperand(1);
assert((CallTarget.isGlobal() || CallTarget.isReg()) &&
"invalid operand for regular call");
assert(RVTarget.isGlobal() && "invalid operand for attached call");
unsigned Opc = CallTarget.isGlobal() ? AArch64::BL : AArch64::BLR;
OriginalCall = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(Opc)).getInstr();
OriginalCall->addOperand(CallTarget);

unsigned RegMaskStartIdx = 2;
// Skip register arguments. Those are added during ISel, but are not
// needed for the concrete branch.
while (!MI.getOperand(RegMaskStartIdx).isRegMask()) {
auto MOP = MI.getOperand(RegMaskStartIdx);
assert(MOP.isReg() && "can only add register operands");
OriginalCall->addOperand(MachineOperand::CreateReg(
MOP.getReg(), /*Def=*/false, /*Implicit=*/true, /*isKill=*/false,
/*isDead=*/false, /*isUndef=*/MOP.isUndef()));
RegMaskStartIdx++;
}
for (const MachineOperand &MO :
llvm::drop_begin(MI.operands(), RegMaskStartIdx))
OriginalCall->addOperand(MO);
MachineInstr *OriginalCall =
createCall(MBB, MBBI, TII, MI.getOperand(1),
// Regmask starts after the RV and call targets.
/*RegMaskStartIdx=*/2);

BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ORRXrs))
.addReg(AArch64::FP, RegState::Define)
Expand Down Expand Up @@ -834,31 +848,10 @@ bool AArch64ExpandPseudo::expandCALL_BTI(MachineBasicBlock &MBB,
// - a BTI instruction
// Mark the sequence as a bundle, to avoid passes moving other code in
// between.

MachineInstr &MI = *MBBI;
MachineOperand &CallTarget = MI.getOperand(0);
assert((CallTarget.isGlobal() || CallTarget.isReg()) &&
"invalid operand for regular call");
unsigned Opc = CallTarget.isGlobal() ? AArch64::BL : AArch64::BLR;
MachineInstr *Call =
BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(Opc)).getInstr();
Call->addOperand(CallTarget);

// 1 because we already added the branch target above.
unsigned RegMaskStartIdx = 1;
// The branch is BL <target>, so we cannot attach the arguments of the called
// function to it. Those must be added as implicitly used by the branch.
while (!MI.getOperand(RegMaskStartIdx).isRegMask()) {
auto MOP = MI.getOperand(RegMaskStartIdx);
assert(MOP.isReg() && "can only add register operands");
Call->addOperand(MachineOperand::CreateReg(
MOP.getReg(), /*Def=*/false, /*Implicit=*/true, /*isKill=*/false,
/*isDead=*/false, /*isUndef=*/MOP.isUndef()));
RegMaskStartIdx++;
}
for (const MachineOperand &MO :
llvm::drop_begin(MI.operands(), RegMaskStartIdx))
Call->addOperand(MO);
MachineInstr *Call = createCall(MBB, MBBI, TII, MI.getOperand(0),
// Regmask starts after the call target.
/*RegMaskStartIdx=*/1);

Call->setCFIType(*MBB.getParent(), MI.getCFIType());

Expand Down
108 changes: 41 additions & 67 deletions llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,8 +379,7 @@ class PrologEpilogSGPRSpillBuilder {
} // namespace llvm

// Emit flat scratch setup code, assuming `MFI->hasFlatScratchInit()`
// and return the FlatScratchInit Register used
Register SIFrameLowering::emitEntryFunctionFlatScratchInit(
void SIFrameLowering::emitEntryFunctionFlatScratchInit(
MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
const DebugLoc &DL, Register ScratchWaveOffsetReg) const {
const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
Expand All @@ -400,7 +399,6 @@ Register SIFrameLowering::emitEntryFunctionFlatScratchInit(

Register FlatScrInitLo;
Register FlatScrInitHi;
Register FlatScratchInitReg;

if (ST.isAmdPalOS()) {
// Extract the scratch offset from the descriptor in the GIT
Expand All @@ -410,6 +408,7 @@ Register SIFrameLowering::emitEntryFunctionFlatScratchInit(

// Find unused reg to load flat scratch init into
MachineRegisterInfo &MRI = MF.getRegInfo();
Register FlatScrInit = AMDGPU::NoRegister;
ArrayRef<MCPhysReg> AllSGPR64s = TRI->getAllSGPR64(MF);
unsigned NumPreloaded = (MFI->getNumPreloadedSGPRs() + 1) / 2;
AllSGPR64s = AllSGPR64s.slice(
Expand All @@ -418,28 +417,16 @@ Register SIFrameLowering::emitEntryFunctionFlatScratchInit(
for (MCPhysReg Reg : AllSGPR64s) {
if (LiveUnits.available(Reg) && !MRI.isReserved(Reg) &&
MRI.isAllocatable(Reg) && !TRI->isSubRegisterEq(Reg, GITPtrLoReg)) {
FlatScratchInitReg = Reg;
FlatScrInit = Reg;
break;
}
}
assert(FlatScrInit && "Failed to find free register for scratch init");

} else {
FlatScratchInitReg =
MFI->getPreloadedReg(AMDGPUFunctionArgInfo::FLAT_SCRATCH_INIT);

MachineRegisterInfo &MRI = MF.getRegInfo();
MRI.addLiveIn(FlatScratchInitReg);
MBB.addLiveIn(FlatScratchInitReg);
}

assert(FlatScratchInitReg && "Failed to find free register for scratch init");

FlatScrInitLo = TRI->getSubReg(FlatScratchInitReg, AMDGPU::sub0);
FlatScrInitHi = TRI->getSubReg(FlatScratchInitReg, AMDGPU::sub1);

if (ST.isAmdPalOS()) {
FlatScrInitLo = TRI->getSubReg(FlatScrInit, AMDGPU::sub0);
FlatScrInitHi = TRI->getSubReg(FlatScrInit, AMDGPU::sub1);

buildGitPtr(MBB, I, DL, TII, FlatScratchInitReg);
buildGitPtr(MBB, I, DL, TII, FlatScrInit);

// We now have the GIT ptr - now get the scratch descriptor from the entry
// at offset 0 (or offset 16 for a compute shader).
Expand All @@ -454,18 +441,29 @@ Register SIFrameLowering::emitEntryFunctionFlatScratchInit(
MF.getFunction().getCallingConv() == CallingConv::AMDGPU_CS ? 16 : 0;
const GCNSubtarget &Subtarget = MF.getSubtarget<GCNSubtarget>();
unsigned EncodedOffset = AMDGPU::convertSMRDOffsetUnits(Subtarget, Offset);
BuildMI(MBB, I, DL, LoadDwordX2, FlatScratchInitReg)
.addReg(FlatScratchInitReg)
BuildMI(MBB, I, DL, LoadDwordX2, FlatScrInit)
.addReg(FlatScrInit)
.addImm(EncodedOffset) // offset
.addImm(0) // cpol
.addMemOperand(MMO);

// Mask the offset in [47:0] of the descriptor
const MCInstrDesc &SAndB32 = TII->get(AMDGPU::S_AND_B32);
auto And = BuildMI(MBB, I, DL, SAndB32, FlatScrInitHi)
.addReg(FlatScrInitHi)
.addImm(0xffff);
.addReg(FlatScrInitHi)
.addImm(0xffff);
And->getOperand(3).setIsDead(); // Mark SCC as dead.
} else {
Register FlatScratchInitReg =
MFI->getPreloadedReg(AMDGPUFunctionArgInfo::FLAT_SCRATCH_INIT);
assert(FlatScratchInitReg);

MachineRegisterInfo &MRI = MF.getRegInfo();
MRI.addLiveIn(FlatScratchInitReg);
MBB.addLiveIn(FlatScratchInitReg);

FlatScrInitLo = TRI->getSubReg(FlatScratchInitReg, AMDGPU::sub0);
FlatScrInitHi = TRI->getSubReg(FlatScratchInitReg, AMDGPU::sub1);
}

// Do a 64-bit pointer add.
Expand All @@ -488,21 +486,20 @@ Register SIFrameLowering::emitEntryFunctionFlatScratchInit(
addReg(FlatScrInitHi).
addImm(int16_t(AMDGPU::Hwreg::ID_FLAT_SCR_HI |
(31 << AMDGPU::Hwreg::WIDTH_M1_SHIFT_)));
return FlatScratchInitReg;
return;
}

assert(ST.getGeneration() == AMDGPUSubtarget::GFX9);

// For GFX9.
BuildMI(MBB, I, DL, TII->get(AMDGPU::S_ADD_U32), AMDGPU::FLAT_SCR_LO)
.addReg(FlatScrInitLo)
.addReg(ScratchWaveOffsetReg);
.addReg(FlatScrInitLo)
.addReg(ScratchWaveOffsetReg);
auto Addc = BuildMI(MBB, I, DL, TII->get(AMDGPU::S_ADDC_U32),
AMDGPU::FLAT_SCR_HI)
.addReg(FlatScrInitHi)
.addImm(0);
Addc->getOperand(3).setIsDead(); // Mark SCC as dead.

return AMDGPU::FLAT_SCR;
return;
}

assert(ST.getGeneration() < AMDGPUSubtarget::GFX9);
Expand All @@ -523,7 +520,6 @@ Register SIFrameLowering::emitEntryFunctionFlatScratchInit(
.addReg(FlatScrInitLo, RegState::Kill)
.addImm(8);
LShr->getOperand(3).setIsDead(); // Mark SCC as dead.
return AMDGPU::FLAT_SCR;
}

// Note SGPRSpill stack IDs should only be used for SGPR spilling to VGPRs, not
Expand Down Expand Up @@ -615,15 +611,11 @@ void SIFrameLowering::emitEntryFunctionPrologue(MachineFunction &MF,
const SIInstrInfo *TII = ST.getInstrInfo();
const SIRegisterInfo *TRI = &TII->getRegisterInfo();
MachineRegisterInfo &MRI = MF.getRegInfo();
const Function &F = MF.getFunction();
MachineFrameInfo &FrameInfo = MF.getFrameInfo();

assert(MFI->isEntryFunction());

bool NeedsFlatScratchInit =
MFI->getUserSGPRInfo().hasFlatScratchInit() &&
(MRI.isPhysRegUsed(AMDGPU::FLAT_SCR) || FrameInfo.hasCalls() ||
(!allStackObjectsAreDead(FrameInfo) && ST.enableFlatScratch()));

Register PreloadedScratchWaveOffsetReg = MFI->getPreloadedReg(
AMDGPUFunctionArgInfo::PRIVATE_SEGMENT_WAVE_BYTE_OFFSET);

Expand All @@ -649,7 +641,7 @@ void SIFrameLowering::emitEntryFunctionPrologue(MachineFunction &MF,
// Now that we have fixed the reserved SRSRC we need to locate the
// (potentially) preloaded SRSRC.
Register PreloadedScratchRsrcReg;
if (ST.isAmdHsaOrMesa(MF.getFunction()) && !NeedsFlatScratchInit) {
if (ST.isAmdHsaOrMesa(F)) {
PreloadedScratchRsrcReg =
MFI->getPreloadedReg(AMDGPUFunctionArgInfo::PRIVATE_SEGMENT_BUFFER);
if (ScratchRsrcReg && PreloadedScratchRsrcReg) {
Expand Down Expand Up @@ -705,30 +697,33 @@ void SIFrameLowering::emitEntryFunctionPrologue(MachineFunction &MF,
BuildMI(MBB, I, DL, TII->get(AMDGPU::S_MOV_B32), FPReg).addImm(0);
}

bool NeedsFlatScratchInit =
MFI->getUserSGPRInfo().hasFlatScratchInit() &&
(MRI.isPhysRegUsed(AMDGPU::FLAT_SCR) || FrameInfo.hasCalls() ||
(!allStackObjectsAreDead(FrameInfo) && ST.enableFlatScratch()));

if ((NeedsFlatScratchInit || ScratchRsrcReg) &&
PreloadedScratchWaveOffsetReg && !ST.flatScratchIsArchitected()) {
MRI.addLiveIn(PreloadedScratchWaveOffsetReg);
MBB.addLiveIn(PreloadedScratchWaveOffsetReg);
}

Register FlatScratchInit;
if (NeedsFlatScratchInit) {
FlatScratchInit =
emitEntryFunctionFlatScratchInit(MF, MBB, I, DL, ScratchWaveOffsetReg);
emitEntryFunctionFlatScratchInit(MF, MBB, I, DL, ScratchWaveOffsetReg);
}

if (ScratchRsrcReg) {
emitEntryFunctionScratchRsrcRegSetup(
MF, MBB, I, DL, FlatScratchInit, ScratchRsrcReg,
PreloadedScratchRsrcReg, ScratchWaveOffsetReg);
emitEntryFunctionScratchRsrcRegSetup(MF, MBB, I, DL,
PreloadedScratchRsrcReg,
ScratchRsrcReg, ScratchWaveOffsetReg);
}
}

// Emit scratch RSRC setup code, assuming `ScratchRsrcReg != AMDGPU::NoReg`
void SIFrameLowering::emitEntryFunctionScratchRsrcRegSetup(
MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
const DebugLoc &DL, Register FlatScratchInit, Register ScratchRsrcReg,
Register PreloadedScratchRsrcReg, Register ScratchWaveOffsetReg) const {
const DebugLoc &DL, Register PreloadedScratchRsrcReg,
Register ScratchRsrcReg, Register ScratchWaveOffsetReg) const {

const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
const SIInstrInfo *TII = ST.getInstrInfo();
Expand Down Expand Up @@ -776,8 +771,7 @@ void SIFrameLowering::emitEntryFunctionScratchRsrcRegSetup(
.addImm(21)
.addReg(Rsrc03);
}
} else if (ST.isMesaGfxShader(Fn) ||
(!FlatScratchInit.isValid() && !PreloadedScratchRsrcReg)) {
} else if (ST.isMesaGfxShader(Fn) || !PreloadedScratchRsrcReg) {
assert(!ST.isAmdHsaOrMesa(Fn));
const MCInstrDesc &SMovB32 = TII->get(AMDGPU::S_MOV_B32);

Expand Down Expand Up @@ -836,26 +830,6 @@ void SIFrameLowering::emitEntryFunctionScratchRsrcRegSetup(
.addImm(Rsrc23 >> 32)
.addReg(ScratchRsrcReg, RegState::ImplicitDefine);
} else if (ST.isAmdHsaOrMesa(Fn)) {

if (FlatScratchInit) {
const MCInstrDesc &SMovB32 = TII->get(AMDGPU::S_MOV_B32);
Register Lo_32 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub2);
Register Hi_32 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub3);
uint64_t Rsrc23 = TII->getScratchRsrcWords23();
I = BuildMI(MBB, I, DL, TII->get(AMDGPU::COPY),
TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub0_sub1))
.addReg(FlatScratchInit)
.addReg(ScratchRsrcReg, RegState::ImplicitDefine);
BuildMI(MBB, I, DL, SMovB32, Lo_32)
.addImm(Rsrc23 & 0xffffffff)
.addReg(ScratchRsrcReg, RegState::ImplicitDefine);

BuildMI(MBB, I, DL, SMovB32, Hi_32)
.addImm(Rsrc23 >> 32)
.addReg(ScratchRsrcReg, RegState::ImplicitDefine);
return;
}

assert(PreloadedScratchRsrcReg);

if (ScratchRsrcReg != PreloadedScratchRsrcReg) {
Expand Down
14 changes: 7 additions & 7 deletions llvm/lib/Target/AMDGPU/SIFrameLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,19 @@ class SIFrameLowering final : public AMDGPUFrameLowering {
MachineBasicBlock::iterator MI) const override;

private:
Register
emitEntryFunctionFlatScratchInit(MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
const DebugLoc &DL,
Register ScratchWaveOffsetReg) const;
void emitEntryFunctionFlatScratchInit(MachineFunction &MF,
MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
const DebugLoc &DL,
Register ScratchWaveOffsetReg) const;

Register getEntryFunctionReservedScratchRsrcReg(MachineFunction &MF) const;

void emitEntryFunctionScratchRsrcRegSetup(
MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I, const DebugLoc &DL,
Register FlatScratchInit, Register ScratchRsrcReg,
Register PreloadedScratchRsrcReg, Register ScratchWaveOffsetReg) const;
Register PreloadedPrivateBufferReg, Register ScratchRsrcReg,
Register ScratchWaveOffsetReg) const;

public:
bool hasFP(const MachineFunction &MF) const override;
Expand Down
12 changes: 4 additions & 8 deletions llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -552,14 +552,10 @@ int SIMachineFunctionInfo::getScavengeFI(MachineFrameInfo &MFI,
const SIRegisterInfo &TRI) {
if (ScavengeFI)
return *ScavengeFI;
if (isBottomOfStack()) {
ScavengeFI = MFI.CreateFixedObject(
TRI.getSpillSize(AMDGPU::SGPR_32RegClass), 0, false);
} else {
ScavengeFI = MFI.CreateStackObject(
TRI.getSpillSize(AMDGPU::SGPR_32RegClass),
TRI.getSpillAlign(AMDGPU::SGPR_32RegClass), false);
}

ScavengeFI =
MFI.CreateStackObject(TRI.getSpillSize(AMDGPU::SGPR_32RegClass),
TRI.getSpillAlign(AMDGPU::SGPR_32RegClass), false);
return *ScavengeFI;
}

Expand Down
3 changes: 0 additions & 3 deletions llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2287,9 +2287,6 @@ bool SIRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
if (FrameReg)
FIOp.ChangeToRegister(FrameReg, false);

if (!Offset)
return false;

MachineOperand *OffsetOp =
TII->getNamedOperand(*MI, AMDGPU::OpName::offset);
int64_t NewOffset = Offset + OffsetOp->getImm();
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/Target/Hexagon/HexagonOptAddrMode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ static cl::opt<int> CodeGrowthLimit("hexagon-amode-growth-limit",
cl::Hidden, cl::init(0), cl::desc("Code growth limit for address mode "
"optimization"));

extern cl::opt<unsigned> RDFFuncBlockLimit;

namespace llvm {

FunctionPass *createHexagonOptAddrMode();
Expand Down Expand Up @@ -856,6 +858,14 @@ bool HexagonOptAddrMode::runOnMachineFunction(MachineFunction &MF) {
if (skipFunction(MF.getFunction()))
return false;

// Perform RDF optimizations only if number of basic blocks in the
// function is less than the limit
if (MF.size() > RDFFuncBlockLimit) {
LLVM_DEBUG(dbgs() << "Skipping " << getPassName()
<< ": too many basic blocks\n");
return false;
}

bool Changed = false;
auto &HST = MF.getSubtarget<HexagonSubtarget>();
MRI = &MF.getRegInfo();
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/Target/Hexagon/HexagonRDFOpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ static unsigned RDFCount = 0;
static cl::opt<unsigned>
RDFLimit("hexagon-rdf-limit",
cl::init(std::numeric_limits<unsigned>::max()));

extern cl::opt<unsigned> RDFFuncBlockLimit;

static cl::opt<bool> RDFDump("hexagon-rdf-dump", cl::Hidden);
static cl::opt<bool> RDFTrackReserved("hexagon-rdf-track-reserved", cl::Hidden);

Expand Down Expand Up @@ -285,6 +288,14 @@ bool HexagonRDFOpt::runOnMachineFunction(MachineFunction &MF) {
if (skipFunction(MF.getFunction()))
return false;

// Perform RDF optimizations only if number of basic blocks in the
// function is less than the limit
if (MF.size() > RDFFuncBlockLimit) {
if (RDFDump)
dbgs() << "Skipping " << getPassName() << ": too many basic blocks\n";
return false;
}

if (RDFLimit.getPosition()) {
if (RDFCount >= RDFLimit)
return false;
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ static cl::opt<bool>
static cl::opt<bool> EnableRDFOpt("rdf-opt", cl::Hidden, cl::init(true),
cl::desc("Enable RDF-based optimizations"));

cl::opt<unsigned> RDFFuncBlockLimit(
"rdf-bb-limit", cl::Hidden, cl::init(1000),
cl::desc("Basic block limit for a function for RDF optimizations"));

static cl::opt<bool> DisableHardwareLoops("disable-hexagon-hwloops",
cl::Hidden, cl::desc("Disable Hardware Loops for Hexagon target"));

Expand Down
70 changes: 17 additions & 53 deletions llvm/lib/Target/NVPTX/NVVMReflect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ static bool runNVVMReflect(Function &F, unsigned SmVersion) {
}

SmallVector<Instruction *, 4> ToRemove;
SmallVector<ICmpInst *, 4> ToSimplify;
SmallVector<Instruction *, 4> ToSimplify;

// Go through the calls in this function. Each call to __nvvm_reflect or
// llvm.nvvm.reflect should be a CallInst with a ConstantArray argument.
Expand Down Expand Up @@ -177,9 +177,8 @@ static bool runNVVMReflect(Function &F, unsigned SmVersion) {
}

// If the immediate user is a simple comparison we want to simplify it.
// TODO: This currently does not handle switch instructions.
for (User *U : Call->users())
if (ICmpInst *I = dyn_cast<ICmpInst>(U))
if (Instruction *I = dyn_cast<Instruction>(U))
ToSimplify.push_back(I);

Call->replaceAllUsesWith(ConstantInt::get(Call->getType(), ReflectVal));
Expand All @@ -190,56 +189,21 @@ static bool runNVVMReflect(Function &F, unsigned SmVersion) {
I->eraseFromParent();

// The code guarded by __nvvm_reflect may be invalid for the target machine.
// We need to do some basic dead code elimination to trim invalid code before
// it reaches the backend at all optimization levels.
SmallVector<BranchInst *> Simplified;
for (ICmpInst *Cmp : ToSimplify) {
Constant *LHS = dyn_cast<Constant>(Cmp->getOperand(0));
Constant *RHS = dyn_cast<Constant>(Cmp->getOperand(1));

if (!LHS || !RHS)
continue;

// If the comparison is a compile time constant we simply propagate it.
Constant *C = ConstantFoldCompareInstOperands(
Cmp->getPredicate(), LHS, RHS, Cmp->getModule()->getDataLayout());

if (!C)
continue;

for (User *U : Cmp->users())
if (BranchInst *I = dyn_cast<BranchInst>(U))
Simplified.push_back(I);

Cmp->replaceAllUsesWith(C);
Cmp->eraseFromParent();
}

// Each instruction here is a conditional branch off of a constant true or
// false value. Simply replace it with an unconditional branch to the
// appropriate basic block and delete the rest if it is trivially dead.
DenseSet<Instruction *> Removed;
for (BranchInst *Branch : Simplified) {
if (Removed.contains(Branch))
continue;

ConstantInt *C = dyn_cast<ConstantInt>(Branch->getCondition());
if (!C || (!C->isOne() && !C->isZero()))
continue;

BasicBlock *TrueBB =
C->isOne() ? Branch->getSuccessor(0) : Branch->getSuccessor(1);
BasicBlock *FalseBB =
C->isOne() ? Branch->getSuccessor(1) : Branch->getSuccessor(0);

// This transformation is only correct on simple edges.
if (!FalseBB->hasNPredecessors(1))
continue;

ReplaceInstWithInst(Branch, BranchInst::Create(TrueBB));
if (FalseBB->use_empty() && !FalseBB->getFirstNonPHIOrDbg()) {
Removed.insert(FalseBB->getFirstNonPHIOrDbg());
changeToUnreachable(FalseBB->getFirstNonPHIOrDbg());
// Traverse the use-def chain, continually simplifying constant expressions
// until we find a terminator that we can then remove.
while (!ToSimplify.empty()) {
Instruction *I = ToSimplify.pop_back_val();
if (Constant *C =
ConstantFoldInstruction(I, F.getParent()->getDataLayout())) {
for (User *U : I->users())
if (Instruction *I = dyn_cast<Instruction>(U))
ToSimplify.push_back(I);

I->replaceAllUsesWith(C);
if (isInstructionTriviallyDead(I))
I->eraseFromParent();
} else if (I->isTerminator()) {
ConstantFoldTerminator(I->getParent());
}
}

Expand Down
4 changes: 1 addition & 3 deletions llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1003,9 +1003,7 @@ void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF,
};

for (auto Reg : CSRegs)
// Only save x0-x15 for RVE.
if (Reg < RISCV::X16 || !Subtarget.isRVE())
SavedRegs.set(Reg);
SavedRegs.set(Reg);

// According to psABI, if ilp32e/lp64e ABIs are used with an ISA that
// has any of the registers x16-x31 and f0-f31, then these registers are
Expand Down
Loading