mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 12:12:47 +01:00
61d980d677
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
141 lines
3.8 KiB
C++
141 lines
3.8 KiB
C++
//===----- lib/Support/Error.cpp - Error and associated utilities ---------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/ADT/Twine.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/ManagedStatic.h"
|
|
#include <system_error>
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
|
|
enum class ErrorErrorCode : int {
|
|
MultipleErrors = 1,
|
|
InconvertibleError
|
|
};
|
|
|
|
// FIXME: This class is only here to support the transition to llvm::Error. It
|
|
// will be removed once this transition is complete. Clients should prefer to
|
|
// deal with the Error value directly, rather than converting to error_code.
|
|
class ErrorErrorCategory : public std::error_category {
|
|
public:
|
|
const char *name() const noexcept override { return "Error"; }
|
|
|
|
std::string message(int condition) const override {
|
|
switch (static_cast<ErrorErrorCode>(condition)) {
|
|
case ErrorErrorCode::MultipleErrors:
|
|
return "Multiple errors";
|
|
case ErrorErrorCode::InconvertibleError:
|
|
return "Inconvertible error value. An error has occurred that could "
|
|
"not be converted to a known std::error_code. Please file a "
|
|
"bug.";
|
|
}
|
|
llvm_unreachable("Unhandled error code");
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
static ManagedStatic<ErrorErrorCategory> ErrorErrorCat;
|
|
|
|
namespace llvm {
|
|
|
|
void ErrorInfoBase::anchor() {}
|
|
char ErrorInfoBase::ID = 0;
|
|
char ErrorList::ID = 0;
|
|
char ECError::ID = 0;
|
|
char StringError::ID = 0;
|
|
|
|
void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner) {
|
|
if (!E)
|
|
return;
|
|
OS << ErrorBanner;
|
|
handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) {
|
|
EI.log(OS);
|
|
OS << "\n";
|
|
});
|
|
}
|
|
|
|
|
|
std::error_code ErrorList::convertToErrorCode() const {
|
|
return std::error_code(static_cast<int>(ErrorErrorCode::MultipleErrors),
|
|
*ErrorErrorCat);
|
|
}
|
|
|
|
std::error_code inconvertibleErrorCode() {
|
|
return std::error_code(static_cast<int>(ErrorErrorCode::InconvertibleError),
|
|
*ErrorErrorCat);
|
|
}
|
|
|
|
Error errorCodeToError(std::error_code EC) {
|
|
if (!EC)
|
|
return Error::success();
|
|
return Error(llvm::make_unique<ECError>(ECError(EC)));
|
|
}
|
|
|
|
std::error_code errorToErrorCode(Error Err) {
|
|
std::error_code EC;
|
|
handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
|
|
EC = EI.convertToErrorCode();
|
|
});
|
|
if (EC == inconvertibleErrorCode())
|
|
report_fatal_error(EC.message());
|
|
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) {}
|
|
|
|
void StringError::log(raw_ostream &OS) const { OS << Msg; }
|
|
|
|
std::error_code StringError::convertToErrorCode() const {
|
|
return EC;
|
|
}
|
|
|
|
void report_fatal_error(Error Err, bool GenCrashDiag) {
|
|
assert(Err && "report_fatal_error called with success value");
|
|
std::string ErrMsg;
|
|
{
|
|
raw_string_ostream ErrStream(ErrMsg);
|
|
logAllUnhandledErrors(std::move(Err), ErrStream, "");
|
|
}
|
|
report_fatal_error(ErrMsg);
|
|
}
|
|
|
|
}
|
|
|
|
#ifndef _MSC_VER
|
|
namespace llvm {
|
|
|
|
// One of these two variables will be referenced by a symbol defined in
|
|
// llvm-config.h. We provide a link-time (or load time for DSO) failure when
|
|
// there is a mismatch in the build configuration of the API client and LLVM.
|
|
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
|
|
int EnableABIBreakingChecks;
|
|
#else
|
|
int DisableABIBreakingChecks;
|
|
#endif
|
|
|
|
} // end namespace llvm
|
|
#endif
|