diff options
| author | 2017-01-24 08:32:59 +0000 | |
|---|---|---|
| committer | 2017-01-24 08:32:59 +0000 | |
| commit | 53d771aafdbe5b919f264f53cba3788e2c4cffd2 (patch) | |
| tree | 7eca39498be0ff1e3a6daf583cd9ca5886bb2636 /gnu/llvm/docs/ProgrammersManual.rst | |
| parent | In preparation of compiling our kernels with -ffreestanding, explicitly map (diff) | |
| download | wireguard-openbsd-53d771aafdbe5b919f264f53cba3788e2c4cffd2.tar.xz wireguard-openbsd-53d771aafdbe5b919f264f53cba3788e2c4cffd2.zip | |
Import LLVM 4.0.0 rc1 including clang and lld to help the current
development effort on OpenBSD/arm64.
Diffstat (limited to 'gnu/llvm/docs/ProgrammersManual.rst')
| -rw-r--r-- | gnu/llvm/docs/ProgrammersManual.rst | 583 |
1 files changed, 525 insertions, 58 deletions
diff --git a/gnu/llvm/docs/ProgrammersManual.rst b/gnu/llvm/docs/ProgrammersManual.rst index 030637048bf..ffc022eef16 100644 --- a/gnu/llvm/docs/ProgrammersManual.rst +++ b/gnu/llvm/docs/ProgrammersManual.rst @@ -149,7 +149,7 @@ rarely have to include this file directly). .. code-block:: c++ - if (AllocationInst *AI = dyn_cast<AllocationInst>(Val)) { + if (auto *AI = dyn_cast<AllocationInst>(Val)) { // ... } @@ -263,6 +263,134 @@ almost never be stored or mentioned directly. They are intended solely for use when defining a function which should be able to efficiently accept concatenated strings. +.. _formatting_strings: + +Formatting strings (the ``formatv`` function) +--------------------------------------------- +While LLVM doesn't necessarily do a lot of string manipulation and parsing, it +does do a lot of string formatting. From diagnostic messages, to llvm tool +outputs such as ``llvm-readobj`` to printing verbose disassembly listings and +LLDB runtime logging, the need for string formatting is pervasive. + +The ``formatv`` is similar in spirit to ``printf``, but uses a different syntax +which borrows heavily from Python and C#. Unlike ``printf`` it deduces the type +to be formatted at compile time, so it does not need a format specifier such as +``%d``. This reduces the mental overhead of trying to construct portable format +strings, especially for platform-specific types like ``size_t`` or pointer types. +Unlike both ``printf`` and Python, it additionally fails to compile if LLVM does +not know how to format the type. These two properties ensure that the function +is both safer and simpler to use than traditional formatting methods such as +the ``printf`` family of functions. + +Simple formatting +^^^^^^^^^^^^^^^^^ + +A call to ``formatv`` involves a single **format string** consisting of 0 or more +**replacement sequences**, followed by a variable length list of **replacement values**. +A replacement sequence is a string of the form ``{N[[,align]:style]}``. + +``N`` refers to the 0-based index of the argument from the list of replacement +values. Note that this means it is possible to reference the same parameter +multiple times, possibly with different style and/or alignment options, in any order. + +``align`` is an optional string specifying the width of the field to format +the value into, and the alignment of the value within the field. It is specified as +an optional **alignment style** followed by a positive integral **field width**. The +alignment style can be one of the characters ``-`` (left align), ``=`` (center align), +or ``+`` (right align). The default is right aligned. + +``style`` is an optional string consisting of a type specific that controls the +formatting of the value. For example, to format a floating point value as a percentage, +you can use the style option ``P``. + +Custom formatting +^^^^^^^^^^^^^^^^^ + +There are two ways to customize the formatting behavior for a type. + +1. Provide a template specialization of ``llvm::format_provider<T>`` for your + type ``T`` with the appropriate static format method. + + .. code-block:: c++ + + namespace llvm { + template<> + struct format_provider<MyFooBar> { + static void format(const MyFooBar &V, raw_ostream &Stream, StringRef Style) { + // Do whatever is necessary to format `V` into `Stream` + } + }; + void foo() { + MyFooBar X; + std::string S = formatv("{0}", X); + } + } + + This is a useful extensibility mechanism for adding support for formatting your own + custom types with your own custom Style options. But it does not help when you want + to extend the mechanism for formatting a type that the library already knows how to + format. For that, we need something else. + +2. Provide a **format adapter** inheriting from ``llvm::FormatAdapter<T>``. + + .. code-block:: c++ + + namespace anything { + struct format_int_custom : public llvm::FormatAdapter<int> { + explicit format_int_custom(int N) : llvm::FormatAdapter<int>(N) {} + void format(llvm::raw_ostream &Stream, StringRef Style) override { + // Do whatever is necessary to format ``this->Item`` into ``Stream`` + } + }; + } + namespace llvm { + void foo() { + std::string S = formatv("{0}", anything::format_int_custom(42)); + } + } + + If the type is detected to be derived from ``FormatAdapter<T>``, ``formatv`` + will call the + ``format`` method on the argument passing in the specified style. This allows + one to provide custom formatting of any type, including one which already has + a builtin format provider. + +``formatv`` Examples +^^^^^^^^^^^^^^^^^^^^ +Below is intended to provide an incomplete set of examples demonstrating +the usage of ``formatv``. More information can be found by reading the +doxygen documentation or by looking at the unit test suite. + + +.. code-block:: c++ + + std::string S; + // Simple formatting of basic types and implicit string conversion. + S = formatv("{0} ({1:P})", 7, 0.35); // S == "7 (35.00%)" + + // Out-of-order referencing and multi-referencing + outs() << formatv("{0} {2} {1} {0}", 1, "test", 3); // prints "1 3 test 1" + + // Left, right, and center alignment + S = formatv("{0,7}", 'a'); // S == " a"; + S = formatv("{0,-7}", 'a'); // S == "a "; + S = formatv("{0,=7}", 'a'); // S == " a "; + S = formatv("{0,+7}", 'a'); // S == " a"; + + // Custom styles + S = formatv("{0:N} - {0:x} - {1:E}", 12345, 123908342); // S == "12,345 - 0x3039 - 1.24E8" + + // Adapters + S = formatv("{0}", fmt_align(42, AlignStyle::Center, 7)); // S == " 42 " + S = formatv("{0}", fmt_repeat("hi", 3)); // S == "hihihi" + S = formatv("{0}", fmt_pad("hi", 2, 6)); // S == " hi " + + // Ranges + std::vector<int> V = {8, 9, 10}; + S = formatv("{0}", make_range(V.begin(), V.end())); // S == "8, 9, 10" + S = formatv("{0:$[+]}", make_range(V.begin(), V.end())); // S == "8+9+10" + S = formatv("{0:$[ + ]@[x]}", make_range(V.begin(), V.end())); // S == "0x8 + 0x9 + 0xA" + .. _error_apis: Error handling @@ -320,7 +448,7 @@ actually a lightweight wrapper for user-defined error types, allowing arbitrary information to be attached to describe the error. This is similar to the way C++ exceptions allow throwing of user-defined types. -Success values are created by calling ``Error::success()``: +Success values are created by calling ``Error::success()``, E.g.: .. code-block:: c++ @@ -334,28 +462,32 @@ Success values are very cheap to construct and return - they have minimal impact on program performance. Failure values are constructed using ``make_error<T>``, where ``T`` is any class -that inherits from the ErrorInfo utility: +that inherits from the ErrorInfo utility, E.g.: .. code-block:: c++ - class MyError : public ErrorInfo<MyError> { + class BadFileFormat : public ErrorInfo<BadFileFormat> { public: - MyError(std::string Msg) : Msg(Msg) {} - void log(OStream &OS) const override { OS << "MyError - " << Msg; } static char ID; - private: - std::string Msg; - }; + std::string Path; - char MyError::ID = 0; // In MyError.cpp + BadFileFormat(StringRef Path) : Path(Path.str()) {} + + void log(raw_ostream &OS) const override { + OS << Path << " is malformed"; + } - Error bar() { - if (checkErrorCondition) - return make_error<MyError>("Error condition detected"); + std::error_code convertToErrorCode() const override { + return make_error_code(object_error::parse_failed); + } + }; - // No error - proceed with bar. + char FileExists::ID; // This should be declared in the C++ file. - // Return success value. + Error printFormattedFile(StringRef Path) { + if (<check for valid format>) + return make_error<InvalidObjectFile>(Path); + // print file contents. return Error::success(); } @@ -374,35 +506,58 @@ success, enabling the following idiom: For functions that can fail but need to return a value the ``Expected<T>`` utility can be used. Values of this type can be constructed with either a -``T``, or a ``Error``. Expected<T> values are also implicitly convertible to -boolean, but with the opposite convention to Error: true for success, false for -error. If success, the ``T`` value can be accessed via the dereference operator. -If failure, the ``Error`` value can be extracted using the ``takeError()`` -method. Idiomatic usage looks like: +``T``, or an ``Error``. Expected<T> values are also implicitly convertible to +boolean, but with the opposite convention to ``Error``: true for success, false +for error. If success, the ``T`` value can be accessed via the dereference +operator. If failure, the ``Error`` value can be extracted using the +``takeError()`` method. Idiomatic usage looks like: .. code-block:: c++ - Expected<float> parseAndSquareRoot(IStream &IS) { - float f; - OS >> f; - if (f < 0) - return make_error<FloatingPointError>(...); - return sqrt(f); + Expected<FormattedFile> openFormattedFile(StringRef Path) { + // If badly formatted, return an error. + if (auto Err = checkFormat(Path)) + return std::move(Err); + // Otherwise return a FormattedFile instance. + return FormattedFile(Path); } - Error foo(IStream &IS) { - if (auto SqrtOrErr = parseAndSquartRoot(IS)) { - float Sqrt = *SqrtOrErr; - // ... + Error processFormattedFile(StringRef Path) { + // Try to open a formatted file + if (auto FileOrErr = openFormattedFile(Path)) { + // On success, grab a reference to the file and continue. + auto &File = *FileOrErr; + ... } else - return SqrtOrErr.takeError(); + // On error, extract the Error value and return it. + return FileOrErr.takeError(); } -All Error instances, whether success or failure, must be either checked or -moved from (via std::move or a return) before they are destructed. Accidentally -discarding an unchecked error will cause a program abort at the point where the -unchecked value's destructor is run, making it easy to identify and fix -violations of this rule. +If an ``Expected<T>`` value is in success mode then the ``takeError()`` method +will return a success value. Using this fact, the above function can be +rewritten as: + +.. code-block:: c++ + + Error processFormattedFile(StringRef Path) { + // Try to open a formatted file + auto FileOrErr = openFormattedFile(Path); + if (auto Err = FileOrErr.takeError()) + // On error, extract the Error value and return it. + return Err; + // On success, grab a reference to the file and continue. + auto &File = *FileOrErr; + ... + } + +This second form is often more readable for functions that involve multiple +``Expected<T>`` values as it limits the indentation required. + +All ``Error`` instances, whether success or failure, must be either checked or +moved from (via ``std::move`` or a return) before they are destructed. +Accidentally discarding an unchecked error will cause a program abort at the +point where the unchecked value's destructor is run, making it easy to identify +and fix violations of this rule. Success values are considered checked once they have been tested (by invoking the boolean conversion operator): @@ -414,8 +569,8 @@ the boolean conversion operator): // Safe to continue: Err was checked. -In contrast, the following code will always cause an abort, regardless of the -return value of ``foo``: +In contrast, the following code will always cause an abort, even if ``canFail`` +returns a success value: .. code-block:: c++ @@ -428,22 +583,318 @@ been activated: .. code-block:: c++ - auto Err = canFail(...); - if (auto Err2 = - handleErrors(std::move(Err), - [](std::unique_ptr<MyError> M) { - // Try to handle 'M'. If successful, return a success value from - // the handler. - if (tryToHandle(M)) - return Error::success(); + handleErrors( + processFormattedFile(...), + [](const BadFileFormat &BFF) { + report("Unable to process " + BFF.Path + ": bad format"); + }, + [](const FileNotFound &FNF) { + report("File not found " + FNF.Path); + }); + +The ``handleErrors`` function takes an error as its first argument, followed by +a variadic list of "handlers", each of which must be a callable type (a +function, lambda, or class with a call operator) with one argument. The +``handleErrors`` function will visit each handler in the sequence and check its +argument type against the dynamic type of the error, running the first handler +that matches. This is the same decision process that is used decide which catch +clause to run for a C++ exception. + +Since the list of handlers passed to ``handleErrors`` may not cover every error +type that can occur, the ``handleErrors`` function also returns an Error value +that must be checked or propagated. If the error value that is passed to +``handleErrors`` does not match any of the handlers it will be returned from +handleErrors. Idiomatic use of ``handleErrors`` thus looks like: + +.. code-block:: c++ + + if (auto Err = + handleErrors( + processFormattedFile(...), + [](const BadFileFormat &BFF) { + report("Unable to process " + BFF.Path + ": bad format"); + }, + [](const FileNotFound &FNF) { + report("File not found " + FNF.Path); + })) + return Err; + +In cases where you truly know that the handler list is exhaustive the +``handleAllErrors`` function can be used instead. This is identical to +``handleErrors`` except that it will terminate the program if an unhandled +error is passed in, and can therefore return void. The ``handleAllErrors`` +function should generally be avoided: the introduction of a new error type +elsewhere in the program can easily turn a formerly exhaustive list of errors +into a non-exhaustive list, risking unexpected program termination. Where +possible, use handleErrors and propagate unknown errors up the stack instead. + +For tool code, where errors can be handled by printing an error message then +exiting with an error code, the :ref:`ExitOnError <err_exitonerr>` utility +may be a better choice than handleErrors, as it simplifies control flow when +calling fallible functions. + +StringError +""""""""""" + +Many kinds of errors have no recovery strategy, the only action that can be +taken is to report them to the user so that the user can attempt to fix the +environment. In this case representing the error as a string makes perfect +sense. LLVM provides the ``StringError`` class for this purpose. It takes two +arguments: A string error message, and an equivalent ``std::error_code`` for +interoperability: + +.. code-block:: c++ + + make_error<StringError>("Bad executable", + make_error_code(errc::executable_format_error")); + +If you're certain that the error you're building will never need to be converted +to a ``std::error_code`` you can use the ``inconvertibleErrorCode()`` function: + +.. code-block:: c++ + + make_error<StringError>("Bad executable", inconvertibleErrorCode()); + +This should be done only after careful consideration. If any attempt is made to +convert this error to a ``std::error_code`` it will trigger immediate program +termination. Unless you are certain that your errors will not need +interoperability you should look for an existing ``std::error_code`` that you +can convert to, and even (as painful as it is) consider introducing a new one as +a stopgap measure. + +Interoperability with std::error_code and ErrorOr +""""""""""""""""""""""""""""""""""""""""""""""""" + +Many existing LLVM APIs use ``std::error_code`` and its partner ``ErrorOr<T>`` +(which plays the same role as ``Expected<T>``, but wraps a ``std::error_code`` +rather than an ``Error``). The infectious nature of error types means that an +attempt to change one of these functions to return ``Error`` or ``Expected<T>`` +instead often results in an avalanche of changes to callers, callers of callers, +and so on. (The first such attempt, returning an ``Error`` from +MachOObjectFile's constructor, was abandoned after the diff reached 3000 lines, +impacted half a dozen libraries, and was still growing). + +To solve this problem, the ``Error``/``std::error_code`` interoperability requirement was +introduced. Two pairs of functions allow any ``Error`` value to be converted to a +``std::error_code``, any ``Expected<T>`` to be converted to an ``ErrorOr<T>``, and vice +versa: + +.. code-block:: c++ + + std::error_code errorToErrorCode(Error Err); + Error errorCodeToError(std::error_code EC); + + template <typename T> ErrorOr<T> expectedToErrorOr(Expected<T> TOrErr); + template <typename T> Expected<T> errorOrToExpected(ErrorOr<T> TOrEC); + + +Using these APIs it is easy to make surgical patches that update individual +functions from ``std::error_code`` to ``Error``, and from ``ErrorOr<T>`` to +``Expected<T>``. + +Returning Errors from error handlers +"""""""""""""""""""""""""""""""""""" + +Error recovery attempts may themselves fail. For that reason, ``handleErrors`` +actually recognises three different forms of handler signature: + +.. code-block:: c++ - // We failed to handle 'M' - return it from the handler. - // This value will be passed back from catchErrors and - // wind up in Err2, where it will be returned from this function. - return Error(std::move(M)); - }))) - return Err2; + // Error must be handled, no new errors produced: + void(UserDefinedError &E); + // Error must be handled, new errors can be produced: + Error(UserDefinedError &E); + + // Original error can be inspected, then re-wrapped and returned (or a new + // error can be produced): + Error(std::unique_ptr<UserDefinedError> E); + +Any error returned from a handler will be returned from the ``handleErrors`` +function so that it can be handled itself, or propagated up the stack. + +.. _err_exitonerr: + +Using ExitOnError to simplify tool code +""""""""""""""""""""""""""""""""""""""" + +Library code should never call ``exit`` for a recoverable error, however in tool +code (especially command line tools) this can be a reasonable approach. Calling +``exit`` upon encountering an error dramatically simplifies control flow as the +error no longer needs to be propagated up the stack. This allows code to be +written in straight-line style, as long as each fallible call is wrapped in a +check and call to exit. The ``ExitOnError`` class supports this pattern by +providing call operators that inspect ``Error`` values, stripping the error away +in the success case and logging to ``stderr`` then exiting in the failure case. + +To use this class, declare a global ``ExitOnError`` variable in your program: + +.. code-block:: c++ + + ExitOnError ExitOnErr; + +Calls to fallible functions can then be wrapped with a call to ``ExitOnErr``, +turning them into non-failing calls: + +.. code-block:: c++ + + Error mayFail(); + Expected<int> mayFail2(); + + void foo() { + ExitOnErr(mayFail()); + int X = ExitOnErr(mayFail2()); + } + +On failure, the error's log message will be written to ``stderr``, optionally +preceded by a string "banner" that can be set by calling the setBanner method. A +mapping can also be supplied from ``Error`` values to exit codes using the +``setExitCodeMapper`` method: + +.. code-block:: c++ + + int main(int argc, char *argv[]) { + ExitOnErr.setBanner(std::string(argv[0]) + " error:"); + ExitOnErr.setExitCodeMapper( + [](const Error &Err) { + if (Err.isA<BadFileFormat>()) + return 2; + return 1; + }); + +Use ``ExitOnError`` in your tool code where possible as it can greatly improve +readability. + +Fallible constructors +""""""""""""""""""""" + +Some classes require resource acquisition or other complex initialization that +can fail during construction. Unfortunately constructors can't return errors, +and having clients test objects after they're constructed to ensure that they're +valid is error prone as it's all too easy to forget the test. To work around +this, use the named constructor idiom and return an ``Expected<T>``: + +.. code-block:: c++ + + class Foo { + public: + + static Expected<Foo> Create(Resource R1, Resource R2) { + Error Err; + Foo F(R1, R2, Err); + if (Err) + return std::move(Err); + return std::move(F); + } + + private: + + Foo(Resource R1, Resource R2, Error &Err) { + ErrorAsOutParameter EAO(&Err); + if (auto Err2 = R1.acquire()) { + Err = std::move(Err2); + return; + } + Err = R2.acquire(); + } + }; + + +Here, the named constructor passes an ``Error`` by reference into the actual +constructor, which the constructor can then use to return errors. The +``ErrorAsOutParameter`` utility sets the ``Error`` value's checked flag on entry +to the constructor so that the error can be assigned to, then resets it on exit +to force the client (the named constructor) to check the error. + +By using this idiom, clients attempting to construct a Foo receive either a +well-formed Foo or an Error, never an object in an invalid state. + +Propagating and consuming errors based on types +""""""""""""""""""""""""""""""""""""""""""""""" + +In some contexts, certain types of error are known to be benign. For example, +when walking an archive, some clients may be happy to skip over badly formatted +object files rather than terminating the walk immediately. Skipping badly +formatted objects could be achieved using an elaborate handler method, but the +Error.h header provides two utilities that make this idiom much cleaner: the +type inspection method, ``isA``, and the ``consumeError`` function: + +.. code-block:: c++ + + Error walkArchive(Archive A) { + for (unsigned I = 0; I != A.numMembers(); ++I) { + auto ChildOrErr = A.getMember(I); + if (auto Err = ChildOrErr.takeError()) { + if (Err.isA<BadFileFormat>()) + consumeError(std::move(Err)) + else + return Err; + } + auto &Child = *ChildOrErr; + // Use Child + ... + } + return Error::success(); + } + +Concatenating Errors with joinErrors +"""""""""""""""""""""""""""""""""""" + +In the archive walking example above ``BadFileFormat`` errors are simply +consumed and ignored. If the client had wanted report these errors after +completing the walk over the archive they could use the ``joinErrors`` utility: + +.. code-block:: c++ + + Error walkArchive(Archive A) { + Error DeferredErrs = Error::success(); + for (unsigned I = 0; I != A.numMembers(); ++I) { + auto ChildOrErr = A.getMember(I); + if (auto Err = ChildOrErr.takeError()) + if (Err.isA<BadFileFormat>()) + DeferredErrs = joinErrors(std::move(DeferredErrs), std::move(Err)); + else + return Err; + auto &Child = *ChildOrErr; + // Use Child + ... + } + return DeferredErrs; + } + +The ``joinErrors`` routine builds a special error type called ``ErrorList``, +which holds a list of user defined errors. The ``handleErrors`` routine +recognizes this type and will attempt to handle each of the contained erorrs in +order. If all contained errors can be handled, ``handleErrors`` will return +``Error::success()``, otherwise ``handleErrors`` will concatenate the remaining +errors and return the resulting ``ErrorList``. + +Building fallible iterators and iterator ranges +""""""""""""""""""""""""""""""""""""""""""""""" + +The archive walking examples above retrieve archive members by index, however +this requires considerable boiler-plate for iteration and error checking. We can +clean this up by using ``Error`` with the "fallible iterator" pattern. The usual +C++ iterator patterns do not allow for failure on increment, but we can +incorporate support for it by having iterators hold an Error reference through +which they can report failure. In this pattern, if an increment operation fails +the failure is recorded via the Error reference and the iterator value is set to +the end of the range in order to terminate the loop. This ensures that the +dereference operation is safe anywhere that an ordinary iterator dereference +would be safe (i.e. when the iterator is not equal to end). Where this pattern +is followed (as in the ``llvm::object::Archive`` class) the result is much +cleaner iteration idiom: + +.. code-block:: c++ + + Error Err; + for (auto &Child : Ar->children(Err)) { + // Use Child - we only enter the loop when it's valid + ... + } + // Check Err after the loop to ensure it didn't break due to an error. + if (Err) + return Err; .. _function_apis: @@ -1743,6 +2194,22 @@ reverse) is O(1) worst case. Testing and setting bits within 128 bits (depends on size) of the current bit is also O(1). As a general statement, testing/setting bits in a SparseBitVector is O(distance away from last set bit). +.. _debugging: + +Debugging +========= + +A handful of `GDB pretty printers +<https://sourceware.org/gdb/onlinedocs/gdb/Pretty-Printing.html>`__ are +provided for some of the core LLVM libraries. To use them, execute the +following (or add it to your ``~/.gdbinit``):: + + source /path/to/llvm/src/utils/gdb-scripts/prettyprinters.py + +It also might be handy to enable the `print pretty +<http://ftp.gnu.org/old-gnu/Manuals/gdb/html_node/gdb_57.html>`__ option to +avoid data structures being printed as a big block of text. + .. _common: Helpful Hints for Common Operations @@ -2054,7 +2521,7 @@ iterate over all predecessors of BB: .. code-block:: c++ - #include "llvm/Support/CFG.h" + #include "llvm/IR/CFG.h" BasicBlock *BB = ...; for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) { @@ -2825,20 +3292,20 @@ Important Derived Types * ``unsigned getBitWidth() const``: Get the bit width of an integer type. ``SequentialType`` - This is subclassed by ArrayType, PointerType and VectorType. + This is subclassed by ArrayType and VectorType. * ``const Type * getElementType() const``: Returns the type of each of the elements in the sequential type. + * ``uint64_t getNumElements() const``: Returns the number of elements + in the sequential type. + ``ArrayType`` This is a subclass of SequentialType and defines the interface for array types. - * ``unsigned getNumElements() const``: Returns the number of elements - in the array. - ``PointerType`` - Subclass of SequentialType for pointer types. + Subclass of Type for pointer types. ``VectorType`` Subclass of SequentialType for vector types. A vector type is similar to an |
