https://github.com/halide/Halide
Tip revision: f9e4c7878385f43cf88cca23d5bd663233e9e7da authored by Steven Johnson on 27 April 2021, 19:14:54 UTC
Add support for dynamic tensors to hannk (#5942)
Add support for dynamic tensors to hannk (#5942)
Tip revision: f9e4c78
Error.h
#ifndef HALIDE_ERROR_H
#define HALIDE_ERROR_H
#include <sstream>
#include <stdexcept>
#include "Debug.h"
#include "runtime/HalideRuntime.h" // for HALIDE_ALWAYS_INLINE
namespace Halide {
/** Query whether Halide was compiled with exceptions. */
bool exceptions_enabled();
/** A base class for Halide errors. */
struct Error : public std::runtime_error {
// Give each class a non-inlined constructor so that the type
// doesn't get separately instantiated in each compilation unit.
Error(const std::string &msg);
};
/** An error that occurs while running a JIT-compiled Halide pipeline. */
struct RuntimeError : public Error {
RuntimeError(const std::string &msg);
};
/** An error that occurs while compiling a Halide pipeline that Halide
* attributes to a user error. */
struct CompileError : public Error {
CompileError(const std::string &msg);
};
/** An error that occurs while compiling a Halide pipeline that Halide
* attributes to an internal compiler bug, or to an invalid use of
* Halide's internals. */
struct InternalError : public Error {
InternalError(const std::string &msg);
};
/** CompileTimeErrorReporter is used at compile time (*not* runtime) when
* an error or warning is generated by Halide. Note that error() is called
* a fatal error has occurred, and returning to Halide may cause a crash;
* implementations of CompileTimeErrorReporter::error() should never return.
* (Implementations of CompileTimeErrorReporter::warning() may return but
* may also abort(), exit(), etc.)
*/
class CompileTimeErrorReporter {
public:
virtual ~CompileTimeErrorReporter() = default;
virtual void warning(const char *msg) = 0;
virtual void error(const char *msg) = 0;
};
/** The default error reporter logs to stderr, then throws an exception
* (if HALIDE_WITH_EXCEPTIONS) or calls abort (if not). This allows customization
* of that behavior if a more gentle response to error reporting is desired.
* Note that error_reporter is expected to remain valid across all Halide usage;
* it is up to the caller to ensure that this is the case (and to do any
* cleanup necessary).
*/
void set_custom_compile_time_error_reporter(CompileTimeErrorReporter *error_reporter);
namespace Internal {
struct ErrorReport {
enum {
User = 0x0001,
Warning = 0x0002,
Runtime = 0x0004
};
std::ostringstream msg;
const int flags;
ErrorReport(const char *f, int l, const char *cs, int flags);
// Just a trick used to convert RValue into LValue
HALIDE_ALWAYS_INLINE ErrorReport &ref() {
return *this;
}
template<typename T>
ErrorReport &operator<<(const T &x) {
msg << x;
return *this;
}
/** When you're done using << on the object, and let it fall out of
* scope, this errors out, or throws an exception if they are
* enabled. This is a little dangerous because the destructor will
* also be called if there's an exception in flight due to an
* error in one of the arguments passed to operator<<. We handle
* this by only actually throwing if there isn't an exception in
* flight already.
*/
#if __cplusplus >= 201100 || _MSC_VER >= 1900
~ErrorReport() noexcept(false);
#else
~ErrorReport();
#endif
};
// This uses operator precedence as a trick to avoid argument evaluation if
// an assertion is true: it is intended to be used as part of the
// _halide_internal_assertion macro, to coerce the result of the stream
// expression to void (to match the condition-is-false case).
class Voidifier {
public:
HALIDE_ALWAYS_INLINE Voidifier() = default;
// This has to be an operator with a precedence lower than << but
// higher than ?:
HALIDE_ALWAYS_INLINE void operator&(ErrorReport &) {
}
};
/**
* _halide_internal_assertion is used to implement our assertion macros
* in such a way that the messages output for the assertion are only
* evaluated if the assertion's value is false.
*
* Note that this macro intentionally has no parens internally; in actual
* use, the implicit grouping will end up being
*
* condition ? (void) : (Voidifier() & (ErrorReport << arg1 << arg2 ... << argN))
*
* This (regrettably) requires a macro to work, but has the highly desirable
* effect that all assertion parameters are totally skipped (not ever evaluated)
* when the assertion is true.
*/
#define _halide_internal_assertion(condition, flags) \
/* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
(condition) ? (void)0 : ::Halide::Internal::Voidifier() & ::Halide::Internal::ErrorReport(__FILE__, __LINE__, #condition, flags).ref()
#define internal_error Halide::Internal::ErrorReport(__FILE__, __LINE__, nullptr, 0)
#define user_error Halide::Internal::ErrorReport(__FILE__, __LINE__, nullptr, Halide::Internal::ErrorReport::User)
#define user_warning Halide::Internal::ErrorReport(__FILE__, __LINE__, nullptr, Halide::Internal::ErrorReport::User | Halide::Internal::ErrorReport::Warning)
#define halide_runtime_error Halide::Internal::ErrorReport(__FILE__, __LINE__, nullptr, Halide::Internal::ErrorReport::User | Halide::Internal::ErrorReport::Runtime)
#define internal_assert(c) _halide_internal_assertion(c, 0)
#define user_assert(c) _halide_internal_assertion(c, Halide::Internal::ErrorReport::User)
// The nicely named versions get cleaned up at the end of Halide.h,
// but user code might want to do halide-style user_asserts (e.g. the
// Extern macros introduce calls to user_assert), so for that purpose
// we define an equivalent macro that can be used outside of Halide.h
#define _halide_user_assert(c) _halide_internal_assertion(c, Halide::Internal::ErrorReport::User)
// N.B. Any function that might throw a user_assert or user_error may
// not be inlined into the user's code, or the line number will be
// misattributed to Halide.h. Either make such functions internal to
// libHalide, or mark them as HALIDE_NO_USER_CODE_INLINE.
} // namespace Internal
} // namespace Halide
#endif