llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang @llvm/pr-subscribers-llvm-support Author: Daniel Thornburgh (mysterymath) <details> <summary>Changes</summary> …thread to get more stack space (#<!-- -->133173)" This change breaks the Clang build on Mac AArch64. This reverts commit d0c973a7a0149db3b71767d4c5a20a31e6a8ed5b. This reverts commit 429a84f8a4bf559f43f50072747ef49d3e3b2cf1. This reverts commit 4f64c80d5a23c244f942193e58ecac666c173308. --- Full diff: https://github.com/llvm/llvm-project/pull/135865.diff 12 Files Affected: - (modified) clang/docs/ReleaseNotes.rst (-4) - (modified) clang/include/clang/Basic/Stack.h (+1-4) - (modified) clang/lib/Basic/Stack.cpp (+28-12) - (modified) clang/lib/Frontend/CompilerInstance.cpp (+1-1) - (modified) llvm/include/llvm/Support/CrashRecoveryContext.h (-3) - (removed) llvm/include/llvm/Support/ProgramStack.h (-63) - (modified) llvm/include/llvm/Support/thread.h (-1) - (modified) llvm/lib/Support/CMakeLists.txt (-1) - (modified) llvm/lib/Support/CrashRecoveryContext.cpp (-11) - (removed) llvm/lib/Support/ProgramStack.cpp (-114) - (modified) llvm/unittests/Support/CMakeLists.txt (-1) - (removed) llvm/unittests/Support/ProgramStackTest.cpp (-35) ``````````diff diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 38142ad32bea0..166f26921cb71 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -195,10 +195,6 @@ Non-comprehensive list of changes in this release - Added `__builtin_elementwise_exp10`. - For AMDPGU targets, added `__builtin_v_cvt_off_f32_i4` that maps to the `v_cvt_off_f32_i4` instruction. - Added `__builtin_elementwise_minnum` and `__builtin_elementwise_maxnum`. -- Clang itself now uses split stacks instead of threads for allocating more - stack space when running on Apple AArch64 based platforms. This means that - stack traces of Clang from debuggers, crashes, and profilers may look - different than before. New Compiler Flags ------------------ diff --git a/clang/include/clang/Basic/Stack.h b/clang/include/clang/Basic/Stack.h index 9674b9d9b62c3..30ebd94aedd1f 100644 --- a/clang/include/clang/Basic/Stack.h +++ b/clang/include/clang/Basic/Stack.h @@ -27,10 +27,7 @@ namespace clang { /// Call this once on each thread, as soon after starting the thread as /// feasible, to note the approximate address of the bottom of the stack. - /// - /// \param ForceSet set to true if you know the call is near the bottom of a - /// new stack. Used for split stacks. - void noteBottomOfStack(bool ForceSet = false); + void noteBottomOfStack(); /// Determine whether the stack is nearly exhausted. bool isStackNearlyExhausted(); diff --git a/clang/lib/Basic/Stack.cpp b/clang/lib/Basic/Stack.cpp index 8cbb84943f8d3..aa15d8e66950f 100644 --- a/clang/lib/Basic/Stack.cpp +++ b/clang/lib/Basic/Stack.cpp @@ -13,13 +13,33 @@ #include "clang/Basic/Stack.h" #include "llvm/Support/CrashRecoveryContext.h" -#include "llvm/Support/ProgramStack.h" -static LLVM_THREAD_LOCAL uintptr_t BottomOfStack = 0; +#ifdef _MSC_VER +#include <intrin.h> // for _AddressOfReturnAddress +#endif -void clang::noteBottomOfStack(bool ForceSet) { - if (!BottomOfStack || ForceSet) - BottomOfStack = llvm::getStackPointer(); +static LLVM_THREAD_LOCAL void *BottomOfStack = nullptr; + +static void *getStackPointer() { +#if __GNUC__ || __has_builtin(__builtin_frame_address) + return __builtin_frame_address(0); +#elif defined(_MSC_VER) + return _AddressOfReturnAddress(); +#else + char CharOnStack = 0; + // The volatile store here is intended to escape the local variable, to + // prevent the compiler from optimizing CharOnStack into anything other + // than a char on the stack. + // + // Tested on: MSVC 2015 - 2019, GCC 4.9 - 9, Clang 3.2 - 9, ICC 13 - 19. + char *volatile Ptr = &CharOnStack; + return Ptr; +#endif +} + +void clang::noteBottomOfStack() { + if (!BottomOfStack) + BottomOfStack = getStackPointer(); } bool clang::isStackNearlyExhausted() { @@ -31,8 +51,7 @@ bool clang::isStackNearlyExhausted() { if (!BottomOfStack) return false; - intptr_t StackDiff = - (intptr_t)llvm::getStackPointer() - (intptr_t)BottomOfStack; + intptr_t StackDiff = (intptr_t)getStackPointer() - (intptr_t)BottomOfStack; size_t StackUsage = (size_t)std::abs(StackDiff); // If the stack pointer has a surprising value, we do not understand this @@ -47,12 +66,9 @@ bool clang::isStackNearlyExhausted() { void clang::runWithSufficientStackSpaceSlow(llvm::function_ref<void()> Diag, llvm::function_ref<void()> Fn) { llvm::CrashRecoveryContext CRC; - // Preserve the BottomOfStack in case RunSafelyOnNewStack uses split stacks. - uintptr_t PrevBottom = BottomOfStack; - CRC.RunSafelyOnNewStack([&] { - noteBottomOfStack(true); + CRC.RunSafelyOnThread([&] { + noteBottomOfStack(); Diag(); Fn(); }, DesiredStackSize); - BottomOfStack = PrevBottom; } diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 5fe80fc16482e..243e0a3c15b05 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1265,7 +1265,7 @@ bool CompilerInstance::compileModule(SourceLocation ImportLoc, // Execute the action to actually build the module in-place. Use a separate // thread so that we get a stack large enough. - bool Crashed = !llvm::CrashRecoveryContext().RunSafelyOnNewStack( + bool Crashed = !llvm::CrashRecoveryContext().RunSafelyOnThread( [&]() { GenerateModuleFromModuleMapAction Action; Instance.ExecuteAction(Action); diff --git a/llvm/include/llvm/Support/CrashRecoveryContext.h b/llvm/include/llvm/Support/CrashRecoveryContext.h index 31293d6715757..26ddf97b3ef02 100644 --- a/llvm/include/llvm/Support/CrashRecoveryContext.h +++ b/llvm/include/llvm/Support/CrashRecoveryContext.h @@ -97,9 +97,6 @@ class CrashRecoveryContext { return RunSafelyOnThread([&]() { Fn(UserData); }, RequestedStackSize); } - bool RunSafelyOnNewStack(function_ref<void()>, - unsigned RequestedStackSize = 0); - /// Explicitly trigger a crash recovery in the current process, and /// return failure from RunSafely(). This function does not return. [[noreturn]] void HandleExit(int RetCode); diff --git a/llvm/include/llvm/Support/ProgramStack.h b/llvm/include/llvm/Support/ProgramStack.h deleted file mode 100644 index 232a7b5670b44..0000000000000 --- a/llvm/include/llvm/Support/ProgramStack.h +++ /dev/null @@ -1,63 +0,0 @@ -//===--- ProgramStack.h -----------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SUPPORT_PROGRAMSTACK_H -#define LLVM_SUPPORT_PROGRAMSTACK_H - -#include "llvm/ADT/STLFunctionalExtras.h" - -// LLVM_HAS_SPLIT_STACKS is exposed in the header because CrashRecoveryContext -// needs to know if it's running on another thread or not. -// -// Currently only Apple AArch64 is known to support split stacks in the debugger -// and other tooling. -#if defined(__APPLE__) && defined(__aarch64__) && \ - LLVM_HAS_CPP_ATTRIBUTE(gnu::naked) && __has_extension(gnu_asm) -# define LLVM_HAS_SPLIT_STACKS -# define LLVM_HAS_SPLIT_STACKS_AARCH64 -#endif - -namespace llvm { - -/// \returns an address close to the current value of the stack pointer. -/// -/// The value is not guaranteed to point to anything specific. It can be used to -/// estimate how much stack space has been used since the previous call. -uintptr_t getStackPointer(); - -/// \returns the default stack size for this platform. -/// -/// Based on \p RLIMIT_STACK or the equivalent. -unsigned getDefaultStackSize(); - -/// Runs Fn on a new stack of at least the given size. -/// -/// \param StackSize requested stack size. A size of 0 uses the default stack -/// size of the platform. -/// -/// The preferred implementation is split stacks on platforms that have a good -/// debugging experience for them. On other platforms a new thread is used. -void runOnNewStack(unsigned StackSize, function_ref<void()> Fn); - -template <typename R, typename... Ts> -std::enable_if_t<!std::is_same_v<R, void>, R> -runOnNewStack(unsigned StackSize, function_ref<R(Ts...)> Fn, Ts &&...Args) { - std::optional<R> Ret; - runOnNewStack(StackSize, [&]() { Ret = Fn(std::forward<Ts>(Args)...); }); - return std::move(*Ret); -} - -template <typename... Ts> -void runOnNewStack(unsigned StackSize, function_ref<void(Ts...)> Fn, - Ts &&...Args) { - runOnNewStack(StackSize, [&]() { Fn(std::forward<Ts>(Args)...); }); -} - -} // namespace llvm - -#endif // LLVM_SUPPORT_PROGRAMSTACK_H diff --git a/llvm/include/llvm/Support/thread.h b/llvm/include/llvm/Support/thread.h index ef2fba822cb1c..e3005fdb63175 100644 --- a/llvm/include/llvm/Support/thread.h +++ b/llvm/include/llvm/Support/thread.h @@ -213,7 +213,6 @@ inline thread::id get_id() { return std::this_thread::get_id(); } #else // !LLVM_ENABLE_THREADS -#include "llvm/Support/ErrorHandling.h" #include <utility> namespace llvm { diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt index def37f3f278d0..98ffd829d80b8 100644 --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -295,7 +295,6 @@ add_llvm_component_library(LLVMSupport Path.cpp Process.cpp Program.cpp - ProgramStack.cpp RWMutex.cpp Signals.cpp Threading.cpp diff --git a/llvm/lib/Support/CrashRecoveryContext.cpp b/llvm/lib/Support/CrashRecoveryContext.cpp index 88c38d7526e71..f53aea177d612 100644 --- a/llvm/lib/Support/CrashRecoveryContext.cpp +++ b/llvm/lib/Support/CrashRecoveryContext.cpp @@ -10,7 +10,6 @@ #include "llvm/Config/llvm-config.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ExitCodes.h" -#include "llvm/Support/ProgramStack.h" #include "llvm/Support/Signals.h" #include "llvm/Support/thread.h" #include <cassert> @@ -524,13 +523,3 @@ bool CrashRecoveryContext::RunSafelyOnThread(function_ref<void()> Fn, CRC->setSwitchedThread(); return Info.Result; } - -bool CrashRecoveryContext::RunSafelyOnNewStack(function_ref<void()> Fn, - unsigned RequestedStackSize) { -#ifdef LLVM_HAS_SPLIT_STACKS - return runOnNewStack(RequestedStackSize, - function_ref<bool()>([&]() { return RunSafely(Fn); })); -#else - return RunSafelyOnThread(Fn, RequestedStackSize); -#endif -} diff --git a/llvm/lib/Support/ProgramStack.cpp b/llvm/lib/Support/ProgramStack.cpp deleted file mode 100644 index 9e5a546b34974..0000000000000 --- a/llvm/lib/Support/ProgramStack.cpp +++ /dev/null @@ -1,114 +0,0 @@ -//===--- RunOnNewStack.cpp - Crash Recovery -------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/ProgramStack.h" -#include "llvm/Config/config.h" -#include "llvm/Support/Compiler.h" - -#ifdef LLVM_ON_UNIX -# include <sys/resource.h> // for getrlimit -#endif - -#ifdef _MSC_VER -# include <intrin.h> // for _AddressOfReturnAddress -#endif - -#ifndef LLVM_HAS_SPLIT_STACKS -# include "llvm/Support/thread.h" -#endif - -using namespace llvm; - -uintptr_t llvm::getStackPointer() { -#if __GNUC__ || __has_builtin(__builtin_frame_address) - return (uintptr_t)__builtin_frame_address(0); -#elif defined(_MSC_VER) - return (uintptr_t)_AddressOfReturnAddress(); -#else - volatile char CharOnStack = 0; - // The volatile store here is intended to escape the local variable, to - // prevent the compiler from optimizing CharOnStack into anything other - // than a char on the stack. - // - // Tested on: MSVC 2015 - 2019, GCC 4.9 - 9, Clang 3.2 - 9, ICC 13 - 19. - char *volatile Ptr = &CharOnStack; - return (uintptr_t)Ptr; -#endif -} - -unsigned llvm::getDefaultStackSize() { -#ifdef LLVM_ON_UNIX - rlimit RL; - getrlimit(RLIMIT_STACK, &RL); - return RL.rlim_cur; -#else - // Clang recursively parses, instantiates templates, and evaluates constant - // expressions. We've found 8MiB to be a reasonable stack size given the way - // Clang works and the way C++ is commonly written. - return 8 << 20; -#endif -} - -namespace { -#ifdef LLVM_HAS_SPLIT_STACKS_AARCH64 -[[gnu::naked]] void runOnNewStackImpl(void *Stack, void (*Fn)(void *), - void *Ctx) { - __asm__ volatile( - "mov x16, sp\n\t" - "sub x0, x0, #0x20\n\t" // subtract space from stack - "stp xzr, x16, [x0, #0x00]\n\t" // save old sp - "stp x29, x30, [x0, #0x10]\n\t" // save fp, lr - "mov sp, x0\n\t" // switch to new stack - "add x29, x0, #0x10\n\t" // switch to new frame - ".cfi_def_cfa w29, 16\n\t" - ".cfi_offset w30, -8\n\t" // lr - ".cfi_offset w29, -16\n\t" // fp - - "mov x0, x2\n\t" // Ctx is the only argument - "blr x1\n\t" // call Fn - - "ldp x29, x30, [sp, #0x10]\n\t" // restore fp, lr - "ldp xzr, x16, [sp, #0x00]\n\t" // load old sp - "mov sp, x16\n\t" - "ret" - ); -} -#endif - -#ifdef LLVM_HAS_SPLIT_STACKS -void callback(void *Ctx) { - (*reinterpret_cast<function_ref<void()> *>(Ctx))(); -} -#endif -} // namespace - -#ifdef LLVM_HAS_SPLIT_STACKS -void llvm::runOnNewStack(unsigned StackSize, function_ref<void()> Fn) { - if (StackSize == 0) - StackSize = getDefaultStackSize(); - - // We use malloc here instead of mmap because: - // - it's simpler, - // - many malloc implementations will reuse the allocation in cases where - // we're bouncing accross the edge of a stack boundry, and - // - many malloc implemenations will already provide guard pages for - // allocations this large. - void *Stack = malloc(StackSize); - void *BottomOfStack = (char *)Stack + StackSize; - - runOnNewStackImpl(BottomOfStack, callback, &Fn); - - free(Stack); -} -#else -void llvm::runOnNewStack(unsigned StackSize, function_ref<void()> Fn) { - llvm::thread Thread( - StackSize == 0 ? std::nullopt : std::optional<unsigned>(StackSize), Fn); - Thread.join(); -} -#endif diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt index e5bf820fb4d1c..6c4e7cb689b20 100644 --- a/llvm/unittests/Support/CMakeLists.txt +++ b/llvm/unittests/Support/CMakeLists.txt @@ -70,7 +70,6 @@ add_llvm_unittest(SupportTests PerThreadBumpPtrAllocatorTest.cpp ProcessTest.cpp ProgramTest.cpp - ProgramStackTest.cpp RecyclerTest.cpp RegexTest.cpp ReverseIterationTest.cpp diff --git a/llvm/unittests/Support/ProgramStackTest.cpp b/llvm/unittests/Support/ProgramStackTest.cpp deleted file mode 100644 index 31dfb3b88ade6..0000000000000 --- a/llvm/unittests/Support/ProgramStackTest.cpp +++ /dev/null @@ -1,35 +0,0 @@ -//===- unittest/Support/ProgramStackTest.cpp ------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/ProgramStack.h" -#include "llvm/Support/Process.h" -#include "gtest/gtest.h" - -using namespace llvm; - -static uintptr_t func(int &A) { - A = 7; - return getStackPointer(); -} - -static void func2(int &A) { - A = 5; -} - -TEST(ProgramStackTest, runOnNewStack) { - int A = 0; - uintptr_t Stack = runOnNewStack(0, function_ref<uintptr_t(int &)>(func), A); - EXPECT_EQ(A, 7); - intptr_t StackDiff = (intptr_t)llvm::getStackPointer() - (intptr_t)Stack; - size_t StackDistance = (size_t)std::abs(StackDiff); - // Page size is used as it's large enough to guarantee were not on the same - // stack but not too large to cause spurious failures. - EXPECT_GT(StackDistance, llvm::sys::Process::getPageSizeEstimate()); - runOnNewStack(0, function_ref<void(int &)>(func2), A); - EXPECT_EQ(A, 5); -} `````````` </details> https://github.com/llvm/llvm-project/pull/135865 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits