diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index 49fef4298bfecd..f6cead412236da 100644 --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -491,6 +491,7 @@ SanitizerMask toolchains::MinGW::getSupportedSanitizers() const { Res |= SanitizerKind::Address; Res |= SanitizerKind::PointerCompare; Res |= SanitizerKind::PointerSubtract; + Res |= SanitizerKind::Vptr; return Res; } diff --git a/clang/test/Analysis/scan-build/cxx-name.test b/clang/test/Analysis/scan-build/cxx-name.test new file mode 100644 index 00000000000000..483762d619d178 --- /dev/null +++ b/clang/test/Analysis/scan-build/cxx-name.test @@ -0,0 +1,9 @@ +REQUIRES: shell + +RUN: %scan-build sh -c 'echo "CLANG_CXX=/$(basename "$CLANG_CXX")/"' | FileCheck %s + +Check that scan-build sets the CLANG_CXX environment variable (meant to be +consumed by ccc-analyzer) to an appropriate pathname for the clang++ executable, +derived from the pathname of the clang executable: + +CHECK: CLANG_CXX=/clang++{{(\.exe)?}}/ diff --git a/clang/test/Analysis/scan-build/lit.local.cfg b/clang/test/Analysis/scan-build/lit.local.cfg index b4e097d4bab9e2..09ed9217147861 100644 --- a/clang/test/Analysis/scan-build/lit.local.cfg +++ b/clang/test/Analysis/scan-build/lit.local.cfg @@ -15,4 +15,4 @@ config.substitutions.append(('%scan-build', 'tools', 'scan-build', 'bin')), - config.clang))) + os.path.realpath(config.clang)))) diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c index 0ecf656f292c01..8926d55a0cf4fe 100644 --- a/clang/test/Driver/fsanitize.c +++ b/clang/test/Driver/fsanitize.c @@ -15,16 +15,17 @@ // RUN: %clang -target x86_64-apple-darwin10 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-DARWIN // CHECK-UNDEFINED-DARWIN: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){18}"}} -// RUN: %clang -target i386-pc-win32 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-WIN --check-prefix=CHECK-UNDEFINED-WIN32 -// RUN: %clang -target i386-pc-win32 -fsanitize=undefined -x c++ %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-WIN --check-prefix=CHECK-UNDEFINED-WIN32 --check-prefix=CHECK-UNDEFINED-WIN-CXX -// RUN: %clang -target x86_64-pc-win32 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-WIN --check-prefix=CHECK-UNDEFINED-WIN64 +// RUN: %clang -target i386-pc-win32 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-WIN --check-prefix=CHECK-UNDEFINED-WIN32 --check-prefix=CHECK-UNDEFINED-MSVC +// RUN: %clang -target i386-pc-win32 -fsanitize=undefined -x c++ %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-WIN --check-prefix=CHECK-UNDEFINED-WIN32 --check-prefix=CHECK-UNDEFINED-WIN-CXX --check-prefix=CHECK-UNDEFINED-MSVC +// RUN: %clang -target x86_64-pc-win32 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-WIN --check-prefix=CHECK-UNDEFINED-WIN64 --check-prefix=CHECK-UNDEFINED-MSVC // RUN: %clang -target x86_64-w64-mingw32 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-WIN --check-prefix=CHECK-UNDEFINED-WIN64-MINGW -// RUN: %clang -target x86_64-pc-win32 -fsanitize=undefined -x c++ %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-WIN --check-prefix=CHECK-UNDEFINED-WIN64 --check-prefix=CHECK-UNDEFINED-WIN-CXX +// RUN: %clang -target x86_64-pc-win32 -fsanitize=undefined -x c++ %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-WIN --check-prefix=CHECK-UNDEFINED-WIN64 --check-prefix=CHECK-UNDEFINED-WIN-CXX --check-prefix=CHECK-UNDEFINED-MSVC // CHECK-UNDEFINED-WIN32: "--dependent-lib={{[^"]*}}ubsan_standalone-i386.lib" // CHECK-UNDEFINED-WIN64: "--dependent-lib={{[^"]*}}ubsan_standalone-x86_64.lib" // CHECK-UNDEFINED-WIN64-MINGW: "--dependent-lib={{[^"]*}}libclang_rt.ubsan_standalone-x86_64.a" // CHECK-UNDEFINED-WIN-CXX: "--dependent-lib={{[^"]*}}ubsan_standalone_cxx{{[^"]*}}.lib" -// CHECK-UNDEFINED-WIN-SAME: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){17}"}} +// CHECK-UNDEFINED-MSVC-SAME: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){17}"}} +// CHECK-UNDEFINED-WIN64-MINGW-SAME: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|vptr),?){18}"}} // RUN: %clang -target i386-pc-win32 -fsanitize-coverage=bb %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-COVERAGE-WIN32 // CHECK-COVERAGE-WIN32: "--dependent-lib={{[^"]*}}ubsan_standalone-i386.lib" diff --git a/clang/test/Driver/mingw-sanitizers.c b/clang/test/Driver/mingw-sanitizers.c index 09f28fea8abf22..701e9107f4850a 100644 --- a/clang/test/Driver/mingw-sanitizers.c +++ b/clang/test/Driver/mingw-sanitizers.c @@ -9,3 +9,5 @@ // ASAN-X86_64: "{{[^"]*}}libclang_rt.asan_dynamic_runtime_thunk-x86_64.a" // ASAN-X86_64: "--require-defined" "__asan_seh_interceptor" // ASAN-X86_64: "--whole-archive" "{{.*}}libclang_rt.asan_dynamic_runtime_thunk-x86_64.a" "--no-whole-archive" + +// RUN: %clang -target x86_64-windows-gnu %s -### -fsanitize=vptr diff --git a/clang/tools/scan-build/bin/scan-build b/clang/tools/scan-build/bin/scan-build index aed8c417b6ccd1..645f5507b6fa07 100755 --- a/clang/tools/scan-build/bin/scan-build +++ b/clang/tools/scan-build/bin/scan-build @@ -1925,7 +1925,7 @@ if ($Clang !~ /\+\+(\.exe)?$/) { $ClangCXX =~ s/.exe$/++.exe/; } else { - $ClangCXX =~ s/\-\d+\.\d+$//; + $ClangCXX =~ s/\-\d+(\.\d+)?$//; $ClangCXX .= "++"; } } diff --git a/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp b/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp index 4f1708ba1901f2..d82b542a020e76 100644 --- a/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp +++ b/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp @@ -12,7 +12,7 @@ #include "sanitizer_common/sanitizer_platform.h" #include "ubsan_platform.h" -#if CAN_SANITIZE_UB && !SANITIZER_WINDOWS +#if CAN_SANITIZE_UB && !defined(_MSC_VER) #include "ubsan_type_hash.h" #include "sanitizer_common/sanitizer_common.h" diff --git a/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp b/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp index 45dcb758ec445a..106fa1b85a558d 100644 --- a/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp +++ b/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp @@ -12,7 +12,7 @@ #include "sanitizer_common/sanitizer_platform.h" #include "ubsan_platform.h" -#if CAN_SANITIZE_UB && SANITIZER_WINDOWS +#if CAN_SANITIZE_UB && defined(_MSC_VER) #include "ubsan_type_hash.h" #include "sanitizer_common/sanitizer_common.h" diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp index 788e31b673aa56..6a259792477c6e 100644 --- a/libcxx/src/filesystem/operations.cpp +++ b/libcxx/src/filesystem/operations.cpp @@ -684,12 +684,14 @@ namespace { ec = capture_errno(); return false; } + read_fd.fd = -1; ofstream out; out.__open(write_fd.fd, ios::binary); if (!out.is_open()) { ec = capture_errno(); return false; } + write_fd.fd = -1; if (in.good() && out.good()) { using InIt = istreambuf_iterator; diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp index e787f5dc1b8b2c..eabd6f92da3c49 100644 --- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp @@ -330,6 +330,7 @@ int main(int, char**) doAppendSourceTest(TC); } for (auto const & TC : LongLHSCases) { + (void)TC; LIBCPP_ONLY(doAppendSourceAllocTest(TC)); LIBCPP_ONLY(doAppendSourceAllocTest(TC)); } diff --git a/libcxx/test/std/input.output/filesystems/class.rec.dir.itr/rec.dir.itr.members/increment.pass.cpp b/libcxx/test/std/input.output/filesystems/class.rec.dir.itr/rec.dir.itr.members/increment.pass.cpp index 60f3c6a7175f5d..679ab5260b9555 100644 --- a/libcxx/test/std/input.output/filesystems/class.rec.dir.itr/rec.dir.itr.members/increment.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/class.rec.dir.itr/rec.dir.itr.members/increment.pass.cpp @@ -260,8 +260,7 @@ TEST_CASE(test_PR35078) perms::group_exec|perms::owner_exec|perms::others_exec, perm_options::remove); - const std::error_code eacess_ec = - std::make_error_code(std::errc::permission_denied); + const std::errc eacess = std::errc::permission_denied; std::error_code ec = GetTestEC(); const recursive_directory_iterator endIt; @@ -287,7 +286,7 @@ TEST_CASE(test_PR35078) ec = GetTestEC(); it.increment(ec); TEST_CHECK(ec); - TEST_CHECK(ec == eacess_ec); + TEST_CHECK(ErrorIs(ec, eacess)); TEST_CHECK(it == endIt); } { @@ -346,8 +345,7 @@ TEST_CASE(test_PR35078_with_symlink) perms::group_exec|perms::owner_exec|perms::others_exec, perm_options::remove); - const std::error_code eacess_ec = - std::make_error_code(std::errc::permission_denied); + const std::errc eacess = std::errc::permission_denied; std::error_code ec = GetTestEC(); const recursive_directory_iterator endIt; @@ -397,7 +395,7 @@ TEST_CASE(test_PR35078_with_symlink) } } else { TEST_CHECK(ec); - TEST_CHECK(ec == eacess_ec); + TEST_CHECK(ErrorIs(ec, eacess)); TEST_CHECK(it == endIt); } } @@ -430,8 +428,7 @@ TEST_CASE(test_PR35078_with_symlink_file) perms::group_exec|perms::owner_exec|perms::others_exec, perm_options::remove); - const std::error_code eacess_ec = - std::make_error_code(std::errc::permission_denied); + const std::errc eacess = std::errc::permission_denied; std::error_code ec = GetTestEC(); const recursive_directory_iterator EndIt; @@ -488,7 +485,7 @@ TEST_CASE(test_PR35078_with_symlink_file) TEST_CHECK(it == EndIt); } else { TEST_CHECK(ec); - TEST_CHECK(ec == eacess_ec); + TEST_CHECK(ErrorIs(ec, eacess)); TEST_CHECK(it == EndIt); } } diff --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.absolute/absolute.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.absolute/absolute.pass.cpp index 335ba06b64aafd..23c18f1e689d9f 100644 --- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.absolute/absolute.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.absolute/absolute.pass.cpp @@ -42,8 +42,8 @@ TEST_CASE(basic_test) } TestCases [] = { {"", cwd / ""}, {"foo", cwd / "foo"}, - {"foo/", cwd / "foo/"}, - {"/already_absolute", "/already_absolute"} + {"foo/", cwd / "foo" / ""}, + {"/already_absolute", cwd.root_path() / "already_absolute"} }; for (auto& TC : TestCases) { std::error_code ec = GetTestEC(); diff --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.copy/copy.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.copy/copy.pass.cpp index 14fc7a4ac2d92e..7f0cc3f39811ba 100644 --- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.copy/copy.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.copy/copy.pass.cpp @@ -286,14 +286,14 @@ TEST_CASE(test_dir_create_symlink) { std::error_code ec = GetTestEC(); fs::copy(dir, dest, copy_options::create_symlinks, ec); - TEST_CHECK(ec == std::make_error_code(std::errc::is_a_directory)); + TEST_CHECK(ErrorIs(ec, std::errc::is_a_directory)); TEST_CHECK(!exists(dest)); TEST_CHECK(!is_symlink(dest)); } { std::error_code ec = GetTestEC(); fs::copy(dir, dest, copy_options::create_symlinks|copy_options::recursive, ec); - TEST_CHECK(ec == std::make_error_code(std::errc::is_a_directory)); + TEST_CHECK(ErrorIs(ec, std::errc::is_a_directory)); TEST_CHECK(!exists(dest)); TEST_CHECK(!is_symlink(dest)); } diff --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.permissions/permissions.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.permissions/permissions.pass.cpp index fe4ddee022a698..d7a8c8a82a82c8 100644 --- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.permissions/permissions.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.permissions/permissions.pass.cpp @@ -172,7 +172,10 @@ TEST_CASE(test_no_resolve_symlink_on_symlink) #endif std::error_code ec = GetTestEC(); permissions(sym, TC.set_perms, TC.opts | perm_options::nofollow, ec); - TEST_CHECK(ec == expected_ec); + if (expected_ec) + TEST_CHECK(ErrorIs(ec, static_cast(expected_ec.value()))); + else + TEST_CHECK(!ec); TEST_CHECK(status(file).permissions() == file_perms); TEST_CHECK(symlink_status(sym).permissions() == expected_link_perms); } diff --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.status/status.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.status/status.pass.cpp index 7aece3196d70b5..8a4e352738e8a7 100644 --- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.status/status.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.status/status.pass.cpp @@ -34,8 +34,7 @@ TEST_CASE(signature_test) TEST_CASE(test_status_not_found) { static_test_env static_env; - const std::error_code expect_ec = - std::make_error_code(std::errc::no_such_file_or_directory); + const std::errc expect_errc = std::errc::no_such_file_or_directory; const path cases[] { static_env.DNE, static_env.BadSymlink @@ -44,7 +43,7 @@ TEST_CASE(test_status_not_found) std::error_code ec = std::make_error_code(std::errc::address_in_use); // test non-throwing overload. file_status st = status(p, ec); - TEST_CHECK(ec == expect_ec); + TEST_CHECK(ErrorIs(ec, expect_errc)); TEST_CHECK(st.type() == file_type::not_found); TEST_CHECK(st.permissions() == perms::unknown); // test throwing overload. It should not throw even though it reports @@ -63,27 +62,24 @@ TEST_CASE(test_status_cannot_resolve) const path sym = env.create_symlink("dir/file", "sym"); permissions(dir, perms::none); - const std::error_code set_ec = - std::make_error_code(std::errc::address_in_use); - const std::error_code perm_ec = - std::make_error_code(std::errc::permission_denied); - const std::error_code name_too_long_ec = - std::make_error_code(std::errc::filename_too_long); + const std::errc set_errc = std::errc::address_in_use; + const std::errc perm_errc = std::errc::permission_denied; + const std::errc name_too_long_errc = std::errc::filename_too_long; struct TestCase { path p; - std::error_code expect_ec; + std::errc expect_errc; } const TestCases[] = { - {file, perm_ec}, - {sym, perm_ec}, - {path(std::string(2500, 'a')), name_too_long_ec} + {file, perm_errc}, + {sym, perm_errc}, + {path(std::string(2500, 'a')), name_too_long_errc} }; for (auto& TC : TestCases) { { // test non-throwing case - std::error_code ec = set_ec; + std::error_code ec = std::make_error_code(set_errc); file_status st = status(TC.p, ec); - TEST_CHECK(ec == TC.expect_ec); + TEST_CHECK(ErrorIs(ec, TC.expect_errc)); TEST_CHECK(st.type() == file_type::none); TEST_CHECK(st.permissions() == perms::unknown); } @@ -94,7 +90,7 @@ TEST_CASE(test_status_cannot_resolve) } catch (filesystem_error const& err) { TEST_CHECK(err.path1() == TC.p); TEST_CHECK(err.path2() == ""); - TEST_CHECK(err.code() == TC.expect_ec); + TEST_CHECK(ErrorIs(err.code(), TC.expect_errc)); } } #endif diff --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.symlink_status/symlink_status.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.symlink_status/symlink_status.pass.cpp index d2116779ba1fe2..1e71bf7a01d5b8 100644 --- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.symlink_status/symlink_status.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.symlink_status/symlink_status.pass.cpp @@ -34,8 +34,7 @@ TEST_CASE(signature_test) TEST_CASE(test_symlink_status_not_found) { static_test_env static_env; - const std::error_code expect_ec = - std::make_error_code(std::errc::no_such_file_or_directory); + const std::errc expect_errc = std::errc::no_such_file_or_directory; const path cases[] { static_env.DNE }; @@ -43,7 +42,7 @@ TEST_CASE(test_symlink_status_not_found) std::error_code ec = std::make_error_code(std::errc::address_in_use); // test non-throwing overload. file_status st = symlink_status(p, ec); - TEST_CHECK(ec == expect_ec); + TEST_CHECK(ErrorIs(ec, expect_errc)); TEST_CHECK(st.type() == file_type::not_found); TEST_CHECK(st.permissions() == perms::unknown); // test throwing overload. It should not throw even though it reports @@ -63,10 +62,8 @@ TEST_CASE(test_symlink_status_cannot_resolve) const path sym_points_in_dir = env.create_symlink("dir/file", "sym"); permissions(dir, perms::none); - const std::error_code set_ec = - std::make_error_code(std::errc::address_in_use); - const std::error_code expect_ec = - std::make_error_code(std::errc::permission_denied); + const std::errc set_errc = std::errc::address_in_use; + const std::errc expect_errc = std::errc::permission_denied; const path fail_cases[] = { file_in_dir, sym_in_dir @@ -74,9 +71,9 @@ TEST_CASE(test_symlink_status_cannot_resolve) for (auto& p : fail_cases) { { // test non-throwing case - std::error_code ec = set_ec; + std::error_code ec = std::make_error_code(set_errc); file_status st = symlink_status(p, ec); - TEST_CHECK(ec == expect_ec); + TEST_CHECK(ErrorIs(ec, expect_errc)); TEST_CHECK(st.type() == file_type::none); TEST_CHECK(st.permissions() == perms::unknown); } @@ -87,7 +84,7 @@ TEST_CASE(test_symlink_status_cannot_resolve) } catch (filesystem_error const& err) { TEST_CHECK(err.path1() == p); TEST_CHECK(err.path2() == ""); - TEST_CHECK(err.code() == expect_ec); + TEST_CHECK(ErrorIs(err.code(), expect_errc)); } } #endif @@ -95,7 +92,7 @@ TEST_CASE(test_symlink_status_cannot_resolve) // Test that a symlink that points into a directory without read perms // can be stat-ed using symlink_status { - std::error_code ec = set_ec; + std::error_code ec = std::make_error_code(set_errc); file_status st = symlink_status(sym_points_in_dir, ec); TEST_CHECK(!ec); TEST_CHECK(st.type() == file_type::symlink); diff --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.temp_dir_path/temp_directory_path.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.temp_dir_path/temp_directory_path.pass.cpp index a0b30e17128d57..c99614267a2113 100644 --- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.temp_dir_path/temp_directory_path.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.temp_dir_path/temp_directory_path.pass.cpp @@ -50,7 +50,7 @@ TEST_CASE(basic_tests) const path dir_perms = env.create_dir("bad_perms_dir"); const path nested_dir = env.create_dir("bad_perms_dir/nested"); permissions(dir_perms, perms::none); - const std::error_code expect_ec = std::make_error_code(std::errc::not_a_directory); + LIBCPP_ONLY(const std::errc expect_errc = std::errc::not_a_directory); struct TestCase { std::string name; path p; @@ -75,7 +75,7 @@ TEST_CASE(basic_tests) PutEnv(TC.name, dne); ec = GetTestEC(); ret = temp_directory_path(ec); - LIBCPP_ONLY(TEST_CHECK(ec == expect_ec)); + LIBCPP_ONLY(TEST_CHECK(ErrorIs(ec, expect_errc))); TEST_CHECK(ec != GetTestEC()); TEST_CHECK(ec); TEST_CHECK(ret == ""); @@ -84,7 +84,7 @@ TEST_CASE(basic_tests) PutEnv(TC.name, file); ec = GetTestEC(); ret = temp_directory_path(ec); - LIBCPP_ONLY(TEST_CHECK(ec == expect_ec)); + LIBCPP_ONLY(TEST_CHECK(ErrorIs(ec, expect_errc))); TEST_CHECK(ec != GetTestEC()); TEST_CHECK(ec); TEST_CHECK(ret == ""); @@ -93,7 +93,7 @@ TEST_CASE(basic_tests) PutEnv(TC.name, nested_dir); ec = GetTestEC(); ret = temp_directory_path(ec); - TEST_CHECK(ec == std::make_error_code(std::errc::permission_denied)); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); TEST_CHECK(ret == ""); // Set the env variable to point to a non-existent dir diff --git a/libcxx/test/support/filesystem_test_helper.h b/libcxx/test/support/filesystem_test_helper.h index 1cf6bff870067e..636eeecb637cde 100644 --- a/libcxx/test/support/filesystem_test_helper.h +++ b/libcxx/test/support/filesystem_test_helper.h @@ -330,7 +330,7 @@ class static_test_env { env_.create_file("dir1/file2", 42); env_.create_file("empty_file"); env_.create_file("non_empty_file", 42); - env_.create_symlink("dir1", "symlink_to_dir", false); + env_.create_symlink("dir1", "symlink_to_dir", false, true); env_.create_symlink("empty_file", "symlink_to_empty_file", false); } @@ -560,8 +560,9 @@ inline std::error_code GetTestEC(unsigned Idx = 0) { inline bool ErrorIsImp(const std::error_code& ec, std::vector const& errors) { + std::error_condition cond = ec.default_error_condition(); for (auto errc : errors) { - if (ec == std::make_error_code(errc)) + if (cond.value() == static_cast(errc)) return true; } return false; diff --git a/libcxxabi/CMakeLists.txt b/libcxxabi/CMakeLists.txt index d9ed55aadc77e3..b8cdb188ebeb06 100644 --- a/libcxxabi/CMakeLists.txt +++ b/libcxxabi/CMakeLists.txt @@ -282,6 +282,10 @@ endif() # library. add_definitions(-D_LIBCXXABI_BUILDING_LIBRARY) +# libcxxabi needs to, for various reasons, include the libcpp headers as if +# it is being built as part of libcxx. +add_definitions(-D_LIBCPP_BUILDING_LIBRARY) + # Disable DLL annotations on Windows for static builds. if (WIN32 AND LIBCXXABI_ENABLE_STATIC AND NOT LIBCXXABI_ENABLE_SHARED) add_definitions(-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) diff --git a/libcxxabi/src/fallback_malloc.cpp b/libcxxabi/src/fallback_malloc.cpp index 8c0fd6c8db4b39..75c01efebed223 100644 --- a/libcxxabi/src/fallback_malloc.cpp +++ b/libcxxabi/src/fallback_malloc.cpp @@ -6,9 +6,6 @@ // //===----------------------------------------------------------------------===// -// Define _LIBCPP_BUILDING_LIBRARY to ensure _LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION -// is only defined when libc aligned allocation is not available. -#define _LIBCPP_BUILDING_LIBRARY #include "fallback_malloc.h" #include <__threading_support> diff --git a/libcxxabi/src/stdlib_exception.cpp b/libcxxabi/src/stdlib_exception.cpp index 88d911d96c96f5..b0cc431f241548 100644 --- a/libcxxabi/src/stdlib_exception.cpp +++ b/libcxxabi/src/stdlib_exception.cpp @@ -6,7 +6,6 @@ // //===----------------------------------------------------------------------===// -#define _LIBCPP_BUILDING_LIBRARY #include #include diff --git a/libcxxabi/src/stdlib_new_delete.cpp b/libcxxabi/src/stdlib_new_delete.cpp index 698c5f7c290c0d..58f181eb357ff5 100644 --- a/libcxxabi/src/stdlib_new_delete.cpp +++ b/libcxxabi/src/stdlib_new_delete.cpp @@ -8,7 +8,6 @@ // This file implements the new and delete operators. //===----------------------------------------------------------------------===// -#define _LIBCPP_BUILDING_LIBRARY #include "__cxxabi_config.h" #include #include diff --git a/lldb/source/Host/freebsd/Host.cpp b/lldb/source/Host/freebsd/Host.cpp index 09547e48afa97a..460a535cf1e0f7 100644 --- a/lldb/source/Host/freebsd/Host.cpp +++ b/lldb/source/Host/freebsd/Host.cpp @@ -175,6 +175,9 @@ uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc)); + ProcessInstanceInfoMatch match_info_noname{match_info}; + match_info_noname.SetNameMatchType(NameMatch::Ignore); + for (size_t i = 0; i < actual_pid_count; i++) { const struct kinfo_proc &kinfo = kinfos[i]; @@ -212,7 +215,7 @@ uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, process_info.SetEffectiveGroupID(kinfo.ki_svgid); // Make sure our info matches before we go fetch the name and cpu type - if (match_info.Matches(process_info) && + if (match_info_noname.Matches(process_info) && GetFreeBSDProcessArgs(&match_info, process_info)) { GetFreeBSDProcessCPUType(process_info); if (match_info.Matches(process_info)) diff --git a/lldb/source/Host/netbsd/HostNetBSD.cpp b/lldb/source/Host/netbsd/HostNetBSD.cpp index 38e2aa5c1e058d..1945f9f9052f74 100644 --- a/lldb/source/Host/netbsd/HostNetBSD.cpp +++ b/lldb/source/Host/netbsd/HostNetBSD.cpp @@ -200,6 +200,9 @@ uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, return 0; } + ProcessInstanceInfoMatch match_info_noname{match_info}; + match_info_noname.SetNameMatchType(NameMatch::Ignore); + for (int i = 0; i < nproc; i++) { if (proc_kinfo[i].p_pid < 1) continue; /* not valid */ @@ -237,7 +240,7 @@ uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, process_info.SetEffectiveUserID(proc_kinfo[i].p_uid); process_info.SetEffectiveGroupID(proc_kinfo[i].p_gid); // Make sure our info matches before we go fetch the name and cpu type - if (match_info.Matches(process_info) && + if (match_info_noname.Matches(process_info) && GetNetBSDProcessArgs(&match_info, process_info)) { GetNetBSDProcessCPUType(process_info); if (match_info.Matches(process_info)) diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp b/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp index 0a4e8ed6bcbfde..2c22f110159796 100644 --- a/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp +++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp @@ -447,6 +447,9 @@ Status NativeProcessFreeBSD::Kill() { Status NativeProcessFreeBSD::GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info) { + // TODO: figure out why it breaks stuff + return Status("currently breaks determining module list"); + if (m_supports_mem_region == LazyBool::eLazyBoolNo) { // We're done. return Status("unsupported"); @@ -580,11 +583,6 @@ Status NativeProcessFreeBSD::PopulateMemoryRegionCache() { return Status(); } -lldb::addr_t NativeProcessFreeBSD::GetSharedLibraryInfoAddress() { - // punt on this for now - return LLDB_INVALID_ADDRESS; -} - size_t NativeProcessFreeBSD::UpdateThreads() { return m_threads.size(); } Status NativeProcessFreeBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size, @@ -698,8 +696,9 @@ Status NativeProcessFreeBSD::Attach() { 0) return Status(errno, eErrorTypePOSIX); - /* Initialize threads */ - status = ReinitializeThreads(); + // Initialize threads and tracing status + // NB: this needs to be called before we set thread state + status = SetupTrace(); if (status.Fail()) return status; @@ -707,7 +706,8 @@ Status NativeProcessFreeBSD::Attach() { static_cast(*thread).SetStoppedBySignal(SIGSTOP); // Let our process instance know the thread has stopped. - SetState(StateType::eStateStopped); + SetCurrentThreadID(m_threads.front()->GetID()); + SetState(StateType::eStateStopped, false); return Status(); } diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h b/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h index 5900048610f5d2..4b6e9af140d09f 100644 --- a/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h +++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h @@ -60,8 +60,6 @@ class NativeProcessFreeBSD : public NativeProcessELF { Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written) override; - lldb::addr_t GetSharedLibraryInfoAddress() override; - size_t UpdateThreads() override; const ArchSpec &GetArchitecture() const override { return m_arch; } diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp b/lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp index c5f0edc64806a0..2e62b0a25ed224 100644 --- a/lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp +++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp @@ -22,9 +22,11 @@ #include #include #include +#include // clang-format on #include +#include using namespace lldb; using namespace lldb_private; @@ -146,7 +148,43 @@ void NativeThreadFreeBSD::SetStepping() { m_stop_info.reason = StopReason::eStopReasonNone; } -std::string NativeThreadFreeBSD::GetName() { return ""; } +std::string NativeThreadFreeBSD::GetName() { + if (!m_thread_name) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + + std::vector kp; + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, + static_cast(GetProcess().GetID())}; + + while (1) { + size_t len = kp.size() * sizeof(struct kinfo_proc); + void *ptr = len == 0 ? nullptr : kp.data(); + int error = ::sysctl(mib, 4, ptr, &len, nullptr, 0); + if (ptr == nullptr || (error != 0 && errno == ENOMEM)) { + kp.resize(len / sizeof(struct kinfo_proc)); + continue; + } + if (error != 0) { + len = 0; + LLDB_LOG(log, "tid = {0} in state {1} failed to get thread name: {2}", GetID(), + m_state, strerror(errno)); + } + kp.resize(len / sizeof(struct kinfo_proc)); + break; + } + + // empty == unknown + m_thread_name = std::string(); + for (auto& procinfo : kp) { + if (procinfo.ki_tid == (lwpid_t)GetID()) { + m_thread_name = procinfo.ki_tdname; + break; + } + } + } + + return m_thread_name.getValue(); +} lldb::StateType NativeThreadFreeBSD::GetState() { return m_state; } diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.h b/lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.h index e4d4941747364f..665e4ea4897107 100644 --- a/lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.h +++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.h @@ -74,6 +74,7 @@ class NativeThreadFreeBSD : public NativeThreadProtocol { using WatchpointIndexMap = std::map; WatchpointIndexMap m_watchpoint_index_map; WatchpointIndexMap m_hw_break_index_map; + llvm::Optional m_thread_name; }; typedef std::shared_ptr NativeThreadFreeBSDSP; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index d19becca823f04..3b6f740a598336 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -1728,6 +1728,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReasonForState( case eStateSuspended: case eStateStopped: case eStateCrashed: { + assert(m_debugged_process_up != nullptr); lldb::tid_t tid = m_debugged_process_up->GetCurrentThreadID(); // Make sure we set the current thread so g and p packets return the data // the gdb will expect. diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h index 5c12231331be8c..0f6604bd510a2f 100644 --- a/llvm/include/llvm/Object/ELFObjectFile.h +++ b/llvm/include/llvm/Object/ELFObjectFile.h @@ -249,14 +249,14 @@ template class ELFObjectFile : public ELFObjectFileBase { private: ELFObjectFile(MemoryBufferRef Object, ELFFile EF, const Elf_Shdr *DotDynSymSec, const Elf_Shdr *DotSymtabSec, - ArrayRef ShndxTable); + const Elf_Shdr *DotSymtabShndxSec); protected: ELFFile EF; const Elf_Shdr *DotDynSymSec = nullptr; // Dynamic symbol table section. const Elf_Shdr *DotSymtabSec = nullptr; // Symbol table section. - ArrayRef ShndxTable; + const Elf_Shdr *DotSymtabShndxSec = nullptr; // SHT_SYMTAB_SHNDX section. void moveSymbolNext(DataRefImpl &Symb) const override; Expected getSymbolName(DataRefImpl Symb) const override; @@ -538,6 +538,16 @@ ELFObjectFile::getSymbolAddress(DataRefImpl Symb) const { return SymTabOrErr.takeError(); if (EF.getHeader().e_type == ELF::ET_REL) { + ArrayRef ShndxTable; + if (DotSymtabShndxSec) { + // TODO: Test this error. + if (Expected> ShndxTableOrErr = + EF.getSHNDXTable(*DotSymtabShndxSec)) + ShndxTable = *ShndxTableOrErr; + else + return ShndxTableOrErr.takeError(); + } + Expected SectionOrErr = EF.getSection(*ESym, *SymTabOrErr, ShndxTable); if (!SectionOrErr) @@ -684,6 +694,16 @@ template Expected ELFObjectFile::getSymbolSection(const Elf_Sym *ESym, const Elf_Shdr *SymTab) const { + ArrayRef ShndxTable; + if (DotSymtabShndxSec) { + // TODO: Test this error. + Expected> ShndxTableOrErr = + EF.getSHNDXTable(*DotSymtabShndxSec); + if (!ShndxTableOrErr) + return ShndxTableOrErr.takeError(); + ShndxTable = *ShndxTableOrErr; + } + auto ESecOrErr = EF.getSection(*ESym, SymTab, ShndxTable); if (!ESecOrErr) return ESecOrErr.takeError(); @@ -984,7 +1004,7 @@ ELFObjectFile::create(MemoryBufferRef Object) { const Elf_Shdr *DotDynSymSec = nullptr; const Elf_Shdr *DotSymtabSec = nullptr; - ArrayRef ShndxTable; + const Elf_Shdr *DotSymtabShndxSec = nullptr; for (const Elf_Shdr &Sec : *SectionsOrErr) { switch (Sec.sh_type) { case ELF::SHT_DYNSYM: { @@ -998,33 +1018,31 @@ ELFObjectFile::create(MemoryBufferRef Object) { break; } case ELF::SHT_SYMTAB_SHNDX: { - auto TableOrErr = EF.getSHNDXTable(Sec); - if (!TableOrErr) - return TableOrErr.takeError(); - ShndxTable = *TableOrErr; + if (!DotSymtabShndxSec) + DotSymtabShndxSec = &Sec; break; } } } return ELFObjectFile(Object, EF, DotDynSymSec, DotSymtabSec, - ShndxTable); + DotSymtabShndxSec); } template ELFObjectFile::ELFObjectFile(MemoryBufferRef Object, ELFFile EF, const Elf_Shdr *DotDynSymSec, const Elf_Shdr *DotSymtabSec, - ArrayRef ShndxTable) + const Elf_Shdr *DotSymtabShndx) : ELFObjectFileBase( getELFType(ELFT::TargetEndianness == support::little, ELFT::Is64Bits), Object), EF(EF), DotDynSymSec(DotDynSymSec), DotSymtabSec(DotSymtabSec), - ShndxTable(ShndxTable) {} + DotSymtabShndxSec(DotSymtabShndx) {} template ELFObjectFile::ELFObjectFile(ELFObjectFile &&Other) : ELFObjectFile(Other.Data, Other.EF, Other.DotDynSymSec, - Other.DotSymtabSec, Other.ShndxTable) {} + Other.DotSymtabSec, Other.DotSymtabShndxSec) {} template basic_symbol_iterator ELFObjectFile::symbol_begin() const { diff --git a/llvm/lib/Target/AMDGPU/AMDGPUCombine.td b/llvm/lib/Target/AMDGPU/AMDGPUCombine.td index d34345e79fa631..a8399176bb4aad 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUCombine.td +++ b/llvm/lib/Target/AMDGPU/AMDGPUCombine.td @@ -11,22 +11,22 @@ include "llvm/Target/GlobalISel/Combine.td" // TODO: This really belongs after legalization after scalarization. // TODO: GICombineRules should accept subtarget predicates -def fmin_fmax_legacy_matchdata : GIDefMatchData<"FMinFMaxLegacyInfo">; +def fmin_fmax_legacy_matchdata : GIDefMatchData<"AMDGPUPostLegalizerCombinerHelper::FMinFMaxLegacyInfo">; def fcmp_select_to_fmin_fmax_legacy : GICombineRule< (defs root:$select, fmin_fmax_legacy_matchdata:$matchinfo), (match (wip_match_opcode G_SELECT):$select, - [{ return matchFMinFMaxLegacy(*${select}, MRI, *MF, ${matchinfo}); }]), - (apply [{ applySelectFCmpToFMinToFMaxLegacy(*${select}, ${matchinfo}); }])>; + [{ return PostLegalizerHelper.matchFMinFMaxLegacy(*${select}, ${matchinfo}); }]), + (apply [{ PostLegalizerHelper.applySelectFCmpToFMinToFMaxLegacy(*${select}, ${matchinfo}); }])>; def uchar_to_float : GICombineRule< (defs root:$itofp), (match (wip_match_opcode G_UITOFP, G_SITOFP):$itofp, - [{ return matchUCharToFloat(*${itofp}, MRI, *MF, Helper); }]), - (apply [{ applyUCharToFloat(*${itofp}); }])>; + [{ return PostLegalizerHelper.matchUCharToFloat(*${itofp}); }]), + (apply [{ PostLegalizerHelper.applyUCharToFloat(*${itofp}); }])>; -def cvt_f32_ubyteN_matchdata : GIDefMatchData<"CvtF32UByteMatchInfo">; +def cvt_f32_ubyteN_matchdata : GIDefMatchData<"AMDGPUPostLegalizerCombinerHelper::CvtF32UByteMatchInfo">; def cvt_f32_ubyteN : GICombineRule< (defs root:$cvt_f32_ubyteN, cvt_f32_ubyteN_matchdata:$matchinfo), @@ -34,8 +34,8 @@ def cvt_f32_ubyteN : GICombineRule< G_AMDGPU_CVT_F32_UBYTE1, G_AMDGPU_CVT_F32_UBYTE2, G_AMDGPU_CVT_F32_UBYTE3):$cvt_f32_ubyteN, - [{ return matchCvtF32UByteN(*${cvt_f32_ubyteN}, MRI, *MF, ${matchinfo}); }]), - (apply [{ applyCvtF32UByteN(*${cvt_f32_ubyteN}, ${matchinfo}); }])>; + [{ return PostLegalizerHelper.matchCvtF32UByteN(*${cvt_f32_ubyteN}, ${matchinfo}); }]), + (apply [{ PostLegalizerHelper.applyCvtF32UByteN(*${cvt_f32_ubyteN}, ${matchinfo}); }])>; // Combines which should only apply on SI/VI def gfx6gfx7_combines : GICombineGroup<[fcmp_select_to_fmin_fmax_legacy]>; @@ -51,6 +51,8 @@ def AMDGPUPostLegalizerCombinerHelper: GICombinerHelper< [all_combines, gfx6gfx7_combines, uchar_to_float, cvt_f32_ubyteN]> { let DisableRuleOption = "amdgpupostlegalizercombiner-disable-rule"; + let StateClass = "AMDGPUPostLegalizerCombinerHelperState"; + let AdditionalArguments = []; } def AMDGPURegBankCombinerHelper : GICombinerHelper< diff --git a/llvm/lib/Target/AMDGPU/AMDGPUPostLegalizerCombiner.cpp b/llvm/lib/Target/AMDGPU/AMDGPUPostLegalizerCombiner.cpp index c4fb1ad54910a2..3fb5eec9f77a7f 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUPostLegalizerCombiner.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUPostLegalizerCombiner.cpp @@ -29,17 +29,47 @@ using namespace llvm; using namespace MIPatternMatch; -struct FMinFMaxLegacyInfo { - Register LHS; - Register RHS; - Register True; - Register False; - CmpInst::Predicate Pred; +class AMDGPUPostLegalizerCombinerHelper { +protected: + MachineIRBuilder &B; + MachineFunction &MF; + MachineRegisterInfo &MRI; + CombinerHelper &Helper; + +public: + AMDGPUPostLegalizerCombinerHelper(MachineIRBuilder &B, CombinerHelper &Helper) + : B(B), MF(B.getMF()), MRI(*B.getMRI()), Helper(Helper){}; + + struct FMinFMaxLegacyInfo { + Register LHS; + Register RHS; + Register True; + Register False; + CmpInst::Predicate Pred; + }; + + // TODO: Make sure fmin_legacy/fmax_legacy don't canonicalize + bool matchFMinFMaxLegacy(MachineInstr &MI, FMinFMaxLegacyInfo &Info); + void applySelectFCmpToFMinToFMaxLegacy(MachineInstr &MI, + const FMinFMaxLegacyInfo &Info); + + bool matchUCharToFloat(MachineInstr &MI); + void applyUCharToFloat(MachineInstr &MI); + + // FIXME: Should be able to have 2 separate matchdatas rather than custom + // struct boilerplate. + struct CvtF32UByteMatchInfo { + Register CvtVal; + unsigned ShiftOffset; + }; + + bool matchCvtF32UByteN(MachineInstr &MI, CvtF32UByteMatchInfo &MatchInfo); + void applyCvtF32UByteN(MachineInstr &MI, + const CvtF32UByteMatchInfo &MatchInfo); }; -// TODO: Make sure fmin_legacy/fmax_legacy don't canonicalize -static bool matchFMinFMaxLegacy(MachineInstr &MI, MachineRegisterInfo &MRI, - MachineFunction &MF, FMinFMaxLegacyInfo &Info) { +bool AMDGPUPostLegalizerCombinerHelper::matchFMinFMaxLegacy( + MachineInstr &MI, FMinFMaxLegacyInfo &Info) { // FIXME: Combines should have subtarget predicates, and we shouldn't need // this here. if (!MF.getSubtarget().hasFminFmaxLegacy()) @@ -77,12 +107,11 @@ static bool matchFMinFMaxLegacy(MachineInstr &MI, MachineRegisterInfo &MRI, } } -static void applySelectFCmpToFMinToFMaxLegacy(MachineInstr &MI, - const FMinFMaxLegacyInfo &Info) { - - auto buildNewInst = [&MI](unsigned Opc, Register X, Register Y) { - MachineIRBuilder MIB(MI); - MIB.buildInstr(Opc, {MI.getOperand(0)}, {X, Y}, MI.getFlags()); +void AMDGPUPostLegalizerCombinerHelper::applySelectFCmpToFMinToFMaxLegacy( + MachineInstr &MI, const FMinFMaxLegacyInfo &Info) { + B.setInstrAndDebugLoc(MI); + auto buildNewInst = [&MI, this](unsigned Opc, Register X, Register Y) { + B.buildInstr(Opc, {MI.getOperand(0)}, {X, Y}, MI.getFlags()); }; switch (Info.Pred) { @@ -127,8 +156,7 @@ static void applySelectFCmpToFMinToFMaxLegacy(MachineInstr &MI, MI.eraseFromParent(); } -static bool matchUCharToFloat(MachineInstr &MI, MachineRegisterInfo &MRI, - MachineFunction &MF, CombinerHelper &Helper) { +bool AMDGPUPostLegalizerCombinerHelper::matchUCharToFloat(MachineInstr &MI) { Register DstReg = MI.getOperand(0).getReg(); // TODO: We could try to match extracting the higher bytes, which would be @@ -147,15 +175,15 @@ static bool matchUCharToFloat(MachineInstr &MI, MachineRegisterInfo &MRI, return false; } -static void applyUCharToFloat(MachineInstr &MI) { - MachineIRBuilder B(MI); +void AMDGPUPostLegalizerCombinerHelper::applyUCharToFloat(MachineInstr &MI) { + B.setInstrAndDebugLoc(MI); const LLT S32 = LLT::scalar(32); Register DstReg = MI.getOperand(0).getReg(); Register SrcReg = MI.getOperand(1).getReg(); - LLT Ty = B.getMRI()->getType(DstReg); - LLT SrcTy = B.getMRI()->getType(SrcReg); + LLT Ty = MRI.getType(DstReg); + LLT SrcTy = MRI.getType(SrcReg); if (SrcTy != S32) SrcReg = B.buildAnyExtOrTrunc(S32, SrcReg).getReg(0); @@ -171,16 +199,8 @@ static void applyUCharToFloat(MachineInstr &MI) { MI.eraseFromParent(); } -// FIXME: Should be able to have 2 separate matchdatas rather than custom struct -// boilerplate. -struct CvtF32UByteMatchInfo { - Register CvtVal; - unsigned ShiftOffset; -}; - -static bool matchCvtF32UByteN(MachineInstr &MI, MachineRegisterInfo &MRI, - MachineFunction &MF, - CvtF32UByteMatchInfo &MatchInfo) { +bool AMDGPUPostLegalizerCombinerHelper::matchCvtF32UByteN( + MachineInstr &MI, CvtF32UByteMatchInfo &MatchInfo) { Register SrcReg = MI.getOperand(1).getReg(); // Look through G_ZEXT. @@ -207,14 +227,14 @@ static bool matchCvtF32UByteN(MachineInstr &MI, MachineRegisterInfo &MRI, return false; } -static void applyCvtF32UByteN(MachineInstr &MI, - const CvtF32UByteMatchInfo &MatchInfo) { - MachineIRBuilder B(MI); +void AMDGPUPostLegalizerCombinerHelper::applyCvtF32UByteN( + MachineInstr &MI, const CvtF32UByteMatchInfo &MatchInfo) { + B.setInstrAndDebugLoc(MI); unsigned NewOpc = AMDGPU::G_AMDGPU_CVT_F32_UBYTE0 + MatchInfo.ShiftOffset / 8; const LLT S32 = LLT::scalar(32); Register CvtSrc = MatchInfo.CvtVal; - LLT SrcTy = B.getMRI()->getType(MatchInfo.CvtVal); + LLT SrcTy = MRI.getType(MatchInfo.CvtVal); if (SrcTy != S32) { assert(SrcTy.isScalar() && SrcTy.getSizeInBits() >= 8); CvtSrc = B.buildAnyExt(S32, CvtSrc).getReg(0); @@ -225,6 +245,18 @@ static void applyCvtF32UByteN(MachineInstr &MI, MI.eraseFromParent(); } +class AMDGPUPostLegalizerCombinerHelperState { +protected: + CombinerHelper &Helper; + AMDGPUPostLegalizerCombinerHelper &PostLegalizerHelper; + +public: + AMDGPUPostLegalizerCombinerHelperState( + CombinerHelper &Helper, + AMDGPUPostLegalizerCombinerHelper &PostLegalizerHelper) + : Helper(Helper), PostLegalizerHelper(PostLegalizerHelper) {} +}; + #define AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_DEPS #include "AMDGPUGenPostLegalizeGICombiner.inc" #undef AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_DEPS @@ -259,9 +291,11 @@ bool AMDGPUPostLegalizerCombinerInfo::combine(GISelChangeObserver &Observer, MachineInstr &MI, MachineIRBuilder &B) const { CombinerHelper Helper(Observer, B, KB, MDT, LInfo); - AMDGPUGenPostLegalizerCombinerHelper Generated(GeneratedRuleCfg); + AMDGPUPostLegalizerCombinerHelper PostLegalizerHelper(B, Helper); + AMDGPUGenPostLegalizerCombinerHelper Generated(GeneratedRuleCfg, Helper, + PostLegalizerHelper); - if (Generated.tryCombineAll(Observer, MI, B, Helper)) + if (Generated.tryCombineAll(Observer, MI, B)) return true; switch (MI.getOpcode()) { diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp index e8735b31628c6b..693a41372a6882 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp @@ -3190,18 +3190,55 @@ bool PPCInstrInfo::convertToImmediateForm(MachineInstr &MI, return false; } -bool PPCInstrInfo::combineRLWINM(MachineInstr &MI, - MachineInstr **ToErase) const { +// This function tries to combine two RLWINMs. We not only perform such +// optimization in SSA, but also after RA, since some RLWINM is generated after +// RA. +bool PPCInstrInfo::simplifyRotateAndMaskInstr(MachineInstr &MI, + MachineInstr *&ToErase) const { + bool Is64Bit = false; + switch (MI.getOpcode()) { + case PPC::RLWINM: + case PPC::RLWINM_rec: + break; + case PPC::RLWINM8: + case PPC::RLWINM8_rec: + Is64Bit = true; + break; + default: + return false; + } MachineRegisterInfo *MRI = &MI.getParent()->getParent()->getRegInfo(); - unsigned FoldingReg = MI.getOperand(1).getReg(); - if (!Register::isVirtualRegister(FoldingReg)) + Register FoldingReg = MI.getOperand(1).getReg(); + MachineInstr *SrcMI = nullptr; + bool NoUse = false; + if (MRI->isSSA()) { + if (!Register::isVirtualRegister(FoldingReg)) + return false; + SrcMI = MRI->getVRegDef(FoldingReg); + } else { + bool OtherIntermediateUse = false; + SrcMI = getDefMIPostRA(FoldingReg, MI, OtherIntermediateUse); + NoUse = !OtherIntermediateUse && MI.getOperand(1).isKill(); + } + if (!SrcMI) return false; - MachineInstr *SrcMI = MRI->getVRegDef(FoldingReg); - if (SrcMI->getOpcode() != PPC::RLWINM && - SrcMI->getOpcode() != PPC::RLWINM_rec && - SrcMI->getOpcode() != PPC::RLWINM8 && - SrcMI->getOpcode() != PPC::RLWINM8_rec) + // TODO: The pairs of RLWINM8(RLWINM) or RLWINM(RLWINM8) never occur before + // RA, but after RA. And We can fold RLWINM8(RLWINM) -> RLWINM8, or + // RLWINM(RLWINM8) -> RLWINM. + switch (SrcMI->getOpcode()) { + case PPC::RLWINM: + case PPC::RLWINM_rec: + if (Is64Bit) + return false; + break; + case PPC::RLWINM8: + case PPC::RLWINM8_rec: + if (!Is64Bit) + return false; + break; + default: return false; + } assert((MI.getOperand(2).isImm() && MI.getOperand(3).isImm() && MI.getOperand(4).isImm() && SrcMI->getOperand(2).isImm() && SrcMI->getOperand(3).isImm() && SrcMI->getOperand(4).isImm()) && @@ -3256,8 +3293,6 @@ bool PPCInstrInfo::combineRLWINM(MachineInstr &MI, // If final mask is 0, MI result should be 0 too. if (FinalMask.isNullValue()) { - bool Is64Bit = - (MI.getOpcode() == PPC::RLWINM8 || MI.getOpcode() == PPC::RLWINM8_rec); Simplified = true; LLVM_DEBUG(dbgs() << "Replace Instr: "); LLVM_DEBUG(MI.dump()); @@ -3315,14 +3350,15 @@ bool PPCInstrInfo::combineRLWINM(MachineInstr &MI, LLVM_DEBUG(dbgs() << "To: "); LLVM_DEBUG(MI.dump()); } - if (Simplified & MRI->use_nodbg_empty(FoldingReg) && - !SrcMI->hasImplicitDef()) { - // If FoldingReg has no non-debug use and it has no implicit def (it - // is not RLWINMO or RLWINM8o), it's safe to delete its def SrcMI. - // Otherwise keep it. - *ToErase = SrcMI; - LLVM_DEBUG(dbgs() << "Delete dead instruction: "); - LLVM_DEBUG(SrcMI->dump()); + if (Simplified && !SrcMI->hasImplicitDef()) { + // If SrcMI has no implicit def, and FoldingReg has no non-debug use or + // its flag is "killed", it's safe to delete SrcMI. Otherwise keep it. + if ((!MRI->isSSA() && NoUse) || + (MRI->isSSA() && MRI->use_nodbg_empty(FoldingReg))) { + ToErase = SrcMI; + LLVM_DEBUG(dbgs() << "Delete dead instruction: "); + LLVM_DEBUG(SrcMI->dump()); + } } return Simplified; } diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.h b/llvm/lib/Target/PowerPC/PPCInstrInfo.h index f3ada5a0febc20..0a2564a51fcec6 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.h +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.h @@ -564,7 +564,8 @@ class PPCInstrInfo : public PPCGenInstrInfo { bool convertToImmediateForm(MachineInstr &MI, MachineInstr **KilledDef = nullptr) const; bool foldFrameOffset(MachineInstr &MI) const; - bool combineRLWINM(MachineInstr &MI, MachineInstr **ToErase = nullptr) const; + bool simplifyRotateAndMaskInstr(MachineInstr &MI, + MachineInstr *&ToErase) const; bool isADDIInstrEligibleForFolding(MachineInstr &ADDIMI, int64_t &Imm) const; bool isADDInstrEligibleForFolding(MachineInstr &ADDMI) const; bool isImmInstrEligibleForFolding(MachineInstr &MI, unsigned &BaseReg, diff --git a/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp b/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp index 3fd02bc185c98e..827d3c4693b95d 100644 --- a/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp +++ b/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp @@ -848,7 +848,7 @@ bool PPCMIPeephole::simplifyCode(void) { case PPC::RLWINM_rec: case PPC::RLWINM8: case PPC::RLWINM8_rec: { - Simplified = TII->combineRLWINM(MI, &ToErase); + Simplified = TII->simplifyRotateAndMaskInstr(MI, ToErase); if (Simplified) ++NumRotatesCollapsed; break; diff --git a/llvm/lib/Target/PowerPC/PPCPreEmitPeephole.cpp b/llvm/lib/Target/PowerPC/PPCPreEmitPeephole.cpp index 7d1282df369b1b..8e4a50c1b33ded 100644 --- a/llvm/lib/Target/PowerPC/PPCPreEmitPeephole.cpp +++ b/llvm/lib/Target/PowerPC/PPCPreEmitPeephole.cpp @@ -37,6 +37,8 @@ STATISTIC(NumberOfSelfCopies, "Number of self copy instructions eliminated"); STATISTIC(NumFrameOffFoldInPreEmit, "Number of folding frame offset by using r+r in pre-emit peephole"); +STATISTIC(NumRotateInstrFoldInPreEmit, + "Number of folding Rotate instructions in pre-emit peephole"); static cl::opt EnablePCRelLinkerOpt("ppc-pcrel-linker-opt", cl::Hidden, cl::init(true), @@ -413,6 +415,13 @@ static bool hasPCRelativeForm(MachineInstr &Use) { LLVM_DEBUG(dbgs() << "Frame offset folding by using index form: "); LLVM_DEBUG(MI.dump()); } + MachineInstr *ToErase = nullptr; + if (TII->simplifyRotateAndMaskInstr(MI, ToErase)) { + Changed = true; + NumRotateInstrFoldInPreEmit++; + if (ToErase) + InstrsToErase.push_back(ToErase); + } } // Eliminate conditional branch based on a constant CR bit by diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoB.td b/llvm/lib/Target/RISCV/RISCVInstrInfoB.td index c85ab7996fcc2d..aecb429fdd1584 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoB.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoB.td @@ -665,9 +665,7 @@ def : Pat<(xor (srl (xor GPR:$rs1, -1), GPR:$rs2), -1), let Predicates = [HasStdExtZbbOrZbp] in { def : Pat<(rotl GPR:$rs1, GPR:$rs2), (ROL GPR:$rs1, GPR:$rs2)>; -def : Pat<(fshl GPR:$rs1, GPR:$rs1, GPR:$rs2), (ROL GPR:$rs1, GPR:$rs2)>; def : Pat<(rotr GPR:$rs1, GPR:$rs2), (ROR GPR:$rs1, GPR:$rs2)>; -def : Pat<(fshr GPR:$rs1, GPR:$rs1, GPR:$rs2), (ROR GPR:$rs1, GPR:$rs2)>; } // Predicates = [HasStdExtZbbOrZbp] let Predicates = [HasStdExtZbs, IsRV32] in diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp index 0ee0d6e87a0d98..1be6bd0b497067 100644 --- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -2302,17 +2302,25 @@ bool IndVarSimplify::sinkUnusedInvariants(Loop *L) { return MadeAnyChanges; } -// Returns true if the condition of \p BI being checked is invariant and can be -// proved to be trivially true during at least first \p MaxIter iterations. -static bool isTrivialCond(const Loop *L, BranchInst *BI, ScalarEvolution *SE, - bool ProvingLoopExit, const SCEV *MaxIter) { +enum ExitCondAnalysisResult { + CanBeRemoved, + CannotOptimize +}; + +/// If the condition of BI is trivially true during at least first MaxIter +/// iterations, return CanBeRemoved. +/// Otherwise, return CannotOptimize. +static ExitCondAnalysisResult analyzeCond(const Loop *L, BranchInst *BI, + ScalarEvolution *SE, + bool ProvingLoopExit, + const SCEV *MaxIter) { ICmpInst::Predicate Pred; Value *LHS, *RHS; using namespace PatternMatch; BasicBlock *TrueSucc, *FalseSucc; if (!match(BI, m_Br(m_ICmp(Pred, m_Value(LHS), m_Value(RHS)), m_BasicBlock(TrueSucc), m_BasicBlock(FalseSucc)))) - return false; + return CannotOptimize; assert((L->contains(TrueSucc) != L->contains(FalseSucc)) && "Not a loop exit!"); @@ -2329,10 +2337,10 @@ static bool isTrivialCond(const Loop *L, BranchInst *BI, ScalarEvolution *SE, const SCEV *RHSS = SE->getSCEVAtScope(RHS, L); // Can we prove it to be trivially true? if (SE->isKnownPredicateAt(Pred, LHSS, RHSS, BI)) - return true; + return CanBeRemoved; if (ProvingLoopExit) - return false; + return CannotOptimize; ICmpInst::Predicate InvariantPred; const SCEV *InvariantLHS, *InvariantRHS; @@ -2341,10 +2349,12 @@ static bool isTrivialCond(const Loop *L, BranchInst *BI, ScalarEvolution *SE, if (!SE->isLoopInvariantExitCondDuringFirstIterations( Pred, LHSS, RHSS, L, BI, MaxIter, InvariantPred, InvariantLHS, InvariantRHS)) - return false; + return CannotOptimize; // Can we prove it to be trivially true? - return SE->isKnownPredicateAt(InvariantPred, InvariantLHS, InvariantRHS, BI); + if (SE->isKnownPredicateAt(InvariantPred, InvariantLHS, InvariantRHS, BI)) + return CanBeRemoved; + return CannotOptimize; } bool IndVarSimplify::optimizeLoopExits(Loop *L, SCEVExpander &Rewriter) { @@ -2406,15 +2416,20 @@ bool IndVarSimplify::optimizeLoopExits(Loop *L, SCEVExpander &Rewriter) { } #endif + auto ReplaceExitCond = [&](BranchInst *BI, Value *NewCond) { + auto *OldCond = BI->getCondition(); + BI->setCondition(NewCond); + if (OldCond->use_empty()) + DeadInsts.emplace_back(OldCond); + }; + auto FoldExit = [&](BasicBlock *ExitingBB, bool IsTaken) { BranchInst *BI = cast(ExitingBB->getTerminator()); bool ExitIfTrue = !L->contains(*succ_begin(ExitingBB)); auto *OldCond = BI->getCondition(); auto *NewCond = ConstantInt::get(OldCond->getType(), IsTaken ? ExitIfTrue : !ExitIfTrue); - BI->setCondition(NewCond); - if (OldCond->use_empty()) - DeadInsts.emplace_back(OldCond); + ReplaceExitCond(BI, NewCond); }; bool Changed = false; @@ -2433,11 +2448,14 @@ bool IndVarSimplify::optimizeLoopExits(Loop *L, SCEVExpander &Rewriter) { const SCEV *One = SE->getOne(MaxIter->getType()); MaxIter = SE->getMinusSCEV(MaxIter, One); } - if (isTrivialCond(L, BI, SE, Inverted, MaxIter)) { + switch (analyzeCond(L, BI, SE, Inverted, MaxIter)) { + case CanBeRemoved: FoldExit(ExitingBB, Inverted); return true; + case CannotOptimize: + return false; } - return false; + llvm_unreachable("Unknown case!"); }; // TODO: We might have proved that we can skip the last iteration for diff --git a/llvm/test/CodeGen/PowerPC/fold-rlwinm-after-ra.mir b/llvm/test/CodeGen/PowerPC/fold-rlwinm-after-ra.mir new file mode 100644 index 00000000000000..b26487e6f13652 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/fold-rlwinm-after-ra.mir @@ -0,0 +1,104 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -mcpu=pwr9 -mtriple=powerpc64le-unknown-unknown -stop-after \ +# RUN: ppc-pre-emit-peephole %s -o - | FileCheck %s + +--- +name: testFoldRLWINM +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $r3 + ; CHECK-LABEL: name: testFoldRLWINM + ; CHECK: liveins: $r3 + ; CHECK: renamable $r3 = RLWINM killed renamable $r3, 14, 0, 12, implicit-def $x3 + ; CHECK: BLR8 implicit $lr8, implicit $rm, implicit killed $x3 + $r3 = RLWINM killed $r3, 27, 5, 31 + dead renamable $r3 = RLWINM killed renamable $r3, 19, 0, 12, implicit-def $x3 + BLR8 implicit $lr8, implicit $rm, implicit killed $x3 +... +--- +name: testFoldRLWINMSrcFullMask +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $r3 + ; CHECK-LABEL: name: testFoldRLWINMSrcFullMask + ; CHECK: liveins: $r3 + ; CHECK: renamable $r3 = RLWINM killed renamable $r3, 14, 0, 12, implicit-def $x3 + ; CHECK: BLR8 implicit $lr8, implicit $rm, implicit killed $x3 + $r3 = RLWINM killed $r3, 27, 0, 31 + dead renamable $r3 = RLWINM killed renamable $r3, 19, 0, 12, implicit-def $x3 + BLR8 implicit $lr8, implicit $rm, implicit killed $x3 +... +--- +name: testFoldRLWINMSrcWrapped +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $r3 + ; CHECK-LABEL: name: testFoldRLWINMSrcWrapped + ; CHECK: liveins: $r3 + ; CHECK: renamable $r3 = RLWINM killed renamable $r3, 14, 11, 12, implicit-def $x3 + ; CHECK: BLR8 implicit $lr8, implicit $rm, implicit killed $x3 + $r3 = RLWINM killed $r3, 27, 30, 10 + dead renamable $r3 = RLWINM killed renamable $r3, 19, 0, 12, implicit-def $x3 + BLR8 implicit $lr8, implicit $rm, implicit killed $x3 +... +--- +name: testFoldRLWINMToZero +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $r3 + ; CHECK-LABEL: name: testFoldRLWINMToZero + ; CHECK: liveins: $r3 + ; CHECK: renamable $r3 = LI 0, implicit-def $x3 + ; CHECK: BLR8 implicit $lr8, implicit $rm, implicit killed $x3 + $r3 = RLWINM killed $r3, 27, 5, 10 + dead renamable $r3 = RLWINM killed renamable $r3, 8, 5, 10, implicit-def $x3 + BLR8 implicit $lr8, implicit $rm, implicit killed $x3 +... +--- +name: testFoldRLWINM_recToZero +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $r3 + ; CHECK-LABEL: name: testFoldRLWINM_recToZero + ; CHECK: liveins: $r3 + ; CHECK: dead renamable $r3 = ANDI_rec killed renamable $r3, 0, implicit-def $cr0 + ; CHECK: BLR8 implicit $lr8, implicit $rm, implicit killed $cr0 + $r3 = RLWINM killed $r3, 27, 5, 10 + dead renamable $r3 = RLWINM_rec killed renamable $r3, 8, 5, 10, implicit-def $cr0 + BLR8 implicit $lr8, implicit $rm, implicit killed $cr0 +... +--- +name: testFoldRLWINMoToZeroSrcCanNotBeDeleted +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $r3 + ; CHECK-LABEL: name: testFoldRLWINMoToZeroSrcCanNotBeDeleted + ; CHECK: liveins: $r3 + ; CHECK: $r3 = RLWINM_rec $r3, 27, 5, 10, implicit-def dead $cr0 + ; CHECK: dead renamable $r3 = ANDI_rec killed renamable $r3, 0, implicit-def $cr0 + ; CHECK: BLR8 implicit $lr8, implicit $rm, implicit killed $cr0 + $r3 = RLWINM_rec $r3, 27, 5, 10, implicit-def $cr0 + dead renamable $r3 = RLWINM_rec killed renamable $r3, 8, 5, 10, implicit-def $cr0 + BLR8 implicit $lr8, implicit $rm, implicit killed $cr0 +... +--- +name: testFoldRLWINMInvalidMask +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $r3 + ; CHECK-LABEL: name: testFoldRLWINMInvalidMask + ; CHECK: liveins: $r3 + ; CHECK: $r3 = RLWINM killed $r3, 20, 5, 31 + ; CHECK: renamable $r3 = RLWINM killed renamable $r3, 19, 10, 20, implicit-def $x3 + ; CHECK: BLR8 implicit $lr8, implicit $rm, implicit killed $x3 + $r3 = RLWINM killed $r3, 20, 5, 31 + dead renamable $r3 = RLWINM killed renamable $r3, 19, 10, 20, implicit-def $x3 + BLR8 implicit $lr8, implicit $rm, implicit killed $x3 +... diff --git a/llvm/test/CodeGen/PowerPC/sms-phi-5.ll b/llvm/test/CodeGen/PowerPC/sms-phi-5.ll index bdc773de8aaf1e..c147ddf8182b97 100644 --- a/llvm/test/CodeGen/PowerPC/sms-phi-5.ll +++ b/llvm/test/CodeGen/PowerPC/sms-phi-5.ll @@ -14,9 +14,8 @@ define void @phi5() unnamed_addr { ; CHECK-NEXT: # %bb.2: ; CHECK-NEXT: lhz 3, 0(3) ; CHECK-NEXT: slwi 3, 3, 15 -; CHECK-NEXT: clrlwi 3, 3, 31 -; CHECK-NEXT: rlwinm 4, 3, 31, 17, 31 -; CHECK-NEXT: or 3, 3, 4 +; CHECK-NEXT: li 4, 0 +; CHECK-NEXT: ori 3, 4, 0 ; CHECK-NEXT: rlwimi 3, 3, 15, 0, 16 ; CHECK-NEXT: # %bb.3: ; CHECK-NEXT: blr diff --git a/llvm/test/CodeGen/PowerPC/vsx_builtins.ll b/llvm/test/CodeGen/PowerPC/vsx_builtins.ll index 0aae50af26490c..b40a84a7e95c59 100644 --- a/llvm/test/CodeGen/PowerPC/vsx_builtins.ll +++ b/llvm/test/CodeGen/PowerPC/vsx_builtins.ll @@ -131,8 +131,7 @@ define i32 @xvtdivdp_shift(<2 x double> %a, <2 x double> %b) { ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: xvtdivdp cr0, v2, v3 ; CHECK-NEXT: mfocrf r3, 128 -; CHECK-NEXT: srwi r3, r3, 28 -; CHECK-NEXT: rlwinm r3, r3, 28, 31, 31 +; CHECK-NEXT: li r3, 0 ; CHECK-NEXT: blr entry: %0 = tail call i32 @llvm.ppc.vsx.xvtdivdp(<2 x double> %a, <2 x double> %b) diff --git a/llvm/test/Object/invalid.test b/llvm/test/Object/invalid.test index 8d9068a1ba07a0..b6bee98681b50a 100644 --- a/llvm/test/Object/invalid.test +++ b/llvm/test/Object/invalid.test @@ -211,9 +211,9 @@ Sections: ## sizeof(.symtab_shndx) = (sizeof(.symtab) / entsize(.symtab)) * entsize(.symtab_shndx) # RUN: yaml2obj %s --docnum=11 -o %t11 -# RUN: not llvm-readobj --symbols %t11 2>&1 | FileCheck --check-prefix=INVALID-XINDEX-SIZE %s +# RUN: llvm-readobj --symbols %t11 2>&1 | FileCheck --check-prefix=INVALID-XINDEX-SIZE %s -# INVALID-XINDEX-SIZE: error: {{.*}}: SHT_SYMTAB_SHNDX has 2 entries, but the symbol table associated has 1 +# INVALID-XINDEX-SIZE: warning: {{.*}}: SHT_SYMTAB_SHNDX has 2 entries, but the symbol table associated has 1 --- !ELF FileHeader: diff --git a/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test b/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test index 1163b0b8fafa84..62085b6c18837e 100644 --- a/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test +++ b/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test @@ -254,3 +254,60 @@ Symbols: Index: SHN_XINDEX - Name: no_shndx2 Index: SHN_XINDEX + +## Check we can dump symbols even when the number of entries in the +## SHT_SYMTAB_SHNDX section doesn't match the number of symbols in the symbol table. + +# RUN: yaml2obj --docnum=4 %s -o %t4 +# RUN: llvm-readelf --symbols %t4 2>&1 | FileCheck %s -DFILE=%t4 --check-prefix=SHNDX-ERR-GNU +# RUN: llvm-readobj --symbols %t4 2>&1 | FileCheck %s -DFILE=%t4 --check-prefix=SHNDX-ERR-LLVM + +# SHNDX-ERR-GNU: warning: '[[FILE]]': SHT_SYMTAB_SHNDX has 3 entries, but the symbol table associated has 2 +# SHNDX-ERR-GNU-EMPTY: +# SHNDX-ERR-GNU-NEXT: Symbol table '.symtab' contains 2 entries: +# SHNDX-ERR-GNU-NEXT: Num: Value Size Type Bind Vis Ndx Name +# SHNDX-ERR-GNU-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND +# SHNDX-ERR-GNU-NEXT: warning: '[[FILE]]': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0 +# SHNDX-ERR-GNU-NEXT: 1: 0000000000000000 0 NOTYPE LOCAL DEFAULT RSV[0xffff] +# SHNDX-ERR-GNU-EMPTY: +# SHNDX-ERR-GNU-NOT:{{.}} + +# SHNDX-ERR-LLVM: warning: '[[FILE]]': SHT_SYMTAB_SHNDX has 3 entries, but the symbol table associated has 2 +# SHNDX-ERR-LLVM: Format: elf64-unknown +# SHNDX-ERR-LLVM-NEXT: Arch: unknown +# SHNDX-ERR-LLVM-NEXT: AddressSize: 64bit +# SHNDX-ERR-LLVM-NEXT: LoadName: +# SHNDX-ERR-LLVM-NEXT: Symbols [ +# SHNDX-ERR-LLVM-NEXT: Symbol { +# SHNDX-ERR-LLVM-NEXT: Name: (0) +# SHNDX-ERR-LLVM-NEXT: Value: 0x0 +# SHNDX-ERR-LLVM-NEXT: Size: 0 +# SHNDX-ERR-LLVM-NEXT: Binding: Local (0x0) +# SHNDX-ERR-LLVM-NEXT: Type: None (0x0) +# SHNDX-ERR-LLVM-NEXT: Other: 0 +# SHNDX-ERR-LLVM-NEXT: Section: Undefined (0x0) +# SHNDX-ERR-LLVM-NEXT: } +# SHNDX-ERR-LLVM-NEXT: Symbol { +# SHNDX-ERR-LLVM-NEXT: Name: (0) +# SHNDX-ERR-LLVM-NEXT: Value: 0x0 +# SHNDX-ERR-LLVM-NEXT: Size: 0 +# SHNDX-ERR-LLVM-NEXT: Binding: Local (0x0) +# SHNDX-ERR-LLVM-NEXT: Type: None (0x0) +# SHNDX-ERR-LLVM-NEXT: Other: 0 +# SHNDX-ERR-LLVM-NEXT: warning: '[[FILE]]': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0 +# SHNDX-ERR-LLVM-NEXT: Section: Reserved (0xFFFF) +# SHNDX-ERR-LLVM-NEXT: } +# SHNDX-ERR-LLVM-NEXT: ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL +Sections: + - Name: .symtab_shndx + Type: SHT_SYMTAB_SHNDX + Entries: [ 0, 1, 2 ] + Link: .symtab +Symbols: + - Index: SHN_XINDEX diff --git a/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml b/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml index 27decbe76d9267..2940e54cb435ce 100644 --- a/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml +++ b/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml @@ -143,7 +143,7 @@ Symbols: [] # RUN: yaml2obj --docnum=6 %s -o %t6 # RUN: not obj2yaml %t6 2>&1 | FileCheck %s -DFILE=%t6 --check-prefix=CASE6 -# CASE6: Error reading file: [[FILE]]: SHT_SYMTAB_SHNDX section is linked with SHT_PROGBITS section (expected SHT_SYMTAB/SHT_DYNSYM) +# CASE6: Error reading file: [[FILE]]: only SHT_SYMTAB_SHNDX associated with SHT_SYMTAB are supported --- !ELF FileHeader: diff --git a/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml b/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml index a442c24522e72e..4c185810820d38 100644 --- a/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml +++ b/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml @@ -107,9 +107,9 @@ Symbols: ## Check we can set a custom sh_entsize for SHT_SYMTAB_SHNDX section. # RUN: yaml2obj --docnum=5 %s -o %t5 -# RUN: not llvm-readelf -S 2>&1 %t5 | FileCheck %s -DFILE=%t5 --check-prefix=CASE5 +# RUN: llvm-readelf -S 2>&1 %t5 | FileCheck %s -DFILE=%t5 --check-prefix=CASE5 -# CASE5: error: '[[FILE]]': section [index 1] has an invalid sh_entsize: 2 +# CASE5: warning: '[[FILE]]': section [index 1] has an invalid sh_entsize: 2 --- !ELF FileHeader: diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 4b8e987d99b7b0..470ba491a89bc6 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -2026,7 +2026,10 @@ ELFDumper::ELFDumper(const object::ELFObjectFile &O, } break; case ELF::SHT_SYMTAB_SHNDX: - ShndxTable = unwrapOrError(ObjF.getFileName(), Obj.getSHNDXTable(Sec)); + if (Expected> ShndxTableOrErr = Obj.getSHNDXTable(Sec)) + ShndxTable = *ShndxTableOrErr; + else + this->reportUniqueWarning(ShndxTableOrErr.takeError()); break; case ELF::SHT_GNU_versym: if (!SymbolVersionSection) diff --git a/llvm/unittests/Object/CMakeLists.txt b/llvm/unittests/Object/CMakeLists.txt index b263e03396fd26..559d02ea0ae502 100644 --- a/llvm/unittests/Object/CMakeLists.txt +++ b/llvm/unittests/Object/CMakeLists.txt @@ -1,6 +1,7 @@ set(LLVM_LINK_COMPONENTS BinaryFormat Object + ObjectYAML ) add_llvm_unittest(ObjectTests diff --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp index ebbbae0af0936e..5b7a298914936a 100644 --- a/llvm/unittests/Object/ELFObjectFileTest.cpp +++ b/llvm/unittests/Object/ELFObjectFileTest.cpp @@ -8,6 +8,8 @@ #include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/ObjectYAML/yaml2obj.h" +#include "llvm/Support/YAMLTraits.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" @@ -291,9 +293,38 @@ TEST(ELFObjectFileTest, MachineTestForCSKY) { checkFormatAndArch(D, Formats[I++], Triple::csky); } - - // ELF relative relocation type test. TEST(ELFObjectFileTest, RelativeRelocationTypeTest) { EXPECT_EQ(ELF::R_CKCORE_RELATIVE, getELFRelativeRelocationType(ELF::EM_CSKY)); } + +template +static Expected> toBinary(SmallVectorImpl &Storage, + StringRef Yaml) { + raw_svector_ostream OS(Storage); + yaml::Input YIn(Yaml); + if (!yaml::convertYAML(YIn, OS, [](const Twine &Msg) {})) + return createStringError(std::errc::invalid_argument, + "unable to convert YAML"); + return ELFObjectFile::create(MemoryBufferRef(OS.str(), "dummyELF")); +} + +// Check we are able to create an ELFObjectFile even when the content of the +// SHT_SYMTAB_SHNDX section can't be read properly. +TEST(ELFObjectFileTest, InvalidSymtabShndxTest) { + SmallString<0> Storage; + Expected> ExpectedFile = toBinary(Storage, R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL +Sections: + - Name: .symtab_shndx + Type: SHT_SYMTAB_SHNDX + Entries: [ 0 ] + ShSize: 0xFFFFFFFF +)"); + + ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded()); +}