Index: parallel-libs/trunk/streamexecutor/include/streamexecutor/Device.h =================================================================== --- parallel-libs/trunk/streamexecutor/include/streamexecutor/Device.h +++ parallel-libs/trunk/streamexecutor/include/streamexecutor/Device.h @@ -17,9 +17,9 @@ #include +#include "streamexecutor/Error.h" #include "streamexecutor/KernelSpec.h" #include "streamexecutor/PlatformDevice.h" -#include "streamexecutor/Utils/Error.h" namespace streamexecutor { Index: parallel-libs/trunk/streamexecutor/include/streamexecutor/DeviceMemory.h =================================================================== --- parallel-libs/trunk/streamexecutor/include/streamexecutor/DeviceMemory.h +++ parallel-libs/trunk/streamexecutor/include/streamexecutor/DeviceMemory.h @@ -32,7 +32,7 @@ #include #include -#include "streamexecutor/Utils/Error.h" +#include "streamexecutor/Error.h" namespace streamexecutor { Index: parallel-libs/trunk/streamexecutor/include/streamexecutor/Error.h =================================================================== --- parallel-libs/trunk/streamexecutor/include/streamexecutor/Error.h +++ parallel-libs/trunk/streamexecutor/include/streamexecutor/Error.h @@ -0,0 +1,215 @@ +//===-- Error.h - Error handling --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Error types used in the public API and internally in StreamExecutor. +/// +/// StreamExecutor's error handling is based on the types streamexecutor::Error +/// and streamexecutor::Expected. +/// +/// +/// \section error The Error Class +/// +/// The Error class either represents success or contains an error message +/// describing the cause of the error. Error instances are created by calling +/// Error::success for successes or make_error for errors. +/// +/// \code{.cpp} +/// Error achieveWorldPeace() { +/// if (WorldPeaceAlreadyAchieved) { +/// return Error::success(); +/// } else { +/// return make_error("Can't someone else do it?"); +/// } +/// } +/// \endcode +/// +/// Error instances are implicitly convertible to bool. Error values convert to +/// true and successes convert to false. Error instances must have their boolean +/// values checked or they must be moved before they go out of scope, otherwise +/// their destruction will cause the program to abort with a warning about an +/// unchecked Error. +/// +/// If the Error represents success, then checking the boolean value is all that +/// is required, but if the Error represents a real error, the Error value must +/// be consumed. The function consumeAndGetMessage is the way to extract the +/// error message from an Error and consume the Error at the same time, so +/// typical error handling will first check whether there was an error and then +/// extract the error message if so. Here is an example: +/// +/// \code{.cpp} +/// if (Error E = achieveWorldPeace()) { +/// printf("An error occurred: %s\n", consumeAndGetMessage(E).c_str()); +/// exit(EXIT_FAILURE): +/// } +/// \endcode +/// +/// It is also common to simply pass an error along up the call stack if it +/// cannot be handled in the current function. +/// +/// \code{.cpp} +/// Error doTask() { +/// if (Error E = achieveWorldPeace()) { +/// return E; +/// } +/// ... +/// } +/// \endcode +/// +/// There is also a function consumeError that consumes an error value without +/// fetching the error message. This is useful when we want to ignore an error. +/// +/// The dieIfError function is also provided for quick-and-dirty error handling. +/// +/// +/// \section expected The Expected Class +/// +/// The Expected class either represents a value of type T or an Error. +/// Expected has one constructor that takes a T value and another constructor +/// that takes an Error rvalue reference, so Expected instances can be +/// constructed either from values or from errors: +/// +/// \code{.cpp} +/// Expected getMyFavoriteInt() { +/// int MyFavorite = 42; +/// if (IsThereAFavorite) { +/// return MyFavorite; +/// } else { +/// return make_error("I don't have a favorite"); +/// } +/// } +/// \endcode +/// +/// Expected instances are implicitly convertible to bool and are true if +/// they contain a value and false if they contain an error. Note that this is +/// the opposite convention of the Error type conversion to bool, where true +/// meant error and false meant success. +/// +/// If the Expected instance is not an error, the stored value can be +/// obtained by using operator*. If access to members of the value are desired +/// instead of the value itself, operator-> can be used as well. +/// +/// Expected instances must have their boolean value checked or they must be +/// moved before they go out of scope, otherwise they will cause the program to +/// abort with a warning about an unchecked error. If the Expected instance +/// contains a value, then checking the boolean value is all that is required, +/// but if it contains an Error object, that Error object must be handled by +/// calling Expected::takeError() to get the underlying error. +/// +/// Here is an example of the use of an Expected value returned from a +/// function: +/// +/// \code{.cpp} +/// Expected ExpectedInt = getMyFavoriteInt(); +/// if (ExpectedInt) { +/// printf("My favorite integer is %d\n", *ExpectedInt); +/// } else { +/// printf("An error occurred: %s\n", +/// consumeAndGetMessage(ExpectedInt.takeError())); +/// exit(EXIT_FAILURE); +/// } +/// \endcode +/// +/// The following snippet shows some examples of how Errors and Expected values +/// can be passed up the stack if they should not be handled in the current +/// function. +/// +/// \code{.cpp} +/// Expected doTask3() { +/// Error WorldPeaceError = achieveWorldPeace(); +/// if (!WorldPeaceError) { +/// return WorldPeaceError; +/// } +/// +/// Expected ExpectedMartian = getMyFavoriteMartian(); +/// if (!ExpectedMartian) { +/// // Must extract the error because martian cannot be converted to double. +/// return ExpectedMartian.takeError(): +/// } +/// +/// // It's fine to return Expected for Expected because int can +/// // be converted to double. +/// return getMyFavoriteInt(); +/// } +/// \endcode +/// +/// The getOrDie function is also available for quick-and-dirty error handling. +/// +/// +/// \section llvm Relation to llvm::Error and llvm::Expected +/// +/// The streamexecutor::Error and streamexecutor::Expected classes are actually +/// just their LLVM counterparts redeclared in the streamexectuor namespace, but +/// they should be treated as separate types, even so. +/// +/// StreamExecutor does not support any underlying llvm::ErrorInfo class except +/// the one it defines internally for itself, so a streamexecutor::Error can be +/// thought of as a restricted llvm::Error that is guaranteed to hold a specific +/// error type. +/// +/// Although code may compile if llvm functions used to handle these +/// StreamExecutor error types, it is likely that code will lead to runtime +/// errors, so it is strongly recommended that only the functions from the +/// streamexecutor namespace are used on these StreamExecutor error types. +/// +//===----------------------------------------------------------------------===// + +#ifndef STREAMEXECUTOR_ERROR_H +#define STREAMEXECUTOR_ERROR_H + +#include +#include +#include +#include + +#include "llvm/Support/Error.h" + +namespace streamexecutor { + +using llvm::consumeError; +using llvm::Error; +using llvm::Expected; +using llvm::Twine; + +/// Makes an Error object from an error message. +Error make_error(Twine Message); + +/// Consumes the input error and returns its error message. +/// +/// Assumes the input was created by the make_error function above. +std::string consumeAndGetMessage(Error &&E); + +/// Extracts the T value from an Expected or prints an error message to +/// stderr and exits the program with code EXIT_FAILURE if the Expected is an +/// error. +/// +/// This function and the dieIfError function are provided for applications that +/// are OK with aborting the program if an error occurs, and which don't have +/// any special error logging needs. Applications with different error handling +/// needs will likely want to declare their own functions with similar +/// signatures but which log error messages in a different way or attempt to +/// recover from errors instead of aborting the program. +template T getOrDie(Expected &&E) { + if (!E) { + std::fprintf(stderr, "Error extracting an expected value: %s.\n", + consumeAndGetMessage(E.takeError()).c_str()); + std::exit(EXIT_FAILURE); + } + return std::move(*E); +} + +/// Prints an error message to stderr and exits the program with code +/// EXIT_FAILURE if the input is an error. +/// +/// \sa getOrDie +void dieIfError(Error &&E); + +} // namespace streamexecutor + +#endif // STREAMEXECUTOR_ERROR_H Index: parallel-libs/trunk/streamexecutor/include/streamexecutor/Kernel.h =================================================================== --- parallel-libs/trunk/streamexecutor/include/streamexecutor/Kernel.h +++ parallel-libs/trunk/streamexecutor/include/streamexecutor/Kernel.h @@ -21,8 +21,8 @@ #ifndef STREAMEXECUTOR_KERNEL_H #define STREAMEXECUTOR_KERNEL_H +#include "streamexecutor/Error.h" #include "streamexecutor/KernelSpec.h" -#include "streamexecutor/Utils/Error.h" #include Index: parallel-libs/trunk/streamexecutor/include/streamexecutor/Platform.h =================================================================== --- parallel-libs/trunk/streamexecutor/include/streamexecutor/Platform.h +++ parallel-libs/trunk/streamexecutor/include/streamexecutor/Platform.h @@ -18,7 +18,7 @@ #ifndef STREAMEXECUTOR_PLATFORM_H #define STREAMEXECUTOR_PLATFORM_H -#include "streamexecutor/Utils/Error.h" +#include "streamexecutor/Error.h" namespace streamexecutor { Index: parallel-libs/trunk/streamexecutor/include/streamexecutor/PlatformDevice.h =================================================================== --- parallel-libs/trunk/streamexecutor/include/streamexecutor/PlatformDevice.h +++ parallel-libs/trunk/streamexecutor/include/streamexecutor/PlatformDevice.h @@ -20,10 +20,10 @@ #define STREAMEXECUTOR_PLATFORMDEVICE_H #include "streamexecutor/DeviceMemory.h" +#include "streamexecutor/Error.h" #include "streamexecutor/Kernel.h" #include "streamexecutor/LaunchDimensions.h" #include "streamexecutor/PackedKernelArgumentArray.h" -#include "streamexecutor/Utils/Error.h" namespace streamexecutor { Index: parallel-libs/trunk/streamexecutor/include/streamexecutor/PlatformManager.h =================================================================== --- parallel-libs/trunk/streamexecutor/include/streamexecutor/PlatformManager.h +++ parallel-libs/trunk/streamexecutor/include/streamexecutor/PlatformManager.h @@ -21,8 +21,8 @@ #include +#include "streamexecutor/Error.h" #include "streamexecutor/Platform.h" -#include "streamexecutor/Utils/Error.h" namespace streamexecutor { Index: parallel-libs/trunk/streamexecutor/include/streamexecutor/Stream.h =================================================================== --- parallel-libs/trunk/streamexecutor/include/streamexecutor/Stream.h +++ parallel-libs/trunk/streamexecutor/include/streamexecutor/Stream.h @@ -35,11 +35,11 @@ #include #include "streamexecutor/DeviceMemory.h" +#include "streamexecutor/Error.h" #include "streamexecutor/Kernel.h" #include "streamexecutor/LaunchDimensions.h" #include "streamexecutor/PackedKernelArgumentArray.h" #include "streamexecutor/PlatformDevice.h" -#include "streamexecutor/Utils/Error.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/Twine.h" Index: parallel-libs/trunk/streamexecutor/include/streamexecutor/Utils/Error.h =================================================================== --- parallel-libs/trunk/streamexecutor/include/streamexecutor/Utils/Error.h +++ parallel-libs/trunk/streamexecutor/include/streamexecutor/Utils/Error.h @@ -1,215 +0,0 @@ -//===-- Error.h - Error handling --------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Error types used in the public API and internally in StreamExecutor. -/// -/// StreamExecutor's error handling is based on the types streamexecutor::Error -/// and streamexecutor::Expected. -/// -/// -/// \section error The Error Class -/// -/// The Error class either represents success or contains an error message -/// describing the cause of the error. Error instances are created by calling -/// Error::success for successes or make_error for errors. -/// -/// \code{.cpp} -/// Error achieveWorldPeace() { -/// if (WorldPeaceAlreadyAchieved) { -/// return Error::success(); -/// } else { -/// return make_error("Can't someone else do it?"); -/// } -/// } -/// \endcode -/// -/// Error instances are implicitly convertible to bool. Error values convert to -/// true and successes convert to false. Error instances must have their boolean -/// values checked or they must be moved before they go out of scope, otherwise -/// their destruction will cause the program to abort with a warning about an -/// unchecked Error. -/// -/// If the Error represents success, then checking the boolean value is all that -/// is required, but if the Error represents a real error, the Error value must -/// be consumed. The function consumeAndGetMessage is the way to extract the -/// error message from an Error and consume the Error at the same time, so -/// typical error handling will first check whether there was an error and then -/// extract the error message if so. Here is an example: -/// -/// \code{.cpp} -/// if (Error E = achieveWorldPeace()) { -/// printf("An error occurred: %s\n", consumeAndGetMessage(E).c_str()); -/// exit(EXIT_FAILURE): -/// } -/// \endcode -/// -/// It is also common to simply pass an error along up the call stack if it -/// cannot be handled in the current function. -/// -/// \code{.cpp} -/// Error doTask() { -/// if (Error E = achieveWorldPeace()) { -/// return E; -/// } -/// ... -/// } -/// \endcode -/// -/// There is also a function consumeError that consumes an error value without -/// fetching the error message. This is useful when we want to ignore an error. -/// -/// The dieIfError function is also provided for quick-and-dirty error handling. -/// -/// -/// \section expected The Expected Class -/// -/// The Expected class either represents a value of type T or an Error. -/// Expected has one constructor that takes a T value and another constructor -/// that takes an Error rvalue reference, so Expected instances can be -/// constructed either from values or from errors: -/// -/// \code{.cpp} -/// Expected getMyFavoriteInt() { -/// int MyFavorite = 42; -/// if (IsThereAFavorite) { -/// return MyFavorite; -/// } else { -/// return make_error("I don't have a favorite"); -/// } -/// } -/// \endcode -/// -/// Expected instances are implicitly convertible to bool and are true if -/// they contain a value and false if they contain an error. Note that this is -/// the opposite convention of the Error type conversion to bool, where true -/// meant error and false meant success. -/// -/// If the Expected instance is not an error, the stored value can be -/// obtained by using operator*. If access to members of the value are desired -/// instead of the value itself, operator-> can be used as well. -/// -/// Expected instances must have their boolean value checked or they must be -/// moved before they go out of scope, otherwise they will cause the program to -/// abort with a warning about an unchecked error. If the Expected instance -/// contains a value, then checking the boolean value is all that is required, -/// but if it contains an Error object, that Error object must be handled by -/// calling Expected::takeError() to get the underlying error. -/// -/// Here is an example of the use of an Expected value returned from a -/// function: -/// -/// \code{.cpp} -/// Expected ExpectedInt = getMyFavoriteInt(); -/// if (ExpectedInt) { -/// printf("My favorite integer is %d\n", *ExpectedInt); -/// } else { -/// printf("An error occurred: %s\n", -/// consumeAndGetMessage(ExpectedInt.takeError())); -/// exit(EXIT_FAILURE); -/// } -/// \endcode -/// -/// The following snippet shows some examples of how Errors and Expected values -/// can be passed up the stack if they should not be handled in the current -/// function. -/// -/// \code{.cpp} -/// Expected doTask3() { -/// Error WorldPeaceError = achieveWorldPeace(); -/// if (!WorldPeaceError) { -/// return WorldPeaceError; -/// } -/// -/// Expected ExpectedMartian = getMyFavoriteMartian(); -/// if (!ExpectedMartian) { -/// // Must extract the error because martian cannot be converted to double. -/// return ExpectedMartian.takeError(): -/// } -/// -/// // It's fine to return Expected for Expected because int can -/// // be converted to double. -/// return getMyFavoriteInt(); -/// } -/// \endcode -/// -/// The getOrDie function is also available for quick-and-dirty error handling. -/// -/// -/// \section llvm Relation to llvm::Error and llvm::Expected -/// -/// The streamexecutor::Error and streamexecutor::Expected classes are actually -/// just their LLVM counterparts redeclared in the streamexectuor namespace, but -/// they should be treated as separate types, even so. -/// -/// StreamExecutor does not support any underlying llvm::ErrorInfo class except -/// the one it defines internally for itself, so a streamexecutor::Error can be -/// thought of as a restricted llvm::Error that is guaranteed to hold a specific -/// error type. -/// -/// Although code may compile if llvm functions used to handle these -/// StreamExecutor error types, it is likely that code will lead to runtime -/// errors, so it is strongly recommended that only the functions from the -/// streamexecutor namespace are used on these StreamExecutor error types. -/// -//===----------------------------------------------------------------------===// - -#ifndef STREAMEXECUTOR_UTILS_ERROR_H -#define STREAMEXECUTOR_UTILS_ERROR_H - -#include -#include -#include -#include - -#include "llvm/Support/Error.h" - -namespace streamexecutor { - -using llvm::consumeError; -using llvm::Error; -using llvm::Expected; -using llvm::Twine; - -/// Makes an Error object from an error message. -Error make_error(Twine Message); - -/// Consumes the input error and returns its error message. -/// -/// Assumes the input was created by the make_error function above. -std::string consumeAndGetMessage(Error &&E); - -/// Extracts the T value from an Expected or prints an error message to -/// stderr and exits the program with code EXIT_FAILURE if the Expected is an -/// error. -/// -/// This function and the dieIfError function are provided for applications that -/// are OK with aborting the program if an error occurs, and which don't have -/// any special error logging needs. Applications with different error handling -/// needs will likely want to declare their own functions with similar -/// signatures but which log error messages in a different way or attempt to -/// recover from errors instead of aborting the program. -template T getOrDie(Expected &&E) { - if (!E) { - std::fprintf(stderr, "Error extracting an expected value: %s.\n", - consumeAndGetMessage(E.takeError()).c_str()); - std::exit(EXIT_FAILURE); - } - return std::move(*E); -} - -/// Prints an error message to stderr and exits the program with code -/// EXIT_FAILURE if the input is an error. -/// -/// \sa getOrDie -void dieIfError(Error &&E); - -} // namespace streamexecutor - -#endif // STREAMEXECUTOR_UTILS_ERROR_H Index: parallel-libs/trunk/streamexecutor/lib/CMakeLists.txt =================================================================== --- parallel-libs/trunk/streamexecutor/lib/CMakeLists.txt +++ parallel-libs/trunk/streamexecutor/lib/CMakeLists.txt @@ -3,12 +3,11 @@ set_target_properties(${name} PROPERTIES FOLDER "streamexecutor libraries") endmacro(add_se_library) -add_subdirectory(Utils) - add_se_library( streamexecutor Device.cpp DeviceMemory.cpp + Error.cpp Kernel.cpp KernelSpec.cpp PackedKernelArgumentArray.cpp @@ -16,9 +15,6 @@ PlatformDevice.cpp PlatformManager.cpp Stream.cpp - - LINK_LIBS - utils ) install(TARGETS streamexecutor DESTINATION lib) Index: parallel-libs/trunk/streamexecutor/lib/Error.cpp =================================================================== --- parallel-libs/trunk/streamexecutor/lib/Error.cpp +++ parallel-libs/trunk/streamexecutor/lib/Error.cpp @@ -0,0 +1,71 @@ +//===-- Error.cpp - Error handling ----------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Types for returning recoverable errors. +/// +//===----------------------------------------------------------------------===// + +#include "streamexecutor/Error.h" + +#include "llvm/ADT/StringRef.h" + +namespace { + +// An error with a string message describing the cause. +class StreamExecutorError : public llvm::ErrorInfo { +public: + StreamExecutorError(llvm::StringRef Message) : Message(Message.str()) {} + + void log(llvm::raw_ostream &OS) const override { OS << Message; } + + std::error_code convertToErrorCode() const override { + llvm_unreachable( + "StreamExecutorError does not support conversion to std::error_code"); + } + + std::string getErrorMessage() const { return Message; } + + static char ID; + +private: + std::string Message; +}; + +char StreamExecutorError::ID = 0; + +} // namespace + +namespace streamexecutor { + +Error make_error(Twine Message) { + return llvm::make_error(Message.str()); +} + +std::string consumeAndGetMessage(Error &&E) { + if (!E) { + return "success"; + } + std::string Message; + llvm::handleAllErrors(std::move(E), + [&Message](const StreamExecutorError &SEE) { + Message = SEE.getErrorMessage(); + }); + return Message; +} + +void dieIfError(Error &&E) { + if (E) { + std::fprintf(stderr, "Error encountered: %s.\n", + streamexecutor::consumeAndGetMessage(std::move(E)).c_str()); + std::exit(EXIT_FAILURE); + } +} + +} // namespace streamexecutor Index: parallel-libs/trunk/streamexecutor/lib/Utils/CMakeLists.txt =================================================================== --- parallel-libs/trunk/streamexecutor/lib/Utils/CMakeLists.txt +++ parallel-libs/trunk/streamexecutor/lib/Utils/CMakeLists.txt @@ -1,3 +0,0 @@ -add_se_library( - utils - Error.cpp) Index: parallel-libs/trunk/streamexecutor/lib/Utils/Error.cpp =================================================================== --- parallel-libs/trunk/streamexecutor/lib/Utils/Error.cpp +++ parallel-libs/trunk/streamexecutor/lib/Utils/Error.cpp @@ -1,71 +0,0 @@ -//===-- Error.cpp - Error handling ----------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Types for returning recoverable errors. -/// -//===----------------------------------------------------------------------===// - -#include "streamexecutor/Utils/Error.h" - -#include "llvm/ADT/StringRef.h" - -namespace { - -// An error with a string message describing the cause. -class StreamExecutorError : public llvm::ErrorInfo { -public: - StreamExecutorError(llvm::StringRef Message) : Message(Message.str()) {} - - void log(llvm::raw_ostream &OS) const override { OS << Message; } - - std::error_code convertToErrorCode() const override { - llvm_unreachable( - "StreamExecutorError does not support conversion to std::error_code"); - } - - std::string getErrorMessage() const { return Message; } - - static char ID; - -private: - std::string Message; -}; - -char StreamExecutorError::ID = 0; - -} // namespace - -namespace streamexecutor { - -Error make_error(Twine Message) { - return llvm::make_error(Message.str()); -} - -std::string consumeAndGetMessage(Error &&E) { - if (!E) { - return "success"; - } - std::string Message; - llvm::handleAllErrors(std::move(E), - [&Message](const StreamExecutorError &SEE) { - Message = SEE.getErrorMessage(); - }); - return Message; -} - -void dieIfError(Error &&E) { - if (E) { - std::fprintf(stderr, "Error encountered: %s.\n", - streamexecutor::consumeAndGetMessage(std::move(E)).c_str()); - std::exit(EXIT_FAILURE); - } -} - -} // namespace streamexecutor