`StreamWrapper` is a class that wraps a stream of any type. It has a
`flush` method, that, when called with a `std::stringstream` copies all
of its content in the wrapped stream.
The main reason for having `StreamWrapper` is being able to have a
`dumpInternal` method in a `.cpp` file while preserving a
stream-agnostic `dump` method in the header.
A set of assertion-related functions has been introduced:
* `revng_abort(message)`: aborts, in release builds too.
* `revng_check(what, message)`: asserts `what`, in release builds
too. Also emits a `__builtin_assume`, that can lead to additional
optimizations in clang.
* `revng_unreahcable(message)`: identical to `revng_abort`, but in
release builds emits `__built_unreachable`.
* `revng_assert(what, message)`: asserts in debug builds, otherwise
emits `sizeof(what)` (to suppress unused variable warnings) and
`__builtin_assume`.
The adoption of these function has the following benefits:
* Nice stack traces.
* The developer can choose to enforce an `assert` (or an `unreachable`)
at release-time too by using `check`/`abort`.
* Most warnings about unused variables in release mode should be gone.
* When using clang, the `assert`s become `assume`s, which might enable
additional optimizations (with no run-time costs).
* The `assert(Condition && "Reason")` trick is no longer needed, we now
have a proper argument.
This commit introduces a `dump` method for `OSR` and `BoundedValue` for
easier debugging within gdb. It also introduces `debug_function`, a
definition that wraps attributes to ensure the function is emitted even
if unused and emitted as a standalone function that can be called from
gdb.
Check that the calling `unindent()` never reduces the indentation
"below" zero, causing `IndentLevel` to wrap around to high numbers.
If it drops below zero it's a bug anyway, so assert!
`Logger` is the new infrastructrure for debug messages. They are
supposed to be used by just creating a global variable in a translation
unit and then writing there directly as if they were a stream.
Key features:
* Self-registration: a `Logger` by default register itself automatically
in a register. This means that at run-time, unlike with `DBG`, we have
a list of all the possible `Logger`s. One benefit of this approach is
being able to list all the available `Logger`s in `--help`.
* Indentation: `Logger`s can be indented. In particular the
`LoggerIndent` helper class can automatically indent a certain
`Logger` during the lifetime of its instance.
* Atomic messages: a message is no longer simply delimited by a "\n": to
mark the end of a message, an instance of `LogTerminator` has to be
streamed to the `Logger`. This can also be associated directly to the
lifetime of an object by using the `LogOnReturn` class.
* Custom class formatting: it is possible to decide how a certain object
should be formatted when sent to a `Logger` by implementing the
`writeToLog` function. For example, `llvm::Value`-derived objects are
passed through the `getName` function. If no custom formatter is
specified, the `operator<<` is employed.