From: Zachary Turner Date: Thu, 9 Nov 2017 19:31:52 +0000 (+0000) Subject: [Support] Make llvm::Error and Expected faster. X-Git-Tag: llvmorg-6.0.0-rc1~3760 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=18f21a483b863439ed19cdddb966dd9fe0464dcf;p=platform%2Fupstream%2Fllvm.git [Support] Make llvm::Error and Expected faster. Whenever LLVM_ENABLE_ABI_BREAKING_CHECKS is enabled, which is usually the case for example when asserts are enabled, Error's destructor does some additional checking to make sure that that it does not represent an error condition and that it was checked. However, this is -- by definition -- not the likely codepath. Some profiling shows that at least with some compilers, simply calling assertIsChecked -- in a release build with full optimizations -- can account for up to 15% of the entire runtime of the program, even though this function should almost literally be a no-op. The problem is that the assertIsChecked function can be considered too big to inline depending on the compiler's inliner. Since it's unlikely to ever need to failure path though, we can move it out of line and force it to not be inlined, so that the fast path can be inlined. In my test (using lld to link clang with CMAKE_BUILD_TYPE=Release and LLVM_ENABLE_ASSERTIONS=ON), this reduces link time from 27 seconds to 23.5 seconds, which is a solid 15% gain. llvm-svn: 317824 --- diff --git a/llvm/include/llvm/Support/Error.h b/llvm/include/llvm/Support/Error.h index bb40dbe..8567af3 100644 --- a/llvm/include/llvm/Support/Error.h +++ b/llvm/include/llvm/Support/Error.h @@ -246,18 +246,20 @@ public: } private: +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + // assertIsChecked() happens very frequently, but under normal circumstances + // is supposed to be a no-op. So we want it to be inlined, but having a bunch + // of debug prints can cause the function to be too large for inlining. So + // it's important that we define this function out of line so that it can't be + // inlined. + LLVM_ATTRIBUTE_NORETURN + void fatalUncheckedError() const; +#endif + void assertIsChecked() { #if LLVM_ENABLE_ABI_BREAKING_CHECKS - if (!getChecked() || getPtr()) { - dbgs() << "Program aborted due to an unhandled Error:\n"; - if (getPtr()) - getPtr()->log(dbgs()); - else - dbgs() - << "Error value was Success. (Note: Success values must still be " - "checked prior to being destroyed).\n"; - abort(); - } + if (LLVM_UNLIKELY(!getChecked() || getPtr())) + fatalUncheckedError(); #endif } @@ -632,19 +634,26 @@ private: #endif } +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + LLVM_ATTRIBUTE_NORETURN + LLVM_ATTRIBUTE_NOINLINE + void fatalUncheckedExpected() const { + dbgs() << "Expected must be checked before access or destruction.\n"; + if (HasError) { + dbgs() << "Unchecked Expected contained error:\n"; + (*getErrorStorage())->log(dbgs()); + } else + dbgs() << "Expected value was in success state. (Note: Expected " + "values in success mode must still be checked prior to being " + "destroyed).\n"; + abort(); + } +#endif + void assertIsChecked() { #if LLVM_ENABLE_ABI_BREAKING_CHECKS - if (Unchecked) { - dbgs() << "Expected must be checked before access or destruction.\n"; - if (HasError) { - dbgs() << "Unchecked Expected contained error:\n"; - (*getErrorStorage())->log(dbgs()); - } else - dbgs() << "Expected value was in success state. (Note: Expected " - "values in success mode must still be checked prior to being " - "destroyed).\n"; - abort(); - } + if (LLVM_UNLIKELY(Unchecked)) + fatalUncheckedExpected(); #endif } diff --git a/llvm/lib/Support/Error.cpp b/llvm/lib/Support/Error.cpp index bb02c03..c43a1fa 100644 --- a/llvm/lib/Support/Error.cpp +++ b/llvm/lib/Support/Error.cpp @@ -91,6 +91,18 @@ std::error_code errorToErrorCode(Error Err) { return EC; } +#if LLVM_ENABLE_ABI_BREAKING_CHECKS +void Error::fatalUncheckedError() const { + dbgs() << "Program aborted due to an unhandled Error:\n"; + if (getPtr()) + getPtr()->log(dbgs()); + else + dbgs() << "Error value was Success. (Note: Success values must still be " + "checked prior to being destroyed).\n"; + abort(); +} +#endif + StringError::StringError(const Twine &S, std::error_code EC) : Msg(S.str()), EC(EC) {}