[NFC] Trim trailing whitespace in *.rst
This commit is contained in:
parent
846f33572e
commit
0c660256eb
|
|
@ -3,7 +3,7 @@
|
|||
abseil-redundant-strcat-calls
|
||||
=============================
|
||||
|
||||
Suggests removal of unnecessary calls to ``absl::StrCat`` when the result is
|
||||
Suggests removal of unnecessary calls to ``absl::StrCat`` when the result is
|
||||
being passed to another call to ``absl::StrCat`` or ``absl::StrAppend``.
|
||||
|
||||
The extra calls cause unnecessary temporary strings to be constructed. Removing
|
||||
|
|
@ -21,6 +21,6 @@ Examples:
|
|||
|
||||
absl::StrAppend(&s, absl::StrCat("E", "F", "G"));
|
||||
//before
|
||||
|
||||
|
||||
absl::StrAppend(&s, "E", "F", "G");
|
||||
//after
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
abseil-str-cat-append
|
||||
=====================
|
||||
|
||||
Flags uses of ``absl::StrCat()`` to append to a ``std::string``. Suggests
|
||||
Flags uses of ``absl::StrCat()`` to append to a ``std::string``. Suggests
|
||||
``absl::StrAppend()`` should be used instead.
|
||||
|
||||
The extra calls cause unnecessary temporary strings to be constructed. Removing
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
bugprone-bad-signal-to-kill-thread
|
||||
==================================
|
||||
|
||||
Finds ``pthread_kill`` function calls when a thread is terminated by
|
||||
raising ``SIGTERM`` signal and the signal kills the entire process, not
|
||||
Finds ``pthread_kill`` function calls when a thread is terminated by
|
||||
raising ``SIGTERM`` signal and the signal kills the entire process, not
|
||||
just the individual thread. Use any signal except ``SIGTERM``.
|
||||
|
||||
.. code-block: c++
|
||||
|
|
|
|||
|
|
@ -128,5 +128,5 @@ Options
|
|||
.. option:: WantToUseSafeFunctions
|
||||
|
||||
The value `true` specifies that the target environment is considered to
|
||||
implement '_s' suffixed memory and string handler functions which are safer
|
||||
implement '_s' suffixed memory and string handler functions which are safer
|
||||
than older versions (e.g. 'memcpy_s()'). The default value is `true`.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ bugprone-reserved-identifier
|
|||
|
||||
`cert-dcl37-c` and `cert-dcl51-cpp` redirect here as an alias for this check.
|
||||
|
||||
Checks for usages of identifiers reserved for use by the implementation.
|
||||
Checks for usages of identifiers reserved for use by the implementation.
|
||||
|
||||
The C and C++ standards both reserve the following names for such use:
|
||||
|
||||
|
|
@ -13,34 +13,34 @@ The C and C++ standards both reserve the following names for such use:
|
|||
- identifiers in the global namespace that begin with an underscore.
|
||||
|
||||
The C standard additionally reserves names beginning with a double underscore,
|
||||
while the C++ standard strengthens this to reserve names with a double
|
||||
while the C++ standard strengthens this to reserve names with a double
|
||||
underscore occurring anywhere.
|
||||
|
||||
Violating the naming rules above results in undefined behavior.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
namespace NS {
|
||||
namespace NS {
|
||||
void __f(); // name is not allowed in user code
|
||||
using _Int = int; // same with this
|
||||
#define cool__macro // also this
|
||||
}
|
||||
int _g(); // disallowed in global namespace only
|
||||
|
||||
The check can also be inverted, i.e. it can be configured to flag any
|
||||
identifier that is _not_ a reserved identifier. This mode is for use by e.g.
|
||||
standard library implementors, to ensure they don't infringe on the user
|
||||
The check can also be inverted, i.e. it can be configured to flag any
|
||||
identifier that is _not_ a reserved identifier. This mode is for use by e.g.
|
||||
standard library implementors, to ensure they don't infringe on the user
|
||||
namespace.
|
||||
|
||||
This check does not (yet) check for other reserved names, e.g. macro names
|
||||
identical to language keywords, and names specifically reserved by language
|
||||
This check does not (yet) check for other reserved names, e.g. macro names
|
||||
identical to language keywords, and names specifically reserved by language
|
||||
standards, e.g. C++ 'zombie names' and C future library directions.
|
||||
|
||||
This check corresponds to CERT C Coding Standard rule `DCL37-C. Do not declare
|
||||
This check corresponds to CERT C Coding Standard rule `DCL37-C. Do not declare
|
||||
or define a reserved identifier
|
||||
<https://wiki.sei.cmu.edu/confluence/display/c/DCL37-C.+Do+not+declare+or+define+a+reserved+identifier>`_
|
||||
as well as its C++ counterpart, `DCL51-CPP. Do not declare or define a reserved
|
||||
identifier
|
||||
identifier
|
||||
<https://wiki.sei.cmu.edu/confluence/display/cplusplus/DCL51-CPP.+Do+not+declare+or+define+a+reserved+identifier>`_.
|
||||
|
||||
Options
|
||||
|
|
@ -48,10 +48,10 @@ Options
|
|||
|
||||
.. option:: Invert
|
||||
|
||||
If `true`, inverts the check, i.e. flags names that are not reserved.
|
||||
If `true`, inverts the check, i.e. flags names that are not reserved.
|
||||
Default is `false`.
|
||||
|
||||
.. option:: AllowedIdentifiers
|
||||
|
||||
Semicolon-separated list of names that the check ignores. Default is an
|
||||
Semicolon-separated list of names that the check ignores. Default is an
|
||||
empty list.
|
||||
|
|
|
|||
|
|
@ -32,6 +32,5 @@ and has an alias name ``cert-sig30-c``.
|
|||
assumable that the reason is that the list was not updated for C11.
|
||||
The checker includes ``quick_exit`` in the set of safe functions.
|
||||
Functions registered as exit handlers are not checked.
|
||||
|
||||
Default is ``POSIX``.
|
||||
|
||||
Default is ``POSIX``.
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
bugprone-spuriously-wake-up-functions
|
||||
=====================================
|
||||
|
||||
Finds ``cnd_wait``, ``cnd_timedwait``, ``wait``, ``wait_for``, or
|
||||
Finds ``cnd_wait``, ``cnd_timedwait``, ``wait``, ``wait_for``, or
|
||||
``wait_until`` function calls when the function is not invoked from a loop
|
||||
that checks whether a condition predicate holds or the function has a
|
||||
that checks whether a condition predicate holds or the function has a
|
||||
condition parameter.
|
||||
|
||||
.. code-block: c++
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ bugprone-suspicious-enum-usage
|
|||
|
||||
The checker detects various cases when an enum is probably misused (as a bitmask
|
||||
).
|
||||
|
||||
|
||||
1. When "ADD" or "bitwise OR" is used between two enum which come from different
|
||||
types and these types value ranges are not disjoint.
|
||||
|
||||
The following cases will be investigated only using :option:`StrictMode`. We
|
||||
The following cases will be investigated only using :option:`StrictMode`. We
|
||||
regard the enum as a (suspicious)
|
||||
bitmask if the three conditions below are true at the same time:
|
||||
|
||||
|
|
@ -36,13 +36,13 @@ Examples:
|
|||
enum { A, B, C };
|
||||
enum { D, E, F = 5 };
|
||||
enum { G = 10, H = 11, I = 12 };
|
||||
|
||||
|
||||
unsigned flag;
|
||||
flag =
|
||||
A |
|
||||
H; // OK, disjoint value intervals in the enum types ->probably good use.
|
||||
flag = B | F; // Warning, have common values so they are probably misused.
|
||||
|
||||
|
||||
// Case 2:
|
||||
enum Bitmask {
|
||||
A = 0,
|
||||
|
|
@ -53,7 +53,7 @@ Examples:
|
|||
F = 16,
|
||||
G = 31 // OK, real bitmask.
|
||||
};
|
||||
|
||||
|
||||
enum Almostbitmask {
|
||||
AA = 0,
|
||||
BB = 1,
|
||||
|
|
@ -63,7 +63,7 @@ Examples:
|
|||
FF = 16,
|
||||
GG // Problem, forgot to initialize.
|
||||
};
|
||||
|
||||
|
||||
unsigned flag = 0;
|
||||
flag |= E; // OK.
|
||||
flag |=
|
||||
|
|
|
|||
|
|
@ -16,14 +16,14 @@ properly compare the value representations.
|
|||
Objects with the same value may not have the same object representation.
|
||||
This may be caused by padding or floating-point types.
|
||||
|
||||
See also:
|
||||
See also:
|
||||
`EXP42-C. Do not compare padding data
|
||||
<https://wiki.sei.cmu.edu/confluence/display/c/EXP42-C.+Do+not+compare+padding+data>`_
|
||||
and
|
||||
`FLP37-C. Do not use object representations to compare floating-point values
|
||||
<https://wiki.sei.cmu.edu/confluence/display/c/FLP37-C.+Do+not+use+object+representations+to+compare+floating-point+values>`_
|
||||
|
||||
This check is also related to and partially overlaps the CERT C++ Coding Standard rules
|
||||
This check is also related to and partially overlaps the CERT C++ Coding Standard rules
|
||||
`OOP57-CPP. Prefer special member functions and overloaded operators to C Standard Library functions
|
||||
<https://wiki.sei.cmu.edu/confluence/display/cplusplus/OOP57-CPP.+Prefer+special+member+functions+and+overloaded+operators+to+C+Standard+Library+functions>`_
|
||||
and
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@ cert-dcl37-c
|
|||
============
|
||||
|
||||
The cert-dcl37-c check is an alias, please see
|
||||
`bugprone-reserved-identifier <bugprone-reserved-identifier.html>`_ for more
|
||||
`bugprone-reserved-identifier <bugprone-reserved-identifier.html>`_ for more
|
||||
information.
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@ cert-dcl51-cpp
|
|||
==============
|
||||
|
||||
The cert-dcl51-cpp check is an alias, please see
|
||||
`bugprone-reserved-identifier <bugprone-reserved-identifier.html>`_ for more
|
||||
`bugprone-reserved-identifier <bugprone-reserved-identifier.html>`_ for more
|
||||
information.
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ Examples:
|
|||
std::mt19937 engine2(1); // Diagnose
|
||||
engine1.seed(); // Diagnose
|
||||
engine2.seed(1); // Diagnose
|
||||
|
||||
|
||||
std::time_t t;
|
||||
engine1.seed(std::time(&t)); // Diagnose, system time might be controlled by user
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,6 @@ Options
|
|||
`std::memcmp`, `memcmp`, `std::strcmp`, `strcmp`, `strncmp`.
|
||||
|
||||
This check corresponds to the CERT C++ Coding Standard rule
|
||||
`OOP57-CPP. Prefer special member functions and overloaded operators to C
|
||||
`OOP57-CPP. Prefer special member functions and overloaded operators to C
|
||||
Standard Library functions
|
||||
<https://wiki.sei.cmu.edu/confluence/display/cplusplus/OOP57-CPP.+Prefer+special+member+functions+and+overloaded+operators+to+C+Standard+Library+functions>`_.
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ cppcoreguidelines-avoid-goto
|
|||
The usage of ``goto`` for control flow is error prone and should be replaced
|
||||
with looping constructs. Only forward jumps in nested loops are accepted.
|
||||
|
||||
This check implements `ES.76 <https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es76-avoid-goto>`_
|
||||
from the CppCoreGuidelines and
|
||||
This check implements `ES.76 <https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es76-avoid-goto>`_
|
||||
from the CppCoreGuidelines and
|
||||
`6.3.1 from High Integrity C++ <http://www.codingstandard.com/rule/6-3-1-ensure-that-the-labels-for-a-jump-statement-or-a-switch-condition-appear-later-in-the-same-or-an-enclosing-block/>`_.
|
||||
|
||||
For more information on why to avoid programming
|
||||
For more information on why to avoid programming
|
||||
with ``goto`` you can read the famous paper `A Case against the GO TO Statement. <https://www.cs.utexas.edu/users/EWD/ewd02xx/EWD215.PDF>`_.
|
||||
|
||||
The check diagnoses ``goto`` for backward jumps in every language mode. These
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ cppcoreguidelines-macro-usage
|
|||
Finds macro usage that is considered problematic because better language
|
||||
constructs exist for the task.
|
||||
|
||||
The relevant sections in the C++ Core Guidelines are
|
||||
The relevant sections in the C++ Core Guidelines are
|
||||
`Enum.1 <https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#enum1-prefer-enumerations-over-macros>`_,
|
||||
`ES.30 <https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es30-dont-use-macros-for-program-text-manipulation>`_,
|
||||
`ES.31 <https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es31-dont-use-macros-for-constants-or-functions>`_ and
|
||||
|
|
@ -17,7 +17,7 @@ Options
|
|||
|
||||
.. option:: AllowedRegexp
|
||||
|
||||
A regular expression to filter allowed macros. For example
|
||||
A regular expression to filter allowed macros. For example
|
||||
`DEBUG*|LIBTORRENT*|TORRENT*|UNI*` could be applied to filter `libtorrent`.
|
||||
Default value is `^DEBUG_*`.
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ cppcoreguidelines-no-malloc
|
|||
This check handles C-Style memory management using ``malloc()``, ``realloc()``,
|
||||
``calloc()`` and ``free()``. It warns about its use and tries to suggest the use
|
||||
of an appropriate RAII object.
|
||||
Furthermore, it can be configured to check against a user-specified list of functions
|
||||
Furthermore, it can be configured to check against a user-specified list of functions
|
||||
that are used for memory management (e.g. ``posix_memalign()``).
|
||||
See `C++ Core Guidelines <https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rr-mallocfree>`_.
|
||||
|
||||
|
|
@ -31,16 +31,15 @@ Options
|
|||
|
||||
.. option:: Allocations
|
||||
|
||||
Semicolon-separated list of fully qualified names of memory allocation functions.
|
||||
Semicolon-separated list of fully qualified names of memory allocation functions.
|
||||
Defaults to ``::malloc;::calloc``.
|
||||
|
||||
.. option:: Deallocations
|
||||
|
||||
Semicolon-separated list of fully qualified names of memory allocation functions.
|
||||
Semicolon-separated list of fully qualified names of memory allocation functions.
|
||||
Defaults to ``::free``.
|
||||
|
||||
.. option:: Reallocations
|
||||
|
||||
Semicolon-separated list of fully qualified names of memory allocation functions.
|
||||
Semicolon-separated list of fully qualified names of memory allocation functions.
|
||||
Defaults to ``::realloc``.
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
cppcoreguidelines-owning-memory
|
||||
===============================
|
||||
|
||||
This check implements the type-based semantics of ``gsl::owner<T*>``, which allows
|
||||
static analysis on code, that uses raw pointers to handle resources like
|
||||
This check implements the type-based semantics of ``gsl::owner<T*>``, which allows
|
||||
static analysis on code, that uses raw pointers to handle resources like
|
||||
dynamic memory, but won't introduce RAII concepts.
|
||||
|
||||
The relevant sections in the `C++ Core Guidelines <https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md>`_ are I.11, C.33, R.3 and GSL.Views
|
||||
|
|
@ -20,7 +20,7 @@ the `Guideline Support Library <https://github.com/isocpp/CppCoreGuidelines/blob
|
|||
All checks are purely type based and not (yet) flow sensitive.
|
||||
|
||||
The following examples will demonstrate the correct and incorrect initializations
|
||||
of owners, assignment is handled the same way. Note that both ``new`` and
|
||||
of owners, assignment is handled the same way. Note that both ``new`` and
|
||||
``malloc()``-like resource functions are considered to produce resources.
|
||||
|
||||
.. code-block:: c++
|
||||
|
|
@ -53,7 +53,7 @@ to be deleted.
|
|||
// Example Good, Ownership correctly stated
|
||||
gsl::owner<int*> Owner = new int(42); // Good
|
||||
delete Owner; // Good as well, statically enforced, that only owners get deleted
|
||||
|
||||
|
||||
The check will furthermore ensure, that functions, that expect a ``gsl::owner<T*>`` as
|
||||
argument get called with either a ``gsl::owner<T*>`` or a newly created resource.
|
||||
|
||||
|
|
@ -100,7 +100,7 @@ Options
|
|||
Limitations
|
||||
-----------
|
||||
|
||||
Using ``gsl::owner<T*>`` in a typedef or alias is not handled correctly.
|
||||
Using ``gsl::owner<T*>`` in a typedef or alias is not handled correctly.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
|
|
@ -110,7 +110,7 @@ Using ``gsl::owner<T*>`` in a typedef or alias is not handled correctly.
|
|||
The ``gsl::owner<T*>`` is declared as a templated type alias.
|
||||
In template functions and classes, like in the example below, the information
|
||||
of the type aliases gets lost. Therefore using ``gsl::owner<T*>`` in a heavy templated
|
||||
code base might lead to false positives.
|
||||
code base might lead to false positives.
|
||||
|
||||
Known code constructs that do not get diagnosed correctly are:
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ Known code constructs that do not get diagnosed correctly are:
|
|||
|
||||
gsl::owner<int*> function_that_returns_owner() { return gsl::owner<int*>(new int(42)); }
|
||||
|
||||
// Type deduction does not work for auto variables.
|
||||
// Type deduction does not work for auto variables.
|
||||
// This is caught by the check and will be noted accordingly.
|
||||
auto OwnedObject = function_that_returns_owner(); // Type of OwnedObject will be int*
|
||||
|
||||
|
|
@ -152,9 +152,9 @@ Known code constructs that do not get diagnosed correctly are:
|
|||
};
|
||||
|
||||
// Code, that yields a false positive.
|
||||
OwnedValue<gsl::owner<int*>> Owner(new int(42)); // Type deduction yield T -> int *
|
||||
OwnedValue<gsl::owner<int*>> Owner(new int(42)); // Type deduction yield T -> int *
|
||||
// False positive, getValue returns int* and not gsl::owner<int*>
|
||||
gsl::owner<int*> OwnedInt = Owner.getValue();
|
||||
gsl::owner<int*> OwnedInt = Owner.getValue();
|
||||
|
||||
Another limitation of the current implementation is only the type based checking.
|
||||
Suppose you have code like the following:
|
||||
|
|
@ -162,15 +162,15 @@ Suppose you have code like the following:
|
|||
.. code-block:: c++
|
||||
|
||||
// Two owners with assigned resources
|
||||
gsl::owner<int*> Owner1 = new int(42);
|
||||
gsl::owner<int*> Owner1 = new int(42);
|
||||
gsl::owner<int*> Owner2 = new int(42);
|
||||
|
||||
Owner2 = Owner1; // Conceptual Leak of initial resource of Owner2!
|
||||
Owner1 = nullptr;
|
||||
|
||||
The semantic of a ``gsl::owner<T*>`` is mostly like a ``std::unique_ptr<T>``, therefore
|
||||
assignment of two ``gsl::owner<T*>`` is considered a move, which requires that the
|
||||
assignment of two ``gsl::owner<T*>`` is considered a move, which requires that the
|
||||
resource ``Owner2`` must have been released before the assignment.
|
||||
This kind of condition could be caught in later improvements of this check with
|
||||
This kind of condition could be caught in later improvements of this check with
|
||||
flowsensitive analysis. Currently, the `Clang Static Analyzer` catches this bug
|
||||
for dynamic memory, but not for general types of resources.
|
||||
|
|
|
|||
|
|
@ -27,21 +27,21 @@ Options
|
|||
|
||||
When set to `true` (default is `false`), this check doesn't flag classes with a sole, explicitly
|
||||
defaulted destructor. An example for such a class is:
|
||||
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
|
||||
struct A {
|
||||
virtual ~A() = default;
|
||||
};
|
||||
|
||||
|
||||
.. option:: AllowMissingMoveFunctions
|
||||
|
||||
When set to `true` (default is `false`), this check doesn't flag classes which define no move
|
||||
operations at all. It still flags classes which define only one of either
|
||||
move constructor or move assignment operator. With this option enabled, the following class won't be flagged:
|
||||
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
|
||||
struct A {
|
||||
A(const A&);
|
||||
A& operator=(const A&);
|
||||
|
|
@ -52,11 +52,11 @@ Options
|
|||
|
||||
When set to `true` (default is `false`), this check doesn't flag classes which define deleted copy
|
||||
operations but don't define move operations. This flag is related to Google C++ Style Guide
|
||||
https://google.github.io/styleguide/cppguide.html#Copyable_Movable_Types. With this option enabled, the
|
||||
https://google.github.io/styleguide/cppguide.html#Copyable_Movable_Types. With this option enabled, the
|
||||
following class won't be flagged:
|
||||
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
|
||||
struct A {
|
||||
A(const A&) = delete;
|
||||
A& operator=(const A&) = delete;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ darwin-avoid-spinlock
|
|||
=====================
|
||||
|
||||
Finds usages of ``OSSpinlock``, which is deprecated due to potential livelock
|
||||
problems.
|
||||
problems.
|
||||
|
||||
This check will detect following function invocations:
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
fuchsia-overloaded-operator
|
||||
===========================
|
||||
|
||||
Warns if an operator is overloaded, except for the assignment (copy and move)
|
||||
Warns if an operator is overloaded, except for the assignment (copy and move)
|
||||
operators.
|
||||
|
||||
For example:
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
fuchsia-statically-constructed-objects
|
||||
======================================
|
||||
|
||||
Warns if global, non-trivial objects with static storage are constructed, unless
|
||||
the object is statically initialized with a ``constexpr`` constructor or has no
|
||||
Warns if global, non-trivial objects with static storage are constructed, unless
|
||||
the object is statically initialized with a ``constexpr`` constructor or has no
|
||||
explicit constructor.
|
||||
|
||||
For example:
|
||||
|
|
@ -34,9 +34,9 @@ For example:
|
|||
|
||||
static B b(0); // Warning, as constructor is not constexpr
|
||||
static C c2(0, 1); // Warning, as constructor is not constexpr
|
||||
|
||||
|
||||
static int i; // No warning, as it is trivial
|
||||
|
||||
|
||||
extern int get_i();
|
||||
static C(get_i()) // Warning, as the constructor is dynamically initialized
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
fuchsia-trailing-return
|
||||
=======================
|
||||
|
||||
Functions that have trailing returns are disallowed, except for those using
|
||||
Functions that have trailing returns are disallowed, except for those using
|
||||
``decltype`` specifiers and lambda with otherwise unutterable return types.
|
||||
|
||||
For example:
|
||||
|
|
@ -21,10 +21,10 @@ For example:
|
|||
Exceptions are made for lambdas and ``decltype`` specifiers:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
|
||||
// No warning
|
||||
auto lambda = [](double x, double y) -> double {return x + y;};
|
||||
|
||||
|
||||
// No warning
|
||||
template <typename T1, typename T2>
|
||||
auto fn(const T1 &lhs, const T2 &rhs) -> decltype(lhs + rhs) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ google-objc-avoid-throwing-exception
|
|||
|
||||
Finds uses of throwing exceptions usages in Objective-C files.
|
||||
|
||||
For the same reason as the Google C++ style guide, we prefer not throwing
|
||||
For the same reason as the Google C++ style guide, we prefer not throwing
|
||||
exceptions from Objective-C code.
|
||||
|
||||
The corresponding C++ style guide rule:
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
hicpp-avoid-goto
|
||||
================
|
||||
|
||||
The `hicpp-avoid-goto` check is an alias to
|
||||
The `hicpp-avoid-goto` check is an alias to
|
||||
`cppcoreguidelines-avoid-goto <cppcoreguidelines-avoid-goto.html>`_.
|
||||
Rule `6.3.1 High Integrity C++ <http://www.codingstandard.com/rule/6-3-1-ensure-that-the-labels-for-a-jump-statement-or-a-switch-condition-appear-later-in-the-same-or-an-enclosing-block/>`_
|
||||
requires that ``goto`` only skips parts of a block and is not used for other
|
||||
requires that ``goto`` only skips parts of a block and is not used for other
|
||||
reasons.
|
||||
|
||||
Both coding guidelines implement the same exception to the usage of ``goto``.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
hicpp-exception-baseclass
|
||||
=========================
|
||||
|
||||
Ensure that every value that in a ``throw`` expression is an instance of
|
||||
Ensure that every value that in a ``throw`` expression is an instance of
|
||||
``std::exception``.
|
||||
|
||||
This enforces `rule 15.1 <http://www.codingstandard.com/section/15-1-throwing-an-exception/>`_
|
||||
|
|
@ -27,4 +27,3 @@ of the High Integrity C++ Coding Standard.
|
|||
throw std::runtime_error();
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@ The following checks can be used to check for more forms of casting:
|
|||
|
||||
- `cppcoreguidelines-pro-type-static-cast-downcast <cppcoreguidelines-pro-type-static-cast-downcast.html>`_
|
||||
- `cppcoreguidelines-pro-type-reinterpret-cast <cppcoreguidelines-pro-type-reinterpret-cast.html>`_
|
||||
- `cppcoreguidelines-pro-type-const-cast <cppcoreguidelines-pro-type-const-cast.html>`_
|
||||
- `cppcoreguidelines-pro-type-const-cast <cppcoreguidelines-pro-type-const-cast.html>`_
|
||||
- `cppcoreguidelines-pro-type-cstyle-cast <cppcoreguidelines-pro-type-cstyle-cast.html>`_
|
||||
|
|
|
|||
|
|
@ -6,6 +6,6 @@ hicpp-member-init
|
|||
=================
|
||||
|
||||
This check is an alias for `cppcoreguidelines-pro-type-member-init <cppcoreguidelines-pro-type-member-init.html>`_.
|
||||
Implements the check for
|
||||
`rule 12.4.2 <http://www.codingstandard.com/rule/12-4-2-ensure-that-a-constructor-initializes-explicitly-all-base-classes-and-non-static-data-members/>`_
|
||||
Implements the check for
|
||||
`rule 12.4.2 <http://www.codingstandard.com/rule/12-4-2-ensure-that-a-constructor-initializes-explicitly-all-base-classes-and-non-static-data-members/>`_
|
||||
to initialize class members in the right order.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ The `rule 6.1.2 <http://www.codingstandard.com/rule/6-1-2-explicitly-cover-all-p
|
|||
and `rule 6.1.4 <http://www.codingstandard.com/rule/6-1-4-ensure-that-a-switch-statement-has-at-least-two-case-labels-distinct-from-the-default-label/>`_
|
||||
of the High Integrity C++ Coding Standard are enforced.
|
||||
|
||||
``if-else if`` chains that miss a final ``else`` branch might lead to unexpected
|
||||
``if-else if`` chains that miss a final ``else`` branch might lead to unexpected
|
||||
program execution and be the result of a logical error.
|
||||
If the missing ``else`` branch is intended you can leave it empty with a clarifying
|
||||
comment.
|
||||
|
|
@ -20,10 +20,10 @@ This warning can be noisy on some code bases, so it is disabled by default.
|
|||
void f1() {
|
||||
int i = determineTheNumber();
|
||||
|
||||
if(i > 0) {
|
||||
// Some Calculation
|
||||
} else if (i < 0) {
|
||||
// Precondition violated or something else.
|
||||
if(i > 0) {
|
||||
// Some Calculation
|
||||
} else if (i < 0) {
|
||||
// Precondition violated or something else.
|
||||
}
|
||||
// ...
|
||||
}
|
||||
|
|
@ -72,16 +72,16 @@ Degenerated ``switch`` statements without any labels are caught as well.
|
|||
}
|
||||
|
||||
// Should rather be the following:
|
||||
if (i == 1) {
|
||||
// do something here
|
||||
if (i == 1) {
|
||||
// do something here
|
||||
}
|
||||
else {
|
||||
// do something here
|
||||
else {
|
||||
// do something here
|
||||
}
|
||||
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
|
||||
// A completely degenerated switch will be diagnosed.
|
||||
int i = 42;
|
||||
switch(i) {}
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@ hicpp-no-assembler
|
|||
Check for assembler statements. No fix is offered.
|
||||
|
||||
Inline assembler is forbidden by the `High Integrity C++ Coding Standard
|
||||
<http://www.codingstandard.com/section/7-5-the-asm-declaration/>`_
|
||||
<http://www.codingstandard.com/section/7-5-the-asm-declaration/>`_
|
||||
as it restricts the portability of code.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
hicpp-signed-bitwise
|
||||
====================
|
||||
|
||||
Finds uses of bitwise operations on signed integer types, which may lead to
|
||||
Finds uses of bitwise operations on signed integer types, which may lead to
|
||||
undefined or implementation defined behavior.
|
||||
|
||||
The according rule is defined in the `High Integrity C++ Standard, Section 5.6.1 <http://www.codingstandard.com/section/5-6-shift-operators/>`_.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ hicpp-undelegated-constructor
|
|||
=============================
|
||||
|
||||
This check is an alias for `bugprone-undelegated-constructor <bugprone-undelegated-constructor.html>`_.
|
||||
Partially implements `rule 12.4.5 <http://www.codingstandard.com/rule/12-4-5-use-delegating-constructors-to-reduce-code-duplication/>`_
|
||||
Partially implements `rule 12.4.5 <http://www.codingstandard.com/rule/12-4-5-use-delegating-constructors-to-reduce-code-duplication/>`_
|
||||
to find misplaced constructor calls inside a constructor.
|
||||
|
||||
.. code-block:: c++
|
||||
|
|
@ -17,7 +17,7 @@ to find misplaced constructor calls inside a constructor.
|
|||
Ctor(int, int);
|
||||
Ctor(Ctor *i) {
|
||||
// All Ctor() calls result in a temporary object
|
||||
Ctor(); // did you intend to call a delegated constructor?
|
||||
Ctor(); // did you intend to call a delegated constructor?
|
||||
Ctor(0); // did you intend to call a delegated constructor?
|
||||
Ctor(1, 2); // did you intend to call a delegated constructor?
|
||||
foo();
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@ hicpp-use-equals-delete
|
|||
=======================
|
||||
|
||||
This check is an alias for `modernize-use-equals-delete <modernize-use-equals-delete.html>`_.
|
||||
Implements `rule 12.5.1 <http://www.codingstandard.com/rule/12-5-1-define-explicitly-default-or-delete-implicit-special-member-functions-of-concrete-classes/>`_
|
||||
Implements `rule 12.5.1 <http://www.codingstandard.com/rule/12-5-1-define-explicitly-default-or-delete-implicit-special-member-functions-of-concrete-classes/>`_
|
||||
to explicitly default or delete special member functions.
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@ hicpp-use-override
|
|||
==================
|
||||
|
||||
This check is an alias for `modernize-use-override <modernize-use-override.html>`_.
|
||||
Implements `rule 10.2.1 <http://www.codingstandard.com/section/10-2-virtual-functions/>`_ to
|
||||
Implements `rule 10.2.1 <http://www.codingstandard.com/section/10-2-virtual-functions/>`_ to
|
||||
declare a virtual function `override` when overriding.
|
||||
|
|
|
|||
|
|
@ -451,4 +451,3 @@ Clang-Tidy Checks
|
|||
`hicpp-vararg <hicpp-vararg.html>`_, `cppcoreguidelines-pro-type-vararg <cppcoreguidelines-pro-type-vararg.html>`_,
|
||||
`llvm-else-after-return <llvm-else-after-return.html>`_, `readability-else-after-return <readability-else-after-return.html>`_, "Yes"
|
||||
`llvm-qualified-auto <llvm-qualified-auto.html>`_, `readability-qualified-auto <readability-qualified-auto.html>`_, "Yes"
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ llvmlibc-callee-namespace
|
|||
Checks all calls resolve to functions within ``__llvm_libc`` namespace.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
// Allow calls with the fully qualified name.
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ Options
|
|||
.. option:: MaxSize
|
||||
|
||||
Determines the maximum size of an object allowed to be caught without
|
||||
warning. Only applicable if :option:`WarnOnLargeObject` is set to `true`. If
|
||||
warning. Only applicable if :option:`WarnOnLargeObject` is set to `true`. If
|
||||
the option is set by the user to `std::numeric_limits<uint64_t>::max()` then
|
||||
it reverts to the default value.
|
||||
Default is the size of `size_t`.
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ Options
|
|||
to perform an incorrect transformation in the case where the result of the ``bind``
|
||||
is used in the context of a type erased functor such as ``std::function`` which
|
||||
allows mismatched arguments. For example:
|
||||
|
||||
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
|
|
@ -84,5 +84,5 @@ that accepts 2 arguments. With permissive parameter list, it instead generates
|
|||
}
|
||||
|
||||
which is correct.
|
||||
|
||||
|
||||
This check requires using C++14 or higher to run.
|
||||
|
|
|
|||
|
|
@ -12,6 +12,6 @@ Deprecated member type Replacement
|
|||
``std::ios_base::io_state`` ``std::ios_base::iostate``
|
||||
``std::ios_base::open_mode`` ``std::ios_base::openmode``
|
||||
``std::ios_base::seek_dir`` ``std::ios_base::seekdir``
|
||||
``std::ios_base::streamoff``
|
||||
``std::ios_base::streampos``
|
||||
``std::ios_base::streamoff``
|
||||
``std::ios_base::streampos``
|
||||
=================================== ===========================
|
||||
|
|
|
|||
|
|
@ -121,23 +121,23 @@ After applying the check with minimum confidence level set to `reasonable` (defa
|
|||
Reverse Iterator Support
|
||||
------------------------
|
||||
|
||||
The converter is also capable of transforming iterator loops which use
|
||||
``rbegin`` and ``rend`` for looping backwards over a container. Out of the box
|
||||
this will automatically happen in C++20 mode using the ``ranges`` library,
|
||||
however the check can be configured to work without C++20 by specifying a
|
||||
The converter is also capable of transforming iterator loops which use
|
||||
``rbegin`` and ``rend`` for looping backwards over a container. Out of the box
|
||||
this will automatically happen in C++20 mode using the ``ranges`` library,
|
||||
however the check can be configured to work without C++20 by specifying a
|
||||
function to reverse a range and optionally the header file where that function
|
||||
lives.
|
||||
|
||||
.. option:: UseCxx20ReverseRanges
|
||||
|
||||
When set to true convert loops when in C++20 or later mode using
|
||||
|
||||
When set to true convert loops when in C++20 or later mode using
|
||||
``std::ranges::reverse_view``.
|
||||
Default value is ``true``.
|
||||
|
||||
.. option:: MakeReverseRangeFunction
|
||||
|
||||
Specify the function used to reverse an iterator pair, the function should
|
||||
accept a class with ``rbegin`` and ``rend`` methods and return a
|
||||
Specify the function used to reverse an iterator pair, the function should
|
||||
accept a class with ``rbegin`` and ``rend`` methods and return a
|
||||
class with ``begin`` and ``end`` methods that call the ``rbegin`` and
|
||||
``rend`` methods respectively. Common examples are ``ranges::reverse_view``
|
||||
and ``llvm::reverse``.
|
||||
|
|
@ -146,10 +146,10 @@ lives.
|
|||
.. option:: MakeReverseRangeHeader
|
||||
|
||||
Specifies the header file where :option:`MakeReverseRangeFunction` is
|
||||
declared. For the previous examples this option would be set to
|
||||
declared. For the previous examples this option would be set to
|
||||
``range/v3/view/reverse.hpp`` and ``llvm/ADT/STLExtras.h`` respectively.
|
||||
If this is an empty string and :option:`MakeReverseRangeFunction` is set,
|
||||
the check will proceed on the assumption that the function is already
|
||||
If this is an empty string and :option:`MakeReverseRangeFunction` is set,
|
||||
the check will proceed on the assumption that the function is already
|
||||
available in the translation unit.
|
||||
This can be wrapped in angle brackets to signify to add the include as a
|
||||
system include.
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ Both of these examples will be replaced with:
|
|||
|
||||
The second example will also receive a warning that ``randomFunc`` is no longer supported in the same way as before so if the user wants the same functionality, the user will need to change the implementation of the ``randomFunc``.
|
||||
|
||||
One thing to be aware of here is that ``std::random_device`` is quite expensive to initialize. So if you are using the code in a performance critical place, you probably want to initialize it elsewhere.
|
||||
One thing to be aware of here is that ``std::random_device`` is quite expensive to initialize. So if you are using the code in a performance critical place, you probably want to initialize it elsewhere.
|
||||
Another thing is that the seeding quality of the suggested fix is quite poor: ``std::mt19937`` has an internal state of 624 32-bit integers, but is only seeded with a single integer. So if you require
|
||||
higher quality randomness, you should consider seeding better, for example:
|
||||
|
||||
|
|
|
|||
|
|
@ -71,8 +71,8 @@ if the :option:`ReplacementString` option is set to `NO_DISCARD`.
|
|||
|
||||
.. note::
|
||||
|
||||
If the :option:`ReplacementString` is not a C++ attribute, but instead a
|
||||
macro, then that macro must be defined in scope or the fix-it will not be
|
||||
If the :option:`ReplacementString` is not a C++ attribute, but instead a
|
||||
macro, then that macro must be defined in scope or the fix-it will not be
|
||||
applied.
|
||||
|
||||
.. note::
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ objc-avoid-nserror-init
|
|||
|
||||
Finds improper initialization of ``NSError`` objects.
|
||||
|
||||
According to Apple developer document, we should always use factory method
|
||||
According to Apple developer document, we should always use factory method
|
||||
``errorWithDomain:code:userInfo:`` to create new NSError objects instead
|
||||
of ``[NSError alloc] init]``. Otherwise it will lead to a warning message
|
||||
during runtime.
|
||||
|
|
|
|||
|
|
@ -23,8 +23,7 @@ Options
|
|||
.. option:: StringLikeClasses
|
||||
|
||||
Semicolon-separated list of names of string-like classes. By default only
|
||||
``::std::basic_string`` and ``::std::basic_string_view`` are considered.
|
||||
The check will only consider member functions named ``find``, ``rfind``,
|
||||
``find_first_of``, ``find_first_not_of``, ``find_last_of``, or
|
||||
``::std::basic_string`` and ``::std::basic_string_view`` are considered.
|
||||
The check will only consider member functions named ``find``, ``rfind``,
|
||||
``find_first_of``, ``find_first_not_of``, ``find_last_of``, or
|
||||
``find_last_not_of`` within these classes.
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ Example `[1] <https://godbolt.org/z/x7SYYA>`_:
|
|||
std::vector<int> obj = ...;
|
||||
return obj; // calls StatusOr::StatusOr(std::vector<int>&&)
|
||||
}
|
||||
|
||||
|
||||
StatusOr<std::vector<int>> NotCool() {
|
||||
const std::vector<int> obj = ...;
|
||||
return obj; // calls `StatusOr::StatusOr(const std::vector<int>&)`
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ Options
|
|||
|
||||
.. option:: WarnOnUnfixable
|
||||
|
||||
When `true`, emit a warning for cases where the check can't output a
|
||||
When `true`, emit a warning for cases where the check can't output a
|
||||
Fix-It. These can occur with declarations inside the ``else`` branch that
|
||||
would have an extended lifetime if the ``else`` branch was removed.
|
||||
Default value is `true`.
|
||||
|
|
@ -73,7 +73,7 @@ Options
|
|||
|
||||
When `true`, the check will attempt to refactor a variable defined inside
|
||||
the condition of the ``if`` statement that is used in the ``else`` branch
|
||||
defining them just before the ``if`` statement. This can only be done if
|
||||
defining them just before the ``if`` statement. This can only be done if
|
||||
the ``if`` statement is the last statement in its parent's scope.
|
||||
Default value is `true`.
|
||||
|
||||
|
|
@ -82,7 +82,7 @@ LLVM alias
|
|||
----------
|
||||
|
||||
There is an alias of this check called llvm-else-after-return.
|
||||
In that version the options :option:`WarnOnUnfixable` and
|
||||
In that version the options :option:`WarnOnUnfixable` and
|
||||
:option:`WarnOnConditionVariables` are both set to `false` by default.
|
||||
|
||||
This check helps to enforce this `LLVM Coding Standards recommendation
|
||||
|
|
|
|||
|
|
@ -854,8 +854,8 @@ After:
|
|||
.. option:: GetConfigPerFile
|
||||
|
||||
When `true` the check will look for the configuration for where an
|
||||
identifier is declared. Useful for when included header files use a
|
||||
different style.
|
||||
identifier is declared. Useful for when included header files use a
|
||||
different style.
|
||||
Default value is `true`.
|
||||
|
||||
.. option:: GlobalConstantCase
|
||||
|
|
@ -1084,7 +1084,7 @@ After:
|
|||
|
||||
.. option:: IgnoreMainLikeFunctions
|
||||
|
||||
When set to `true` functions that have a similar signature to ``main`` or
|
||||
When set to `true` functions that have a similar signature to ``main`` or
|
||||
``wmain`` won't enforce checks on the names of their parameters.
|
||||
Default value is `false`.
|
||||
|
||||
|
|
@ -1941,7 +1941,7 @@ After:
|
|||
|
||||
.. option:: ScopedEnumConstantCase
|
||||
|
||||
When defined, the check will ensure scoped enum constant names conform to
|
||||
When defined, the check will ensure scoped enum constant names conform to
|
||||
the selected casing.
|
||||
|
||||
.. option:: ScopedEnumConstantPrefix
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ readability-misleading-indentation
|
|||
Correct indentation helps to understand code. Mismatch of the syntactical
|
||||
structure and the indentation of the code may hide serious problems.
|
||||
Missing braces can also make it significantly harder to read the code,
|
||||
therefore it is important to use braces.
|
||||
therefore it is important to use braces.
|
||||
|
||||
The way to avoid dangling else is to always check that an ``else`` belongs
|
||||
to the ``if`` that begins in the same column.
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@
|
|||
readability-qualified-auto
|
||||
==========================
|
||||
|
||||
Adds pointer qualifications to ``auto``-typed variables that are deduced to
|
||||
Adds pointer qualifications to ``auto``-typed variables that are deduced to
|
||||
pointers.
|
||||
|
||||
`LLVM Coding Standards <https://llvm.org/docs/CodingStandards.html#beware-unnecessary-copies-with-auto>`_
|
||||
advises to make it obvious if a ``auto`` typed variable is a pointer. This
|
||||
advises to make it obvious if a ``auto`` typed variable is a pointer. This
|
||||
check will transform ``auto`` to ``auto *`` when the type is deduced to be a
|
||||
pointer.
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ Would be transformed into:
|
|||
observe(*Data);
|
||||
}
|
||||
|
||||
Note ``const`` ``volatile`` qualified types will retain their ``const`` and
|
||||
Note ``const`` ``volatile`` qualified types will retain their ``const`` and
|
||||
``volatile`` qualifiers. Pointers to pointers will not be fully qualified.
|
||||
|
||||
.. code-block:: c++
|
||||
|
|
@ -54,7 +54,7 @@ Options
|
|||
-------
|
||||
|
||||
.. option:: AddConstToQualified
|
||||
|
||||
|
||||
When set to `true` the check will add const qualifiers variables defined as
|
||||
``auto *`` or ``auto &`` when applicable.
|
||||
Default value is `true`.
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ readability-string-compare
|
|||
|
||||
Finds string comparisons using the compare method.
|
||||
|
||||
A common mistake is to use the string's ``compare`` method instead of using the
|
||||
A common mistake is to use the string's ``compare`` method instead of using the
|
||||
equality or inequality operators. The compare method is intended for sorting
|
||||
functions and thus returns a negative number, a positive number or
|
||||
zero depending on the lexicographical relationship between the strings compared.
|
||||
If an equality or inequality check can suffice, that is recommended. This is
|
||||
functions and thus returns a negative number, a positive number or
|
||||
zero depending on the lexicographical relationship between the strings compared.
|
||||
If an equality or inequality check can suffice, that is recommended. This is
|
||||
recommended to avoid the risk of incorrect interpretation of the return value
|
||||
and to simplify the code. The string equality and inequality operators can
|
||||
also be faster than the ``compare`` method due to early termination.
|
||||
|
|
@ -50,5 +50,5 @@ Examples:
|
|||
}
|
||||
|
||||
The above code examples show the list of if-statements that this check will
|
||||
give a warning for. All of them uses ``compare`` to check if equality or
|
||||
give a warning for. All of them uses ``compare`` to check if equality or
|
||||
inequality of two strings instead of using the correct operators.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ The latter is shorter, simpler and does not require use of raw pointer APIs.
|
|||
|
||||
std::unique_ptr<int> P;
|
||||
P = nullptr;
|
||||
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ The following module map will be generated::
|
|||
// Output/NoProblemsAssistant.txt
|
||||
// Generated by: modularize -module-map-path=Output/NoProblemsAssistant.txt \
|
||||
-root-module=Root NoProblemsAssistant.modularize
|
||||
|
||||
|
||||
module SomeTypes {
|
||||
header "SomeTypes.h"
|
||||
export *
|
||||
|
|
@ -219,7 +219,7 @@ For example, with the same header list from above::
|
|||
// Output/NoProblemsAssistant.txt
|
||||
// Generated by: modularize -module-map-path=Output/NoProblemsAssistant.txt \
|
||||
-root-module=Root NoProblemsAssistant.modularize
|
||||
|
||||
|
||||
module Root {
|
||||
module SomeTypes {
|
||||
header "SomeTypes.h"
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ of a file.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ==============================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ==============================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the directive.
|
||||
Reason (EnterFile|ExitFile|SystemHeaderPragma|RenameFile) PPCallbacks::FileChangeReason Reason for change.
|
||||
|
|
@ -186,7 +186,7 @@ guard optimization.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ========================================================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ========================================================
|
||||
ParentFile ("(file)" or (null)) const FileEntry The file that #included the skipped file.
|
||||
FilenameTok (token) const Token The token in ParentFile that indicates the skipped file.
|
||||
|
|
@ -208,7 +208,7 @@ FileNotFound is called when an inclusion directive results in a file-not-found e
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== =====================================================================================================================================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== =====================================================================================================================================
|
||||
FileName "(file)" StringRef The name of the file being included, as written in the source code.
|
||||
RecoveryPath (path) SmallVectorImpl<char> If this client indicates that it can recover from this missing file, the client should set this as an additional header search patch.
|
||||
|
|
@ -228,7 +228,7 @@ InclusionDirective is called when an inclusion directive of any kind (#include</
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ============================================================================================================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ============================================================================================================
|
||||
HashLoc "(file):(line):(col)" SourceLocation The location of the '#' that starts the inclusion directive.
|
||||
IncludeTok (token) const Token The token that indicates the kind of inclusion directive, e.g., 'include' or 'import'.
|
||||
|
|
@ -261,7 +261,7 @@ moduleImport is called when there was an explicit module-import syntax.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ===========================================================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ===========================================================
|
||||
ImportLoc "(file):(line):(col)" SourceLocation The location of import directive token.
|
||||
Path "(path)" ModuleIdPath The identifiers (and their locations) of the module "path".
|
||||
|
|
@ -283,7 +283,7 @@ EndOfMainFile is called when the end of the main file is reached.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ======================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ======================
|
||||
(no arguments)
|
||||
============== ================================================== ============================== ======================
|
||||
|
|
@ -300,7 +300,7 @@ Ident is called when a #ident or #sccs directive is read.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ==============================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ==============================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the directive.
|
||||
str (name) const std::string The text of the directive.
|
||||
|
|
@ -320,7 +320,7 @@ PragmaDirective is called when start reading any pragma directive.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== =================================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== =================================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the directive.
|
||||
Introducer (PIK_HashPragma|PIK__Pragma|PIK___pragma) PragmaIntroducerKind The type of the pragma directive.
|
||||
|
|
@ -340,7 +340,7 @@ PragmaComment is called when a #pragma comment directive is read.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ==============================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ==============================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the directive.
|
||||
Kind ((name)|(null)) const IdentifierInfo The comment kind symbol.
|
||||
|
|
@ -362,7 +362,7 @@ PragmaDetectMismatch is called when a #pragma detect_mismatch directive is read.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ==============================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ==============================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the directive.
|
||||
Name "(name)" const std::string The name.
|
||||
|
|
@ -384,7 +384,7 @@ PragmaDebug is called when a #pragma clang __debug directive is read.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ================================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ================================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the directive.
|
||||
DebugType (string) StringRef Indicates type of debug message.
|
||||
|
|
@ -404,7 +404,7 @@ PragmaMessage is called when a #pragma message directive is read.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== =======================================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== =======================================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the directive.
|
||||
Namespace (name) StringRef The namespace of the message directive.
|
||||
|
|
@ -428,7 +428,7 @@ PragmaDiagnosticPush is called when a #pragma gcc diagnostic push directive is r
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ==============================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ==============================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the directive.
|
||||
Namespace (name) StringRef Namespace name.
|
||||
|
|
@ -448,7 +448,7 @@ PragmaDiagnosticPop is called when a #pragma gcc diagnostic pop directive is rea
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ==============================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ==============================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the directive.
|
||||
Namespace (name) StringRef Namespace name.
|
||||
|
|
@ -468,7 +468,7 @@ PragmaDiagnostic is called when a #pragma gcc diagnostic directive is read.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ==============================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ==============================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the directive.
|
||||
Namespace (name) StringRef Namespace name.
|
||||
|
|
@ -492,7 +492,7 @@ PragmaOpenCLExtension is called when OpenCL extension is either disabled or enab
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ==========================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ==========================
|
||||
NameLoc "(file):(line):(col)" SourceLocation The location of the name.
|
||||
Name (name) const IdentifierInfo Name symbol.
|
||||
|
|
@ -516,7 +516,7 @@ PragmaWarning is called when a #pragma warning directive is read.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ==============================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ==============================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the directive.
|
||||
WarningSpec (string) StringRef The warning specifier.
|
||||
|
|
@ -538,7 +538,7 @@ PragmaWarningPush is called when a #pragma warning(push) directive is read.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ==============================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ==============================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the directive.
|
||||
Level (number) int Warning level.
|
||||
|
|
@ -558,7 +558,7 @@ PragmaWarningPop is called when a #pragma warning(pop) directive is read.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ==============================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ==============================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the directive.
|
||||
============== ================================================== ============================== ==============================
|
||||
|
|
@ -576,7 +576,7 @@ MacroExpands is called when ::HandleMacroExpandedIdentifier when a macro invocat
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ======================================================================================================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ======================================================================================================
|
||||
MacroNameTok (token) const Token The macro name token.
|
||||
MacroDirective (MD_Define|MD_Undefine|MD_Visibility) const MacroDirective The kind of macro directive from the MacroDirective structure.
|
||||
|
|
@ -600,7 +600,7 @@ MacroDefined is called when a macro definition is seen.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ==============================================================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ==============================================================
|
||||
MacroNameTok (token) const Token The macro name token.
|
||||
MacroDirective (MD_Define|MD_Undefine|MD_Visibility) const MacroDirective The kind of macro directive from the MacroDirective structure.
|
||||
|
|
@ -620,7 +620,7 @@ MacroUndefined is called when a macro #undef is seen.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ==============================================================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ==============================================================
|
||||
MacroNameTok (token) const Token The macro name token.
|
||||
MacroDirective (MD_Define|MD_Undefine|MD_Visibility) const MacroDirective The kind of macro directive from the MacroDirective structure.
|
||||
|
|
@ -640,7 +640,7 @@ Defined is called when the 'defined' operator is seen.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ==============================================================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ==============================================================
|
||||
MacroNameTok (token) const Token The macro name token.
|
||||
MacroDirective (MD_Define|MD_Undefine|MD_Visibility) const MacroDirective The kind of macro directive from the MacroDirective structure.
|
||||
|
|
@ -662,7 +662,7 @@ SourceRangeSkipped is called when a source range is skipped.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== =========================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== =========================
|
||||
Range ["(file):(line):(col)", "(file):(line):(col)"] SourceRange The source range skipped.
|
||||
============== ================================================== ============================== =========================
|
||||
|
|
@ -680,7 +680,7 @@ If is called when an #if is seen.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ===================================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ===================================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the directive.
|
||||
ConditionRange ["(file):(line):(col)", "(file):(line):(col)"] SourceRange The source range for the condition.
|
||||
|
|
@ -702,7 +702,7 @@ Elif is called when an #elif is seen.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ===================================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ===================================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the directive.
|
||||
ConditionRange ["(file):(line):(col)", "(file):(line):(col)"] SourceRange The source range for the condition.
|
||||
|
|
@ -726,7 +726,7 @@ Ifdef is called when an #ifdef is seen.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ==============================================================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ==============================================================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the directive.
|
||||
MacroNameTok (token) const Token The macro name token.
|
||||
|
|
@ -748,7 +748,7 @@ Ifndef is called when an #ifndef is seen.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ==============================================================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ==============================================================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the directive.
|
||||
MacroNameTok (token) const Token The macro name token.
|
||||
|
|
@ -770,7 +770,7 @@ Else is called when an #else is seen.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ===================================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ===================================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the else directive.
|
||||
IfLoc "(file):(line):(col)" SourceLocation The location of the if directive.
|
||||
|
|
@ -790,7 +790,7 @@ Endif is called when an #endif is seen.
|
|||
Argument descriptions:
|
||||
|
||||
============== ================================================== ============================== ====================================
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
Argument Name Argument Value Syntax Clang C++ Type Description
|
||||
============== ================================================== ============================== ====================================
|
||||
Loc "(file):(line):(col)" SourceLocation The location of the endif directive.
|
||||
IfLoc "(file):(line):(col)" SourceLocation The location of the if directive.
|
||||
|
|
@ -822,4 +822,3 @@ To build from source:
|
|||
.. _Getting Started with the LLVM System: https://llvm.org/docs/GettingStarted.html
|
||||
.. _Building LLVM with CMake: https://llvm.org/docs/CMake.html
|
||||
.. _Clang Tools Documentation: https://clang.llvm.org/docs/ClangTools.html
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ the following form:
|
|||
struct Block_literal_1 {
|
||||
void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
|
||||
int flags;
|
||||
int reserved;
|
||||
int reserved;
|
||||
R (*invoke)(struct Block_literal_1 *, P...);
|
||||
struct Block_descriptor_1 {
|
||||
unsigned long int reserved; // NULL
|
||||
|
|
@ -74,7 +74,7 @@ The following flags bits are in use thusly for a possible ABI.2010.3.16:
|
|||
BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code
|
||||
BLOCK_IS_GLOBAL = (1 << 28),
|
||||
BLOCK_HAS_STRET = (1 << 29), // IFF BLOCK_HAS_SIGNATURE
|
||||
BLOCK_HAS_SIGNATURE = (1 << 30),
|
||||
BLOCK_HAS_SIGNATURE = (1 << 30),
|
||||
};
|
||||
|
||||
In 10.6.ABI the (1<<29) was usually set and was always ignored by the runtime -
|
||||
|
|
@ -104,25 +104,25 @@ When a ``Block`` literal expression is evaluated the stack based structure is
|
|||
initialized as follows:
|
||||
|
||||
1. A ``static`` descriptor structure is declared and initialized as follows:
|
||||
|
||||
|
||||
a. The ``invoke`` function pointer is set to a function that takes the
|
||||
``Block`` structure as its first argument and the rest of the arguments (if
|
||||
any) to the ``Block`` and executes the ``Block`` compound statement.
|
||||
|
||||
|
||||
b. The ``size`` field is set to the size of the following ``Block`` literal
|
||||
structure.
|
||||
|
||||
|
||||
c. The ``copy_helper`` and ``dispose_helper`` function pointers are set to
|
||||
respective helper functions if they are required by the ``Block`` literal.
|
||||
|
||||
2. A stack (or global) ``Block`` literal data structure is created and
|
||||
initialized as follows:
|
||||
|
||||
|
||||
a. The ``isa`` field is set to the address of the external
|
||||
``_NSConcreteStackBlock``, which is a block of uninitialized memory supplied
|
||||
in ``libSystem``, or ``_NSConcreteGlobalBlock`` if this is a static or file
|
||||
level ``Block`` literal.
|
||||
|
||||
|
||||
b. The ``flags`` field is set to zero unless there are variables imported
|
||||
into the ``Block`` that need helper functions for program level
|
||||
``Block_copy()`` and ``Block_release()`` operations, in which case the
|
||||
|
|
@ -141,15 +141,15 @@ would cause the following to be created on a 32-bit system:
|
|||
struct __block_literal_1 {
|
||||
void *isa;
|
||||
int flags;
|
||||
int reserved;
|
||||
int reserved;
|
||||
void (*invoke)(struct __block_literal_1 *);
|
||||
struct __block_descriptor_1 *descriptor;
|
||||
};
|
||||
|
||||
|
||||
void __block_invoke_1(struct __block_literal_1 *_block) {
|
||||
printf("hello world\n");
|
||||
}
|
||||
|
||||
|
||||
static struct __block_descriptor_1 {
|
||||
unsigned long int reserved;
|
||||
unsigned long int Block_size;
|
||||
|
|
@ -214,20 +214,20 @@ The simplest example is that of importing a variable of type ``int``:
|
|||
which would be compiled to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
|
||||
struct __block_literal_2 {
|
||||
void *isa;
|
||||
int flags;
|
||||
int reserved;
|
||||
int reserved;
|
||||
void (*invoke)(struct __block_literal_2 *);
|
||||
struct __block_descriptor_2 *descriptor;
|
||||
const int x;
|
||||
};
|
||||
|
||||
|
||||
void __block_invoke_2(struct __block_literal_2 *_block) {
|
||||
printf("x is %d\n", _block->x);
|
||||
}
|
||||
|
||||
|
||||
static struct __block_descriptor_2 {
|
||||
unsigned long int reserved;
|
||||
unsigned long int Block_size;
|
||||
|
|
@ -266,33 +266,33 @@ A quick example:
|
|||
void (^existingBlock)(void) = ...;
|
||||
void (^vv)(void) = ^{ existingBlock(); }
|
||||
vv();
|
||||
|
||||
|
||||
struct __block_literal_3 {
|
||||
...; // existing block
|
||||
};
|
||||
|
||||
|
||||
struct __block_literal_4 {
|
||||
void *isa;
|
||||
int flags;
|
||||
int reserved;
|
||||
int reserved;
|
||||
void (*invoke)(struct __block_literal_4 *);
|
||||
struct __block_literal_3 *const existingBlock;
|
||||
};
|
||||
|
||||
|
||||
void __block_invoke_4(struct __block_literal_2 *_block) {
|
||||
__block->existingBlock->invoke(__block->existingBlock);
|
||||
}
|
||||
|
||||
|
||||
void __block_copy_4(struct __block_literal_4 *dst, struct __block_literal_4 *src) {
|
||||
//_Block_copy_assign(&dst->existingBlock, src->existingBlock, 0);
|
||||
_Block_object_assign(&dst->existingBlock, src->existingBlock, BLOCK_FIELD_IS_BLOCK);
|
||||
}
|
||||
|
||||
|
||||
void __block_dispose_4(struct __block_literal_4 *src) {
|
||||
// was _Block_destroy
|
||||
_Block_object_dispose(src->existingBlock, BLOCK_FIELD_IS_BLOCK);
|
||||
}
|
||||
|
||||
|
||||
static struct __block_descriptor_4 {
|
||||
unsigned long int reserved;
|
||||
unsigned long int Block_size;
|
||||
|
|
@ -344,7 +344,7 @@ would have the following helper functions generated:
|
|||
void __block_copy_foo(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
|
||||
_Block_object_assign(&dst->objectPointer, src-> objectPointer, BLOCK_FIELD_IS_OBJECT);
|
||||
}
|
||||
|
||||
|
||||
void __block_dispose_foo(struct __block_literal_5 *src) {
|
||||
_Block_object_dispose(src->objectPointer, BLOCK_FIELD_IS_OBJECT);
|
||||
}
|
||||
|
|
@ -392,17 +392,17 @@ The structure is initialized such that:
|
|||
|
||||
a. The ``forwarding`` pointer is set to the beginning of its enclosing
|
||||
structure.
|
||||
|
||||
|
||||
b. The ``size`` field is initialized to the total size of the enclosing
|
||||
structure.
|
||||
|
||||
structure.
|
||||
|
||||
c. The ``flags`` field is set to either 0 if no helper functions are needed
|
||||
or (1<<25) if they are.
|
||||
|
||||
d. The helper functions are initialized (if present).
|
||||
|
||||
e. The variable itself is set to its initial value.
|
||||
|
||||
or (1<<25) if they are.
|
||||
|
||||
d. The helper functions are initialized (if present).
|
||||
|
||||
e. The variable itself is set to its initial value.
|
||||
|
||||
f. The ``isa`` field is set to ``NULL``.
|
||||
|
||||
Access to ``__block`` variables from within its lexical scope
|
||||
|
|
@ -428,7 +428,7 @@ would be rewritten to be:
|
|||
int size;
|
||||
int captured_i;
|
||||
} i = { NULL, &i, 0, sizeof(struct _block_byref_i), 10 };
|
||||
|
||||
|
||||
i.forwarding->captured_i = 11;
|
||||
|
||||
In the case of a ``Block`` reference variable being marked ``__block`` the
|
||||
|
|
@ -454,12 +454,12 @@ would translate into:
|
|||
void (*byref_dispose)(struct _block_byref_voidBlock *);
|
||||
void (^captured_voidBlock)(void);
|
||||
};
|
||||
|
||||
|
||||
void _block_byref_keep_helper(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) {
|
||||
//_Block_copy_assign(&dst->captured_voidBlock, src->captured_voidBlock, 0);
|
||||
_Block_object_assign(&dst->captured_voidBlock, src->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER);
|
||||
}
|
||||
|
||||
|
||||
void _block_byref_dispose_helper(struct _block_byref_voidBlock *param) {
|
||||
//_Block_destroy(param->captured_voidBlock, 0);
|
||||
_Block_object_dispose(param->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER)}
|
||||
|
|
@ -471,7 +471,7 @@ and:
|
|||
struct _block_byref_voidBlock voidBlock = {( .forwarding=&voidBlock, .flags=(1<<25), .size=sizeof(struct _block_byref_voidBlock *),
|
||||
.byref_keep=_block_byref_keep_helper, .byref_dispose=_block_byref_dispose_helper,
|
||||
.captured_voidBlock=blockA )};
|
||||
|
||||
|
||||
voidBlock.forwarding->captured_voidBlock = blockB;
|
||||
|
||||
Importing ``__block`` variables into ``Blocks``
|
||||
|
|
@ -503,31 +503,31 @@ would translate to:
|
|||
void (*byref_dispose)(struct _block_byref_i *);
|
||||
int captured_i;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct __block_literal_5 {
|
||||
void *isa;
|
||||
int flags;
|
||||
int reserved;
|
||||
int reserved;
|
||||
void (*invoke)(struct __block_literal_5 *);
|
||||
struct __block_descriptor_5 *descriptor;
|
||||
struct _block_byref_i *i_holder;
|
||||
};
|
||||
|
||||
|
||||
void __block_invoke_5(struct __block_literal_5 *_block) {
|
||||
_block->forwarding->captured_i = 10;
|
||||
}
|
||||
|
||||
|
||||
void __block_copy_5(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
|
||||
//_Block_byref_assign_copy(&dst->captured_i, src->captured_i);
|
||||
_Block_object_assign(&dst->captured_i, src->captured_i, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
|
||||
}
|
||||
|
||||
|
||||
void __block_dispose_5(struct __block_literal_5 *src) {
|
||||
//_Block_byref_release(src->captured_i);
|
||||
_Block_object_dispose(src->captured_i, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
|
||||
}
|
||||
|
||||
|
||||
static struct __block_descriptor_5 {
|
||||
unsigned long int reserved;
|
||||
unsigned long int Block_size;
|
||||
|
|
@ -660,12 +660,12 @@ would translate to:
|
|||
void (*byref_dispose)(struct _block_byref_i *);
|
||||
id captured_obj;
|
||||
};
|
||||
|
||||
|
||||
void _block_byref_obj_keep(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) {
|
||||
//_Block_copy_assign(&dst->captured_obj, src->captured_obj, 0);
|
||||
_Block_object_assign(&dst->captured_obj, src->captured_obj, BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER);
|
||||
}
|
||||
|
||||
|
||||
void _block_byref_obj_dispose(struct _block_byref_voidBlock *param) {
|
||||
//_Block_destroy(param->captured_obj, 0);
|
||||
_Block_object_dispose(param->captured_obj, BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER);
|
||||
|
|
@ -678,26 +678,26 @@ for the block ``byref`` part and:
|
|||
struct __block_literal_5 {
|
||||
void *isa;
|
||||
int flags;
|
||||
int reserved;
|
||||
int reserved;
|
||||
void (*invoke)(struct __block_literal_5 *);
|
||||
struct __block_descriptor_5 *descriptor;
|
||||
struct _block_byref_obj *byref_obj;
|
||||
};
|
||||
|
||||
|
||||
void __block_invoke_5(struct __block_literal_5 *_block) {
|
||||
[objc_read_weak(&_block->byref_obj->forwarding->captured_obj) somemessage];
|
||||
}
|
||||
|
||||
|
||||
void __block_copy_5(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
|
||||
//_Block_byref_assign_copy(&dst->byref_obj, src->byref_obj);
|
||||
_Block_object_assign(&dst->byref_obj, src->byref_obj, BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK);
|
||||
}
|
||||
|
||||
|
||||
void __block_dispose_5(struct __block_literal_5 *src) {
|
||||
//_Block_byref_release(src->byref_obj);
|
||||
_Block_object_dispose(src->byref_obj, BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK);
|
||||
}
|
||||
|
||||
|
||||
static struct __block_descriptor_5 {
|
||||
unsigned long int reserved;
|
||||
unsigned long int Block_size;
|
||||
|
|
@ -712,7 +712,7 @@ and within the compound statement:
|
|||
truct _block_byref_obj obj = {( .forwarding=&obj, .flags=(1<<25), .size=sizeof(struct _block_byref_obj),
|
||||
.byref_keep=_block_byref_obj_keep, .byref_dispose=_block_byref_obj_dispose,
|
||||
.captured_obj = <initialization expression> )};
|
||||
|
||||
|
||||
truct __block_literal_5 _block_literal = {
|
||||
&_NSConcreteStackBlock,
|
||||
(1<<25)|(1<<29), <uninitialized>,
|
||||
|
|
@ -720,8 +720,8 @@ and within the compound statement:
|
|||
&__block_descriptor_5,
|
||||
&obj, // a reference to the on-stack structure containing "captured_obj"
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
functioncall(_block_literal->invoke(&_block_literal));
|
||||
|
||||
C++ Support
|
||||
|
|
@ -755,24 +755,24 @@ The compiler would synthesize:
|
|||
struct __block_literal_10 {
|
||||
void *isa;
|
||||
int flags;
|
||||
int reserved;
|
||||
int reserved;
|
||||
void (*invoke)(struct __block_literal_10 *);
|
||||
struct __block_descriptor_10 *descriptor;
|
||||
const FOO foo;
|
||||
};
|
||||
|
||||
|
||||
void __block_invoke_10(struct __block_literal_10 *_block) {
|
||||
printf("%d\n", _block->foo.value());
|
||||
}
|
||||
|
||||
|
||||
void __block_copy_10(struct __block_literal_10 *dst, struct __block_literal_10 *src) {
|
||||
FOO_ctor(&dst->foo, &src->foo);
|
||||
}
|
||||
|
||||
|
||||
void __block_dispose_10(struct __block_literal_10 *src) {
|
||||
FOO_dtor(&src->foo);
|
||||
}
|
||||
|
||||
|
||||
static struct __block_descriptor_10 {
|
||||
unsigned long int reserved;
|
||||
unsigned long int Block_size;
|
||||
|
|
@ -837,7 +837,7 @@ copy/dispose helpers:
|
|||
void _block_byref_obj_keep(struct _block_byref_blockStorageFoo *dst, struct _block_byref_blockStorageFoo *src) {
|
||||
FOO_ctor(&dst->blockStorageFoo, &src->blockStorageFoo);
|
||||
}
|
||||
|
||||
|
||||
void _block_byref_obj_dispose(struct _block_byref_blockStorageFoo *src) {
|
||||
FOO_dtor(&src->blockStorageFoo);
|
||||
}
|
||||
|
|
@ -881,9 +881,9 @@ in the dispose helper where ``<apropos>`` is:
|
|||
BLOCK_FIELD_IS_OBJECT = 3, // id, NSObject, __attribute__((NSObject)), block, ...
|
||||
BLOCK_FIELD_IS_BLOCK = 7, // a block variable
|
||||
BLOCK_FIELD_IS_BYREF = 8, // the on stack structure holding the __block variable
|
||||
|
||||
|
||||
BLOCK_FIELD_IS_WEAK = 16, // declared __weak
|
||||
|
||||
|
||||
BLOCK_BYREF_CALLER = 128, // called from byref copy/dispose helpers
|
||||
};
|
||||
|
||||
|
|
@ -903,7 +903,7 @@ this causes the addition of ``BLOCK_FIELD_IS_WEAK`` orred onto the
|
|||
The prototypes, and summary, of the helper functions are:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
|
||||
/* Certain field types require runtime assistance when being copied to the
|
||||
heap. The following function is used to copy fields of types: blocks,
|
||||
pointers to byref structures, and objects (including
|
||||
|
|
@ -912,7 +912,7 @@ The prototypes, and summary, of the helper functions are:
|
|||
helper will one see BLOCK_FIELD_IS_BYREF.
|
||||
*/
|
||||
void _Block_object_assign(void *destAddr, const void *object, const int flags);
|
||||
|
||||
|
||||
/* Similarly a compiler generated dispose helper needs to call back for each
|
||||
field of the byref data structure. (Currently the implementation only
|
||||
packs one field into the byref structure but in principle there could be
|
||||
|
|
|
|||
|
|
@ -3236,7 +3236,7 @@ the configuration (without a prefix: ``Auto``).
|
|||
**QualifierAlignment** (``QualifierAlignmentStyle``) :versionbadge:`clang-format 14`
|
||||
Different ways to arrange specifiers and qualifiers (e.g. const/volatile).
|
||||
|
||||
.. warning::
|
||||
.. warning::
|
||||
|
||||
Setting ``QualifierAlignment`` to something other than `Leave`, COULD
|
||||
lead to incorrect code formatting due to incorrect decisions made due to
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ Example::
|
|||
|
||||
1. Extract (libTest-nvptx-sm_50.a) => /tmp/a.cubin /tmp/b.cubin
|
||||
2. nvlink -o a.out-openmp-nvptx64 main.cubin /tmp/a.cubin /tmp/b.cubin
|
||||
|
||||
|
||||
**Output**
|
||||
|
||||
Output file generated by ``nvlink`` which links all cubin files.
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ similar to the one below before the program aborts.
|
|||
bad-cast.cpp:109:7: runtime error: control flow integrity check for type 'B' failed during base-to-derived cast (vtable address 0x000000425a50)
|
||||
0x000000425a50: note: vtable is of type 'A'
|
||||
00 00 00 00 f0 f1 41 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 5a 42 00
|
||||
^
|
||||
^
|
||||
|
||||
If diagnostics are enabled, you can also configure CFI to continue program
|
||||
execution instead of aborting by using the :ref:`-fsanitize-recover=
|
||||
|
|
|
|||
|
|
@ -121,9 +121,9 @@ example class hierarchy will be emitted like this:
|
|||
.. csv-table:: Bit Vectors for A, B, C
|
||||
:header: Class, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
|
||||
|
||||
A, , , 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, ,
|
||||
B, , , , , , , , 1, , , , , , ,
|
||||
C, , , , , , , , , , , , , 1, ,
|
||||
A, , , 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, ,
|
||||
B, , , , , , , , 1, , , , , , ,
|
||||
C, , , , , , , , , , , , , 1, ,
|
||||
|
||||
Short Inline Bit Vectors
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -149,7 +149,7 @@ If the bit vector fits in 32 bits, the code looks like this:
|
|||
de6: 48 89 df mov %rbx,%rdi
|
||||
de9: ff 10 callq *(%rax)
|
||||
[...]
|
||||
e0b: 0f 0b ud2
|
||||
e0b: 0f 0b ud2
|
||||
|
||||
Or if the bit vector fits in 64 bits:
|
||||
|
||||
|
|
@ -163,13 +163,13 @@ Or if the bit vector fits in 64 bits:
|
|||
11ba: 48 83 f9 2a cmp $0x2a,%rcx
|
||||
11be: 77 35 ja 11f5 <main+0xb5>
|
||||
11c0: 48 ba 09 00 00 00 00 movabs $0x40000000009,%rdx
|
||||
11c7: 04 00 00
|
||||
11c7: 04 00 00
|
||||
11ca: 48 0f a3 ca bt %rcx,%rdx
|
||||
11ce: 73 25 jae 11f5 <main+0xb5>
|
||||
11d0: 48 89 df mov %rbx,%rdi
|
||||
11d3: ff 10 callq *(%rax)
|
||||
[...]
|
||||
11f5: 0f 0b ud2
|
||||
11f5: 0f 0b ud2
|
||||
|
||||
If the bit vector consists of a single bit, there is only one possible
|
||||
virtual table, and the check can consist of a single equality comparison:
|
||||
|
|
@ -277,14 +277,14 @@ likely to occur if the virtual tables are padded.
|
|||
Forward-Edge CFI for Virtual Calls by Interleaving Virtual Tables
|
||||
-----------------------------------------------------------------
|
||||
|
||||
Dimitar et. al. proposed a novel approach that interleaves virtual tables in [1]_.
|
||||
This approach is more efficient in terms of space because padding and bit vectors are no longer needed.
|
||||
At the same time, it is also more efficient in terms of performance because in the interleaved layout
|
||||
address points of the virtual tables are consecutive, thus the validity check of a virtual
|
||||
vtable pointer is always a range check.
|
||||
Dimitar et. al. proposed a novel approach that interleaves virtual tables in [1]_.
|
||||
This approach is more efficient in terms of space because padding and bit vectors are no longer needed.
|
||||
At the same time, it is also more efficient in terms of performance because in the interleaved layout
|
||||
address points of the virtual tables are consecutive, thus the validity check of a virtual
|
||||
vtable pointer is always a range check.
|
||||
|
||||
At a high level, the interleaving scheme consists of three steps: 1) split virtual table groups into
|
||||
separate virtual tables, 2) order virtual tables by a pre-order traversal of the class hierarchy
|
||||
At a high level, the interleaving scheme consists of three steps: 1) split virtual table groups into
|
||||
separate virtual tables, 2) order virtual tables by a pre-order traversal of the class hierarchy
|
||||
and 3) interleave virtual tables.
|
||||
|
||||
The interleaving scheme implemented in LLVM is inspired by [1]_ but has its own
|
||||
|
|
@ -295,20 +295,20 @@ enhancements (more in `Interleave virtual tables`_).
|
|||
Split virtual table groups into separate virtual tables
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Itanium C++ ABI glues multiple individual virtual tables for a class into a combined virtual table (virtual table group).
|
||||
The Itanium C++ ABI glues multiple individual virtual tables for a class into a combined virtual table (virtual table group).
|
||||
The interleaving scheme, however, can only work with individual virtual tables so it must split the combined virtual tables first.
|
||||
In comparison, the old scheme does not require the splitting but it is more efficient when the combined virtual tables have been split.
|
||||
The `GlobalSplit`_ pass is responsible for splitting combined virtual tables into individual ones.
|
||||
The `GlobalSplit`_ pass is responsible for splitting combined virtual tables into individual ones.
|
||||
|
||||
.. _GlobalSplit: https://github.com/llvm/llvm-project/blob/main/llvm/lib/Transforms/IPO/GlobalSplit.cpp
|
||||
|
||||
Order virtual tables by a pre-order traversal of the class hierarchy
|
||||
Order virtual tables by a pre-order traversal of the class hierarchy
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This step is common to both the old scheme described above and the interleaving scheme.
|
||||
For the interleaving scheme, since the combined virtual tables have been split in the previous step,
|
||||
this step ensures that for any class all the compatible virtual tables will appear consecutively.
|
||||
For the old scheme, the same property may not hold since it may work on combined virtual tables.
|
||||
This step is common to both the old scheme described above and the interleaving scheme.
|
||||
For the interleaving scheme, since the combined virtual tables have been split in the previous step,
|
||||
this step ensures that for any class all the compatible virtual tables will appear consecutively.
|
||||
For the old scheme, the same property may not hold since it may work on combined virtual tables.
|
||||
|
||||
For example, consider the following four C++ classes:
|
||||
|
||||
|
|
@ -338,67 +338,67 @@ This step will arrange the virtual tables for A, B, C, and D in the order of *vt
|
|||
Interleave virtual tables
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This step is where the interleaving scheme deviates from the old scheme. Instead of laying out
|
||||
whole virtual tables in the previously computed order, the interleaving scheme lays out table
|
||||
entries of the virtual tables strategically to ensure the following properties:
|
||||
This step is where the interleaving scheme deviates from the old scheme. Instead of laying out
|
||||
whole virtual tables in the previously computed order, the interleaving scheme lays out table
|
||||
entries of the virtual tables strategically to ensure the following properties:
|
||||
|
||||
(1) offset-to-top and RTTI fields layout property
|
||||
|
||||
The Itanium C++ ABI specifies that offset-to-top and RTTI fields appear at the offsets behind the
|
||||
address point. Note that libraries like libcxxabi do assume this property.
|
||||
The Itanium C++ ABI specifies that offset-to-top and RTTI fields appear at the offsets behind the
|
||||
address point. Note that libraries like libcxxabi do assume this property.
|
||||
|
||||
(2) virtual function entry layout property
|
||||
|
||||
For each virtual function the distance between an virtual table entry for this function and the corresponding
|
||||
For each virtual function the distance between an virtual table entry for this function and the corresponding
|
||||
address point is always the same. This property ensures that dynamic dispatch still works with the interleaving layout.
|
||||
|
||||
Note that the interleaving scheme in the CFI implementation guarantees both properties above whereas the original scheme proposed
|
||||
in [1]_ only guarantees the second property.
|
||||
Note that the interleaving scheme in the CFI implementation guarantees both properties above whereas the original scheme proposed
|
||||
in [1]_ only guarantees the second property.
|
||||
|
||||
To illustrate how the interleaving algorithm works, let us continue with the running example.
|
||||
The algorithm first separates all the virtual table entries into two work lists. To do so,
|
||||
it starts by allocating two work lists, one initialized with all the offset-to-top entries of virtual tables in the order
|
||||
computed in the last step, one initialized with all the RTTI entries in the same order.
|
||||
The algorithm first separates all the virtual table entries into two work lists. To do so,
|
||||
it starts by allocating two work lists, one initialized with all the offset-to-top entries of virtual tables in the order
|
||||
computed in the last step, one initialized with all the RTTI entries in the same order.
|
||||
|
||||
.. csv-table:: Work list 1 Layout
|
||||
.. csv-table:: Work list 1 Layout
|
||||
:header: 0, 1, 2, 3
|
||||
|
||||
|
||||
A::offset-to-top, B::offset-to-top, D::offset-to-top, C::offset-to-top
|
||||
|
||||
|
||||
.. csv-table:: Work list 2 layout
|
||||
:header: 0, 1, 2, 3,
|
||||
|
||||
&A::rtti, &B::rtti, &D::rtti, &C::rtti
|
||||
|
||||
&A::rtti, &B::rtti, &D::rtti, &C::rtti
|
||||
|
||||
Then for each virtual function the algorithm goes through all the virtual tables in the previously computed order
|
||||
to collect all the related entries into a virtual function list.
|
||||
to collect all the related entries into a virtual function list.
|
||||
After this step, there are the following virtual function lists:
|
||||
|
||||
.. csv-table:: f1 list
|
||||
.. csv-table:: f1 list
|
||||
:header: 0, 1, 2, 3
|
||||
|
||||
&A::f1, &B::f1, &D::f1, &C::f1
|
||||
|
||||
|
||||
.. csv-table:: f2 list
|
||||
.. csv-table:: f2 list
|
||||
:header: 0, 1
|
||||
|
||||
&B::f2, &D::f2
|
||||
|
||||
|
||||
.. csv-table:: f3 list
|
||||
.. csv-table:: f3 list
|
||||
:header: 0
|
||||
|
||||
&C::f3
|
||||
|
||||
Next, the algorithm picks the longest remaining virtual function list and appends the whole list to the shortest work list
|
||||
until no function lists are left, and pads the shorter work list so that they are of the same length.
|
||||
In the example, f1 list will be first added to work list 1, then f2 list will be added
|
||||
to work list 2, and finally f3 list will be added to the work list 2. Since work list 1 now has one more entry than
|
||||
work list 2, a padding entry is added to the latter. After this step, the two work lists look like:
|
||||
until no function lists are left, and pads the shorter work list so that they are of the same length.
|
||||
In the example, f1 list will be first added to work list 1, then f2 list will be added
|
||||
to work list 2, and finally f3 list will be added to the work list 2. Since work list 1 now has one more entry than
|
||||
work list 2, a padding entry is added to the latter. After this step, the two work lists look like:
|
||||
|
||||
.. csv-table:: Work list 1 Layout
|
||||
.. csv-table:: Work list 1 Layout
|
||||
:header: 0, 1, 2, 3, 4, 5, 6, 7
|
||||
|
||||
A::offset-to-top, B::offset-to-top, D::offset-to-top, C::offset-to-top, &A::f1, &B::f1, &D::f1, &C::f1
|
||||
|
|
@ -407,19 +407,19 @@ work list 2, a padding entry is added to the latter. After this step, the two wo
|
|||
.. csv-table:: Work list 2 layout
|
||||
:header: 0, 1, 2, 3, 4, 5, 6, 7
|
||||
|
||||
&A::rtti, &B::rtti, &D::rtti, &C::rtti, &B::f2, &D::f2, &C::f3, padding
|
||||
&A::rtti, &B::rtti, &D::rtti, &C::rtti, &B::f2, &D::f2, &C::f3, padding
|
||||
|
||||
Finally, the algorithm merges the two work lists into the interleaved layout by alternatingly
|
||||
Finally, the algorithm merges the two work lists into the interleaved layout by alternatingly
|
||||
moving the head of each list to the final layout. After this step, the final interleaved layout looks like:
|
||||
|
||||
.. csv-table:: Interleaved layout
|
||||
:header: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
||||
:header: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
||||
|
||||
A::offset-to-top, &A::rtti, B::offset-to-top, &B::rtti, D::offset-to-top, &D::rtti, C::offset-to-top, &C::rtti, &A::f1, &B::f2, &B::f1, &D::f2, &D::f1, &C::f3, &C::f1, padding
|
||||
|
||||
In the above interleaved layout, each virtual table's offset-to-top and RTTI are always adjacent, which shows that the layout has the first property.
|
||||
For the second property, let us look at f2 as an example. In the interleaved layout,
|
||||
there are two entries for f2: B::f2 and D::f2. The distance between &B::f2
|
||||
there are two entries for f2: B::f2 and D::f2. The distance between &B::f2
|
||||
and its address point D::offset-to-top (the entry immediately after &B::rtti) is 5 entry-length, so is the distance between &D::f2 and C::offset-to-top (the entry immediately after &D::rtti).
|
||||
|
||||
Forward-Edge CFI for Indirect Function Calls
|
||||
|
|
|
|||
|
|
@ -685,7 +685,7 @@ use them to construct the ``-cc1`` job:
|
|||
|
||||
void Clang::ConstructJob(const ArgList &Args /*...*/) const {
|
||||
ArgStringList CmdArgs;
|
||||
// ...
|
||||
// ...
|
||||
|
||||
+ for (const Arg *A : Args.filtered(OPT_fpass_plugin_EQ)) {
|
||||
+ CmdArgs.push_back(Args.MakeArgString(Twine("-fpass-plugin=") + A->getValue()));
|
||||
|
|
@ -2883,7 +2883,7 @@ are created implicitly. The following spellings are accepted:
|
|||
|
||||
Subjects
|
||||
~~~~~~~~
|
||||
Attributes appertain to one or more subjects. If the attribute attempts to
|
||||
Attributes appertain to one or more subjects. If the attribute attempts to
|
||||
attach to a subject that is not in the subject list, a diagnostic is issued
|
||||
automatically. Whether the diagnostic is a warning or an error depends on how
|
||||
the attribute's ``SubjectList`` is defined, but the default behavior is to warn.
|
||||
|
|
@ -2914,7 +2914,7 @@ Documentation
|
|||
All attributes must have some form of documentation associated with them.
|
||||
Documentation is table generated on the public web server by a server-side
|
||||
process that runs daily. Generally, the documentation for an attribute is a
|
||||
stand-alone definition in `include/clang/Basic/AttrDocs.td
|
||||
stand-alone definition in `include/clang/Basic/AttrDocs.td
|
||||
<https://github.com/llvm/llvm-project/blob/main/clang/include/clang/Basic/AttrDocs.td>`_
|
||||
that is named after the attribute being documented.
|
||||
|
||||
|
|
@ -2932,7 +2932,7 @@ There are four predefined documentation categories: ``DocCatFunction`` for
|
|||
attributes that appertain to function-like subjects, ``DocCatVariable`` for
|
||||
attributes that appertain to variable-like subjects, ``DocCatType`` for type
|
||||
attributes, and ``DocCatStmt`` for statement attributes. A custom documentation
|
||||
category should be used for groups of attributes with similar functionality.
|
||||
category should be used for groups of attributes with similar functionality.
|
||||
Custom categories are good for providing overview information for the attributes
|
||||
grouped under it. For instance, the consumed annotation attributes define a
|
||||
custom category, ``DocCatConsumed``, that explains what consumed annotations are
|
||||
|
|
@ -3265,4 +3265,3 @@ are similar.
|
|||
proper visitation for your expression, enabling various IDE features such
|
||||
as syntax highlighting, cross-referencing, and so on. The
|
||||
``c-index-test`` helper program can be used to test these features.
|
||||
|
||||
|
|
|
|||
|
|
@ -4034,7 +4034,7 @@ mark macros as final, meaning they cannot be undef'd or re-defined. For example:
|
|||
#undef FINAL_MACRO // warning: FINAL_MACRO is marked final and should not be undefined
|
||||
|
||||
This is useful for enforcing system-provided macros that should not be altered
|
||||
in user headers or code. This is controlled by ``-Wpedantic-macros``. Final
|
||||
in user headers or code. This is controlled by ``-Wpedantic-macros``. Final
|
||||
macros will always warn on redefinition, including situations with identical
|
||||
bodies and in system headers.
|
||||
|
||||
|
|
@ -4077,7 +4077,7 @@ Examples are:
|
|||
|
||||
.. code-block:: c
|
||||
|
||||
# 57 // Advance (or return) to line 57 of the current source file
|
||||
# 57 // Advance (or return) to line 57 of the current source file
|
||||
# 57 "frob" // Set to line 57 of "frob"
|
||||
# 1 "foo.h" 1 // Enter "foo.h" at line 1
|
||||
# 59 "main.c" 2 // Leave current include and return to "main.c"
|
||||
|
|
|
|||
|
|
@ -33,12 +33,12 @@ The ``#include`` mechanism provided by the C preprocessor is a very poor way to
|
|||
code into headers.
|
||||
|
||||
* **Fragility**: ``#include`` directives are treated as textual
|
||||
inclusion by the preprocessor, and are therefore subject to any
|
||||
active macro definitions at the time of inclusion. If any of the
|
||||
active macro definitions happens to collide with a name in the
|
||||
library, it can break the library API or cause compilation failures
|
||||
in the library header itself. For an extreme example,
|
||||
``#define std "The C++ Standard"`` and then include a standard
|
||||
inclusion by the preprocessor, and are therefore subject to any
|
||||
active macro definitions at the time of inclusion. If any of the
|
||||
active macro definitions happens to collide with a name in the
|
||||
library, it can break the library API or cause compilation failures
|
||||
in the library header itself. For an extreme example,
|
||||
``#define std "The C++ Standard"`` and then include a standard
|
||||
library header: the result is a horrific cascade of failures in the
|
||||
C++ Standard Library's implementation. More subtle real-world
|
||||
problems occur when the headers for two different libraries interact
|
||||
|
|
@ -158,7 +158,7 @@ Module maps are specified as separate files (each named ``module.modulemap``) al
|
|||
.. note::
|
||||
|
||||
To actually see any benefits from modules, one first has to introduce module maps for the underlying C standard library and the libraries and headers on which it depends. The section `Modularizing a Platform`_ describes the steps one must take to write these module maps.
|
||||
|
||||
|
||||
One can use module maps without modules to check the integrity of the use of header files. To do this, use the ``-fimplicit-module-maps`` option instead of the ``-fmodules`` option, or use ``-fmodule-map-file=`` option to explicitly specify the module map files to load.
|
||||
|
||||
Compilation model
|
||||
|
|
@ -390,7 +390,7 @@ For example, suppose:
|
|||
|
||||
* ``<stdio.h>`` defines a macro ``getc`` (and exports its ``#define``)
|
||||
* ``<cstdio>`` imports the ``<stdio.h>`` module and undefines the macro (and exports its ``#undef``)
|
||||
|
||||
|
||||
The ``#undef`` overrides the ``#define``, and a source file that imports both modules *in any order* will not see ``getc`` defined as a macro.
|
||||
|
||||
Module Map Language
|
||||
|
|
@ -447,7 +447,7 @@ As an example, the module map file for the C standard library might look a bit l
|
|||
// ...more headers follow...
|
||||
}
|
||||
|
||||
Here, the top-level module ``std`` encompasses the whole C standard library. It has a number of submodules containing different parts of the standard library: ``complex`` for complex numbers, ``ctype`` for character types, etc. Each submodule lists one of more headers that provide the contents for that submodule. Finally, the ``export *`` command specifies that anything included by that submodule will be automatically re-exported.
|
||||
Here, the top-level module ``std`` encompasses the whole C standard library. It has a number of submodules containing different parts of the standard library: ``complex`` for complex numbers, ``ctype`` for character types, etc. Each submodule lists one of more headers that provide the contents for that submodule. Finally, the ``export *`` command specifies that anything included by that submodule will be automatically re-exported.
|
||||
|
||||
Lexical structure
|
||||
-----------------
|
||||
|
|
@ -646,7 +646,7 @@ A header with the ``umbrella`` specifier is called an umbrella header. An umbrel
|
|||
|
||||
.. note::
|
||||
Any headers not included by the umbrella header should have
|
||||
explicit ``header`` declarations. Use the
|
||||
explicit ``header`` declarations. Use the
|
||||
``-Wincomplete-umbrella`` warning option to ask Clang to complain
|
||||
about headers not covered by the umbrella header or the module map.
|
||||
|
||||
|
|
@ -691,7 +691,7 @@ An umbrella directory declaration specifies that all of the headers in the speci
|
|||
|
||||
*umbrella-dir-declaration*:
|
||||
``umbrella`` *string-literal*
|
||||
|
||||
|
||||
The *string-literal* refers to a directory. When the module is built, all of the header files in that directory (and its subdirectories) are included in the module.
|
||||
|
||||
An *umbrella-dir-declaration* shall not refer to the same directory as the location of an umbrella *header-declaration*. In other words, only a single kind of umbrella can be specified for a given directory.
|
||||
|
|
@ -719,7 +719,7 @@ A *submodule-declaration* that is an *inferred-submodule-declaration* describes
|
|||
|
||||
*inferred-submodule-declaration*:
|
||||
``explicit``:sub:`opt` ``framework``:sub:`opt` ``module`` '*' *attributes*:sub:`opt` '{' *inferred-submodule-member** '}'
|
||||
|
||||
|
||||
*inferred-submodule-member*:
|
||||
``export`` '*'
|
||||
|
||||
|
|
@ -729,9 +729,9 @@ For each header included by the umbrella header or in the umbrella directory tha
|
|||
|
||||
* Have the same name as the header (without the file extension)
|
||||
* Have the ``explicit`` specifier, if the *inferred-submodule-declaration* has the ``explicit`` specifier
|
||||
* Have the ``framework`` specifier, if the
|
||||
* Have the ``framework`` specifier, if the
|
||||
*inferred-submodule-declaration* has the ``framework`` specifier
|
||||
* Have the attributes specified by the \ *inferred-submodule-declaration*
|
||||
* Have the attributes specified by the \ *inferred-submodule-declaration*
|
||||
* Contain a single *header-declaration* naming that header
|
||||
* Contain a single *export-declaration* ``export *``, if the \ *inferred-submodule-declaration* contains the \ *inferred-submodule-member* ``export *``
|
||||
|
||||
|
|
@ -914,11 +914,11 @@ Each *identifier* in the *config-macro-list* specifies the name of a macro. The
|
|||
|
||||
A *config-macros-declaration* shall only be present on a top-level module, i.e., a module that is not nested within an enclosing module.
|
||||
|
||||
The ``exhaustive`` attribute specifies that the list of macros in the *config-macros-declaration* is exhaustive, meaning that no other macro definition is intended to have an effect on the API of that module.
|
||||
The ``exhaustive`` attribute specifies that the list of macros in the *config-macros-declaration* is exhaustive, meaning that no other macro definition is intended to have an effect on the API of that module.
|
||||
|
||||
.. note::
|
||||
|
||||
The ``exhaustive`` attribute implies that any macro definitions
|
||||
The ``exhaustive`` attribute implies that any macro definitions
|
||||
for macros not listed as configuration macros should be ignored
|
||||
completely when building the module. As an optimization, the
|
||||
compiler could reduce the number of unique module variants by not
|
||||
|
|
@ -1062,7 +1062,7 @@ When writing a private module as part of a *framework*, it's recommended that:
|
|||
|
||||
Modularizing a Platform
|
||||
=======================
|
||||
To get any benefit out of modules, one needs to introduce module maps for software libraries starting at the bottom of the stack. This typically means introducing a module map covering the operating system's headers and the C standard library headers (in ``/usr/include``, for a Unix system).
|
||||
To get any benefit out of modules, one needs to introduce module maps for software libraries starting at the bottom of the stack. This typically means introducing a module map covering the operating system's headers and the C standard library headers (in ``/usr/include``, for a Unix system).
|
||||
|
||||
The module maps will be written using the `module map language`_, which provides the tools necessary to describe the mapping between headers and modules. Because the set of headers differs from one system to the next, the module map will likely have to be somewhat customized for, e.g., a particular distribution and version of the operating system. Moreover, the system headers themselves may require some modification, if they exhibit any anti-patterns that break modules. Such common patterns are described below.
|
||||
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ if full functionality is required.
|
|||
**Example of Use**:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
|
||||
$ clang -Xclang -fdeclare-opencl-builtins test.cl
|
||||
|
||||
.. _opencl_fake_address_space_map:
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ following CMakeLists.txt to link it:
|
|||
|
||||
add_clang_executable(find-class-decls FindClassDecls.cpp)
|
||||
|
||||
target_link_libraries(find-class-decls
|
||||
target_link_libraries(find-class-decls
|
||||
PRIVATE
|
||||
clangAST
|
||||
clangBasic
|
||||
|
|
@ -224,4 +224,3 @@ declarations of a class n::m::C it found:
|
|||
|
||||
$ ./bin/find-class-decls "namespace n { namespace m { class C {}; } }"
|
||||
Found declaration at 1:29
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ With an additional ``...=trace-pc,indirect-calls`` flag
|
|||
|
||||
The functions `__sanitizer_cov_trace_pc_*` should be defined by the user.
|
||||
|
||||
Example:
|
||||
Example:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ Example:
|
|||
extern "C" void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
|
||||
if (!*guard) return; // Duplicate the guard check.
|
||||
// If you set *guard to 0 this code will not be called again for this edge.
|
||||
// Now you can get the PC and do whatever you want:
|
||||
// Now you can get the PC and do whatever you want:
|
||||
// store it somewhere or symbolize it and print right away.
|
||||
// The values of `*guard` are as you set them in
|
||||
// __sanitizer_cov_trace_pc_guard_init and so you can make them consecutive
|
||||
|
|
@ -96,7 +96,7 @@ Example:
|
|||
}
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
|
||||
clang++ -g -fsanitize-coverage=trace-pc-guard trace-pc-guard-example.cc -c
|
||||
clang++ trace-pc-guard-cb.cc trace-pc-guard-example.o -fsanitize=address
|
||||
ASAN_OPTIONS=strip_path_prefix=`pwd`/ ./a.out
|
||||
|
|
@ -295,7 +295,7 @@ will not be instrumented.
|
|||
void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2);
|
||||
|
||||
// Called before a comparison instruction if exactly one of the arguments is constant.
|
||||
// Arg1 and Arg2 are arguments of the comparison, Arg1 is a compile-time constant.
|
||||
// Arg1 and Arg2 are arguments of the comparison, Arg1 is a compile-time constant.
|
||||
// These callbacks are emitted by -fsanitize-coverage=trace-cmp since 2017-08-11
|
||||
void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2);
|
||||
void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2);
|
||||
|
|
@ -444,8 +444,8 @@ Sancov Tool
|
|||
An simple ``sancov`` tool is provided to process coverage files.
|
||||
The tool is part of LLVM project and is currently supported only on Linux.
|
||||
It can handle symbolization tasks autonomously without any extra support
|
||||
from the environment. You need to pass .sancov files (named
|
||||
``<module_name>.<pid>.sancov`` and paths to all corresponding binary elf files.
|
||||
from the environment. You need to pass .sancov files (named
|
||||
``<module_name>.<pid>.sancov`` and paths to all corresponding binary elf files.
|
||||
Sancov matches these files using module names and binaries file names.
|
||||
|
||||
.. code-block:: console
|
||||
|
|
|
|||
|
|
@ -892,7 +892,7 @@ implementation.
|
|||
|
||||
// Assert that is mutex is currently held for read operations.
|
||||
void AssertReaderHeld() ASSERT_SHARED_CAPABILITY(this);
|
||||
|
||||
|
||||
// For negative capabilities.
|
||||
const Mutex& operator!() const { return *this; }
|
||||
};
|
||||
|
|
@ -1041,4 +1041,3 @@ implementation.
|
|||
#endif // USE_LOCK_STYLE_THREAD_SAFETY_ATTRIBUTES
|
||||
|
||||
#endif // THREAD_SAFETY_ANALYSIS_MUTEX_H
|
||||
|
||||
|
|
|
|||
|
|
@ -777,22 +777,22 @@ compilations steps.
|
|||
ld,"a.out",900,8000,53568
|
||||
|
||||
The data on each row represent:
|
||||
|
||||
|
||||
* file name of the tool executable,
|
||||
* output file name in quotes,
|
||||
* total execution time in microseconds,
|
||||
* execution time in user mode in microseconds,
|
||||
* peak memory usage in Kb.
|
||||
|
||||
|
||||
It is possible to specify this option without any value. In this case statistics
|
||||
are printed on standard output in human readable format:
|
||||
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ clang -fproc-stat-report foo.c
|
||||
clang-11: output=/tmp/foo-855a8e.o, total=68.000 ms, user=60.000 ms, mem=86920 Kb
|
||||
ld: output=a.out, total=8.000 ms, user=4.000 ms, mem=52320 Kb
|
||||
|
||||
|
||||
The report file specified in the option is locked for write, so this option
|
||||
can be used to collect statistics in parallel builds. The report file is not
|
||||
cleared, new data is appended to it, thus making posible to accumulate build
|
||||
|
|
@ -1347,7 +1347,7 @@ floating point semantic models: precise (the default), strict, and fast.
|
|||
|
||||
Select which denormal numbers the code is permitted to require.
|
||||
|
||||
Valid values are:
|
||||
Valid values are:
|
||||
|
||||
* ``ieee`` - IEEE 754 denormal numbers
|
||||
* ``preserve-sign`` - the sign of a flushed-to-zero number is preserved in the sign of 0
|
||||
|
|
@ -1359,7 +1359,7 @@ floating point semantic models: precise (the default), strict, and fast.
|
|||
|
||||
**-f[no-]strict-float-cast-overflow**
|
||||
|
||||
When a floating-point value is not representable in a destination integer
|
||||
When a floating-point value is not representable in a destination integer
|
||||
type, the code has undefined behavior according to the language standard.
|
||||
By default, Clang will not guarantee any particular result in that case.
|
||||
With the 'no-strict' option, Clang attempts to match the overflowing behavior
|
||||
|
|
@ -1540,7 +1540,7 @@ Note that floating-point operations performed as part of constant initialization
|
|||
the optimizer may ignore parentheses when computing arithmetic expressions
|
||||
in circumstances where the parenthesized and unparenthesized expression
|
||||
express the same mathematical value. For example (a+b)+c is the same
|
||||
mathematical value as a+(b+c), but the optimizer is free to evaluate the
|
||||
mathematical value as a+(b+c), but the optimizer is free to evaluate the
|
||||
additions in any order regardless of the parentheses. When enabled, this
|
||||
option forces the optimizer to honor the order of operations with respect
|
||||
to parentheses in all circumstances.
|
||||
|
|
@ -2213,7 +2213,7 @@ instrumentation:
|
|||
2. Run the instrumented executable with inputs that reflect the typical usage.
|
||||
By default, the profile data will be written to a ``default.profraw`` file
|
||||
in the current directory. You can override that default by using option
|
||||
``-fprofile-instr-generate=`` or by setting the ``LLVM_PROFILE_FILE``
|
||||
``-fprofile-instr-generate=`` or by setting the ``LLVM_PROFILE_FILE``
|
||||
environment variable to specify an alternate file. If non-default file name
|
||||
is specified by both the environment variable and the command line option,
|
||||
the environment variable takes precedence. The file name pattern specified
|
||||
|
|
@ -2303,7 +2303,7 @@ programs using the same instrumentation method as ``-fprofile-generate``.
|
|||
When ``code`` is executed, the profile will be written to the file
|
||||
``yyy/zzz/default_xxxx.profraw``.
|
||||
|
||||
To generate the profile data file with the compiler readable format, the
|
||||
To generate the profile data file with the compiler readable format, the
|
||||
``llvm-profdata`` tool can be used with the profile directory as the input:
|
||||
|
||||
.. code-block:: console
|
||||
|
|
@ -2567,7 +2567,7 @@ from ``-fprofile-exclude-list``.
|
|||
|
||||
$ clang --coverage -fprofile-exclude-files="^/usr/include/.*$" \
|
||||
-fprofile-filter-files="^/usr/.*$"
|
||||
|
||||
|
||||
In that case ``/usr/foo/oof.h`` is instrumented since it matches the filter regex and
|
||||
doesn't match the exclude regex, but ``/usr/include/foo.h`` doesn't since it matches
|
||||
the exclude regex.
|
||||
|
|
@ -3020,7 +3020,7 @@ tools
|
|||
|
||||
Clang currently supports OpenCL C language standards up to v2.0. Clang mainly
|
||||
supports full profile. There is only very limited support of the embedded
|
||||
profile.
|
||||
profile.
|
||||
Starting from clang 9 a C++ mode is available for OpenCL (see
|
||||
:ref:`C++ for OpenCL <cxx_for_opencl>`).
|
||||
|
||||
|
|
@ -3213,14 +3213,14 @@ convergent
|
|||
To make sure no invalid optimizations occur for single program multiple data
|
||||
(SPMD) / single instruction multiple thread (SIMT) Clang provides attributes that
|
||||
can be used for special functions that have cross work item semantics.
|
||||
An example is the subgroup operations such as `intel_sub_group_shuffle
|
||||
An example is the subgroup operations such as `intel_sub_group_shuffle
|
||||
<https://www.khronos.org/registry/cl/extensions/intel/cl_intel_subgroups.txt>`_
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
// Define custom my_sub_group_shuffle(data, c)
|
||||
// that makes use of intel_sub_group_shuffle
|
||||
r1 = ...
|
||||
r1 = ...
|
||||
if (r0) r1 = computeA();
|
||||
// Shuffle data from r1 into r3
|
||||
// of threads id r2.
|
||||
|
|
@ -3252,7 +3252,7 @@ would prevent this:
|
|||
Using ``convergent`` guarantees correct execution by keeping CFG equivalence
|
||||
wrt operations marked as ``convergent``. CFG ``G´`` is equivalent to ``G`` wrt
|
||||
node ``Ni`` : ``iff ∀ Nj (i≠j)`` domination and post-domination relations with
|
||||
respect to ``Ni`` remain the same in both ``G`` and ``G´``.
|
||||
respect to ``Ni`` remain the same in both ``G`` and ``G´``.
|
||||
|
||||
noduplicate
|
||||
^^^^^^^^^^^
|
||||
|
|
@ -3333,7 +3333,7 @@ mode.
|
|||
|
||||
clang test.clcpp
|
||||
|
||||
C++ for OpenCL kernel sources can also be compiled online in drivers supporting
|
||||
C++ for OpenCL kernel sources can also be compiled online in drivers supporting
|
||||
`cl_ext_cxx_for_opencl
|
||||
<https://www.khronos.org/registry/OpenCL/extensions/ext/cl_ext_cxx_for_opencl.html>`_
|
||||
extension.
|
||||
|
|
@ -3350,7 +3350,7 @@ constructors. However, an easy workaround is to manually enqueue the
|
|||
constructor initialization kernel that has the following name scheme
|
||||
``_GLOBAL__sub_I_<compiled file name>``.
|
||||
This kernel is only present if there are global objects with non-trivial
|
||||
constructors present in the compiled binary. One way to check this is by
|
||||
constructors present in the compiled binary. One way to check this is by
|
||||
passing ``CL_PROGRAM_KERNEL_NAMES`` to ``clGetProgramInfo`` (OpenCL v2.0
|
||||
s5.8.7) and then checking whether any kernel name matches the naming scheme of
|
||||
global constructor initialization kernel above.
|
||||
|
|
|
|||
|
|
@ -5,10 +5,9 @@ Contents:
|
|||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
|
||||
developer-docs/DebugChecks
|
||||
developer-docs/IPA
|
||||
developer-docs/InitializerLists
|
||||
developer-docs/nullability
|
||||
developer-docs/RegionStore
|
||||
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ ExprInspection checks
|
|||
clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
|
||||
return 42;
|
||||
}
|
||||
|
||||
|
||||
void topLevel() {
|
||||
clang_analyzer_checkInlined(false); // no-warning (not inlined)
|
||||
int value = inlined();
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ Inlining
|
|||
There are several options that control which calls the analyzer will consider for
|
||||
inlining. The major one is ``-analyzer-config ipa``:
|
||||
|
||||
* ``analyzer-config ipa=none`` - All inlining is disabled. This is the only mode
|
||||
* ``analyzer-config ipa=none`` - All inlining is disabled. This is the only mode
|
||||
available in LLVM 3.1 and earlier and in Xcode 4.3 and earlier.
|
||||
|
||||
* ``analyzer-config ipa=basic-inlining`` - Turns on inlining for C functions, C++
|
||||
static member functions, and blocks -- essentially, the calls that behave
|
||||
like simple C function calls. This is essentially the mode used in
|
||||
* ``analyzer-config ipa=basic-inlining`` - Turns on inlining for C functions, C++
|
||||
static member functions, and blocks -- essentially, the calls that behave
|
||||
like simple C function calls. This is essentially the mode used in
|
||||
Xcode 4.4.
|
||||
|
||||
* ``analyzer-config ipa=inlining`` - Turns on inlining when we can confidently find
|
||||
|
|
@ -23,15 +23,15 @@ inlining. The major one is ``-analyzer-config ipa``:
|
|||
correct. For virtual calls, inline the most plausible definition.
|
||||
|
||||
* ``analyzer-config ipa=dynamic-bifurcate`` - Same as -analyzer-config ipa=dynamic,
|
||||
but the path is split. We inline on one branch and do not inline on the
|
||||
other. This mode does not drop the coverage in cases when the parent class
|
||||
but the path is split. We inline on one branch and do not inline on the
|
||||
other. This mode does not drop the coverage in cases when the parent class
|
||||
has code that is only exercised when some of its methods are overridden.
|
||||
|
||||
Currently, ``-analyzer-config ipa=dynamic-bifurcate`` is the default mode.
|
||||
|
||||
While ``-analyzer-config ipa`` determines in general how aggressively the analyzer
|
||||
will try to inline functions, several additional options control which types of
|
||||
functions can inlined, in an all-or-nothing way. These options use the
|
||||
While ``-analyzer-config ipa`` determines in general how aggressively the analyzer
|
||||
will try to inline functions, several additional options control which types of
|
||||
functions can inlined, in an all-or-nothing way. These options use the
|
||||
analyzer's configuration table, so they are all specified as follows:
|
||||
|
||||
``-analyzer-config OPTION=VALUE``
|
||||
|
|
@ -52,7 +52,7 @@ functions with visible definitions will be considered for inlining. In some
|
|||
cases the analyzer may still choose not to inline the function.
|
||||
|
||||
Note that under 'constructors', constructors for types with non-trivial
|
||||
destructors will not be inlined. Additionally, no C++ member functions will be
|
||||
destructors will not be inlined. Additionally, no C++ member functions will be
|
||||
inlined under -analyzer-config ipa=none or -analyzer-config ipa=basic-inlining,
|
||||
regardless of the setting of the c++-inlining mode.
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ considered for inlining.
|
|||
|
||||
``-analyzer-config c++-stdlib-inlining=[true | false]``
|
||||
|
||||
Currently, C++ standard library functions are considered for inlining by
|
||||
Currently, C++ standard library functions are considered for inlining by
|
||||
default.
|
||||
|
||||
The standard library functions and the STL in particular are used ubiquitously
|
||||
|
|
@ -107,7 +107,7 @@ objects. For example, these three expressions should be equivalent:
|
|||
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
|
||||
std::distance(c.begin(), c.end()) == 0
|
||||
c.begin() == c.end()
|
||||
c.empty()
|
||||
|
|
@ -214,7 +214,7 @@ Dynamic Calls and Devirtualization
|
|||
"Dynamic" calls are those that are resolved at runtime, such as C++ virtual
|
||||
method calls and Objective-C message sends. Due to the path-sensitive nature of
|
||||
the analysis, the analyzer may be able to reason about the dynamic type of the
|
||||
object whose method is being called and thus "devirtualize" the call.
|
||||
object whose method is being called and thus "devirtualize" the call.
|
||||
|
||||
This path-sensitive devirtualization occurs when the analyzer can determine what
|
||||
method would actually be called at runtime. This is possible when the type
|
||||
|
|
@ -268,14 +268,14 @@ parlance), which ExprEngine uses to decide whether or not the call should be
|
|||
inlined.
|
||||
|
||||
Inlining Dynamic Calls
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The -analyzer-config ipa option has five different modes: none, basic-inlining,
|
||||
inlining, dynamic, and dynamic-bifurcate. Under -analyzer-config ipa=dynamic,
|
||||
all dynamic calls are inlined, whether we are certain or not that this will
|
||||
actually be the definition used at runtime. Under -analyzer-config ipa=inlining,
|
||||
only "near-perfect" devirtualized calls are inlined*, and other dynamic calls
|
||||
are evaluated conservatively (as if no definition were available).
|
||||
are evaluated conservatively (as if no definition were available).
|
||||
|
||||
* Currently, no Objective-C messages are not inlined under
|
||||
-analyzer-config ipa=inlining, even if we are reasonably confident of the type
|
||||
|
|
@ -286,8 +286,8 @@ The last option, -analyzer-config ipa=dynamic-bifurcate, behaves similarly to
|
|||
"dynamic", but performs a conservative invalidation in the general virtual case
|
||||
in *addition* to inlining. The details of this are discussed below.
|
||||
|
||||
As stated above, -analyzer-config ipa=basic-inlining does not inline any C++
|
||||
member functions or Objective-C method calls, even if they are non-virtual or
|
||||
As stated above, -analyzer-config ipa=basic-inlining does not inline any C++
|
||||
member functions or Objective-C method calls, even if they are non-virtual or
|
||||
can be safely devirtualized.
|
||||
|
||||
|
||||
|
|
@ -297,29 +297,29 @@ Bifurcation
|
|||
ExprEngine::BifurcateCall implements the ``-analyzer-config ipa=dynamic-bifurcate``
|
||||
mode.
|
||||
|
||||
When a call is made on an object with imprecise dynamic type information
|
||||
When a call is made on an object with imprecise dynamic type information
|
||||
(RuntimeDefinition::mayHaveOtherDefinitions() evaluates to TRUE), ExprEngine
|
||||
bifurcates the path and marks the object's region (retrieved from the
|
||||
RuntimeDefinition object) with a path-sensitive "mode" in the ProgramState.
|
||||
|
||||
Currently, there are 2 modes:
|
||||
Currently, there are 2 modes:
|
||||
|
||||
* ``DynamicDispatchModeInlined`` - Models the case where the dynamic type information
|
||||
of the receiver (MemoryRegion) is assumed to be perfectly constrained so
|
||||
that a given definition of a method is expected to be the code actually
|
||||
called. When this mode is set, ExprEngine uses the Decl from
|
||||
RuntimeDefinition to inline any dynamically dispatched call sent to this
|
||||
of the receiver (MemoryRegion) is assumed to be perfectly constrained so
|
||||
that a given definition of a method is expected to be the code actually
|
||||
called. When this mode is set, ExprEngine uses the Decl from
|
||||
RuntimeDefinition to inline any dynamically dispatched call sent to this
|
||||
receiver because the function definition is considered to be fully resolved.
|
||||
|
||||
* ``DynamicDispatchModeConservative`` - Models the case where the dynamic type
|
||||
information is assumed to be incorrect, for example, implies that the method
|
||||
definition is overridden in a subclass. In such cases, ExprEngine does not
|
||||
inline the methods sent to the receiver (MemoryRegion), even if a candidate
|
||||
definition is available. This mode is conservative about simulating the
|
||||
information is assumed to be incorrect, for example, implies that the method
|
||||
definition is overridden in a subclass. In such cases, ExprEngine does not
|
||||
inline the methods sent to the receiver (MemoryRegion), even if a candidate
|
||||
definition is available. This mode is conservative about simulating the
|
||||
effects of a call.
|
||||
|
||||
Going forward along the symbolic execution path, ExprEngine consults the mode
|
||||
of the receiver's MemRegion to make decisions on whether the calls should be
|
||||
Going forward along the symbolic execution path, ExprEngine consults the mode
|
||||
of the receiver's MemRegion to make decisions on whether the calls should be
|
||||
inlined or not, which ensures that there is at most one split per region.
|
||||
|
||||
At a high level, "bifurcation mode" allows for increased semantic coverage in
|
||||
|
|
@ -331,8 +331,8 @@ conservative mode is used.
|
|||
Objective-C Message Heuristics
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
ExprEngine relies on a set of heuristics to partition the set of Objective-C
|
||||
method calls into those that require bifurcation and those that do not. Below
|
||||
ExprEngine relies on a set of heuristics to partition the set of Objective-C
|
||||
method calls into those that require bifurcation and those that do not. Below
|
||||
are the cases when the DynamicTypeInfo of the object is considered precise
|
||||
(cannot be a subclass):
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ performance overhead, and clarity seems nice.
|
|||
|
||||
At this point, I am a bit wondering about two questions.
|
||||
|
||||
* When should something belong to a checker and when should something belong to the engine?
|
||||
* When should something belong to a checker and when should something belong to the engine?
|
||||
Sometimes we model library aspects in the engine and model language constructs in checkers.
|
||||
|
||||
* What is the checker programming model that we are aiming for? Maximum freedom or more easy checker development?
|
||||
|
|
@ -218,11 +218,11 @@ essentially immutable. For the future, i feel as if it is a dead end.
|
|||
I'd like to consider another funny example. Suppose we're trying to model
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
|
||||
std::unique_ptr. Consider::
|
||||
|
||||
|
||||
void bar(const std::unique_ptr<int> &x);
|
||||
|
||||
|
||||
void foo(std::unique_ptr<int> &x) {
|
||||
int *a = x.get(); // (a, 0, direct): &AbstractStorageRegion
|
||||
*a = 1; // (AbstractStorageRegion, 0, direct): 1 S32b
|
||||
|
|
@ -233,7 +233,7 @@ I'd like to consider another funny example. Suppose we're trying to model
|
|||
clang_analyzer_eval(*a == 1); // Making this true is up to the checker.
|
||||
clang_analyzer_eval(*b == 2); // Making this unknown is up to the checker.
|
||||
}
|
||||
|
||||
|
||||
The checker doesn't totally need to ensure that ``*a == 1`` passes - even though the
|
||||
pointer was unique, it could theoretically have ``.get()``-ed above and the code
|
||||
could of course break the uniqueness invariant (though we'd probably want it).
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ Explicit cast from nullable to nonnul:
|
|||
anotherTakesNonNull(bar); // would be great to warn here, but not necessary(*)
|
||||
|
||||
Because bar corresponds to the same symbol all the time it is not easy to implement the checker that way the cast only suppress the first call but not the second. For this reason in the first implementation after a contradictory cast happens, I will treat bar as nullable unspecified, this way all of the warnings will be suppressed. Treating the symbol as nullable unspecified also has an advantage that in case the takesNonNull function body is being inlined, the will be no warning, when the symbol is dereferenced. In case I have time after the initial version I might spend additional time to try to find a more sophisticated solution, in which we would produce the second warning (*).
|
||||
|
||||
|
||||
**2) nonnull**
|
||||
|
||||
* Dereferencing a nonnull, or sending message to it is ok.
|
||||
|
|
@ -77,11 +77,11 @@ A symbol may need to be treated differently inside an inlined body. For example,
|
|||
id obj = getNonnull();
|
||||
takesNullable(obj);
|
||||
takesNonnull(obj);
|
||||
|
||||
|
||||
void takesNullable(nullable id obj) {
|
||||
obj->ivar // we should assume obj is nullable and warn here
|
||||
}
|
||||
|
||||
|
||||
With no special treatment, when the takesNullable is inlined the analyzer will not warn when the obj symbol is dereferenced. One solution for this is to reanalyze takesNullable as a top level function to get possible violations. The alternative method, deducing nullability information from the arguments after inlining is not robust enough (for example there might be more parameters with different nullability, but in the given path the two parameters might end up being the same symbol or there can be nested functions that take different view of the nullability of the same symbol). So the symbol will remain nonnull to avoid false positives but the functions that takes nullable parameters will be analyzed separately as well without inlining.
|
||||
|
||||
Annotations on multi level pointers
|
||||
|
|
|
|||
|
|
@ -261,15 +261,15 @@ The compilation database:
|
|||
The `invocation list`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
"/path/to/your/project/foo.cpp":
|
||||
|
||||
"/path/to/your/project/foo.cpp":
|
||||
- "clang++"
|
||||
- "-c"
|
||||
- "/path/to/your/project/foo.cpp"
|
||||
- "-o"
|
||||
- "/path/to/your/project/foo.o"
|
||||
|
||||
"/path/to/your/project/main.cpp":
|
||||
"/path/to/your/project/main.cpp":
|
||||
- "clang++"
|
||||
- "-c"
|
||||
- "/path/to/your/project/main.cpp"
|
||||
|
|
@ -374,4 +374,3 @@ We actively develop CTU with CodeChecker as the driver for feature, `scan-build-
|
|||
`scan-build-py` has various errors and issues, expect it to work only with the very basic projects only.
|
||||
|
||||
Currently On-demand analysis is not supported with `scan-build-py`.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@ Fuzzing for LLVM-libc
|
|||
---------------------
|
||||
|
||||
Fuzzing tests are used to ensure quality and security of LLVM-libc
|
||||
implementations.
|
||||
implementations.
|
||||
|
||||
Each fuzzing test lives under the fuzzing directory in a subdirectory
|
||||
corresponding with the src layout.
|
||||
corresponding with the src layout.
|
||||
|
||||
Currently we use system libc for functions that have yet to be implemented,
|
||||
however as they are implemented the fuzzers will be changed to use our
|
||||
implementation to increase coverage for testing.
|
||||
however as they are implemented the fuzzers will be changed to use our
|
||||
implementation to increase coverage for testing.
|
||||
|
||||
Fuzzers will be run on `oss-fuzz <https://github.com/google/oss-fuzz>`_ and the
|
||||
check-libc target will ensure that they build correctly.
|
||||
check-libc target will ensure that they build correctly.
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@ ObjC symbols treatment
|
|||
There are differences in how LLD and LD64 handle ObjC symbols loaded from archives.
|
||||
|
||||
- LD64:
|
||||
* Duplicate ObjC symbols from the same archives will not raise an error. LD64 will pick the first one.
|
||||
* Duplicate ObjC symbols from the same archives will not raise an error. LD64 will pick the first one.
|
||||
* Duplicate ObjC symbols from different archives will raise a "duplicate symbol" error.
|
||||
- LLD:
|
||||
* Duplicate symbols, regardless of which archives they are from, will raise errors.
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ This is the object format that the llvm will produce when run with the
|
|||
Usage
|
||||
-----
|
||||
|
||||
The WebAssembly version of lld is installed as **wasm-ld**. It shared many
|
||||
The WebAssembly version of lld is installed as **wasm-ld**. It shared many
|
||||
common linker flags with **ld.lld** but also includes several
|
||||
WebAssembly-specific options:
|
||||
|
||||
|
|
|
|||
|
|
@ -321,7 +321,7 @@ A better way to write the test above would be using LLDB's testing function
|
|||
|
||||
**Do not use hard-coded line numbers in your test case.**
|
||||
|
||||
Instead, try to tag the line with some distinguishing pattern, and use the function line_number() defined in lldbtest.py which takes
|
||||
Instead, try to tag the line with some distinguishing pattern, and use the function line_number() defined in lldbtest.py which takes
|
||||
filename and string_to_match as arguments and returns the line number.
|
||||
|
||||
As an example, take a look at test/API/functionalities/breakpoint/breakpoint_conditions/main.c which has these
|
||||
|
|
@ -369,7 +369,7 @@ the test harness.
|
|||
|
||||
The default cleanup action performed by the packages/Python/lldbsuite/test/lldbtest.py module invokes the "make clean" os command.
|
||||
|
||||
If this default cleanup is not enough, individual class can provide an extra cleanup hook with a class method named classCleanup ,
|
||||
If this default cleanup is not enough, individual class can provide an extra cleanup hook with a class method named classCleanup ,
|
||||
for example, in test/API/terminal/TestSTTYBeforeAndAfter.py:
|
||||
|
||||
.. code-block:: python
|
||||
|
|
@ -380,7 +380,7 @@ for example, in test/API/terminal/TestSTTYBeforeAndAfter.py:
|
|||
cls.RemoveTempFile("child_send1.txt")
|
||||
|
||||
|
||||
The 'child_send1.txt' file gets generated during the test run, so it makes sense to explicitly spell out the action in the same
|
||||
The 'child_send1.txt' file gets generated during the test run, so it makes sense to explicitly spell out the action in the same
|
||||
TestSTTYBeforeAndAfter.py file to do the cleanup instead of artificially adding it as part of the default cleanup action which serves to
|
||||
cleanup those intermediate and a.out files.
|
||||
|
||||
|
|
|
|||
|
|
@ -715,7 +715,7 @@ something you have to deal with on your own.
|
|||
``options`` Python summary formatters can optionally define this
|
||||
third argument, which is an object of type ``lldb.SBTypeSummaryOptions``,
|
||||
allowing for a few customizations of the result. The decision to
|
||||
adopt or not this third argument - and the meaning of options
|
||||
adopt or not this third argument - and the meaning of options
|
||||
thereof - is up to the individual formatter's writer.
|
||||
|
||||
Other than interactively typing a Python script there are two other ways for
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ Concepts
|
|||
|
||||
**Layer:** The representation of trace data between passes. For Intel PT there are two types of layers:
|
||||
|
||||
**Instruction Layer:** Composed of the load addresses of the instructions in the trace. In an effort to save space,
|
||||
metadata is only stored for instructions that are of interest, not every instruction in the trace. HTR contains a
|
||||
**Instruction Layer:** Composed of the load addresses of the instructions in the trace. In an effort to save space,
|
||||
metadata is only stored for instructions that are of interest, not every instruction in the trace. HTR contains a
|
||||
single instruction layer.
|
||||
|
||||
**Block Layer:** Composed of blocks - a block in *layer n* refers to a sequence of blocks in *layer n - 1*. A block in
|
||||
*layer 1* refers to a sequence of instructions in *layer 0* (the instruction layer). Metadata is stored for each block in
|
||||
**Block Layer:** Composed of blocks - a block in *layer n* refers to a sequence of blocks in *layer n - 1*. A block in
|
||||
*layer 1* refers to a sequence of instructions in *layer 0* (the instruction layer). Metadata is stored for each block in
|
||||
a block layer. HTR contains one or more block layers.
|
||||
|
||||
**Pass:** A transformation applied to a *layer* that generates a new *layer* that is a more summarized, consolidated representation of the trace data.
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ well together.
|
|||
|
||||
This document contains information necessary to successfully implement this
|
||||
interface, use it, and to test both sides. It also explains some of the finer
|
||||
points about what exactly results mean.
|
||||
points about what exactly results mean.
|
||||
|
||||
``AliasAnalysis`` Class Overview
|
||||
================================
|
||||
|
|
@ -70,7 +70,7 @@ possible) C code:
|
|||
|
||||
int i;
|
||||
char C[2];
|
||||
char A[10];
|
||||
char A[10];
|
||||
/* ... */
|
||||
for (i = 0; i != 10; ++i) {
|
||||
C[0] = A[i]; /* One byte store */
|
||||
|
|
@ -87,7 +87,7 @@ contrast, the following code:
|
|||
|
||||
int i;
|
||||
char C[2];
|
||||
char A[10];
|
||||
char A[10];
|
||||
/* ... */
|
||||
for (i = 0; i != 10; ++i) {
|
||||
((short*)C)[0] = A[i]; /* Two byte store! */
|
||||
|
|
@ -103,7 +103,7 @@ accesses alias.
|
|||
|
||||
The ``alias`` method
|
||||
--------------------
|
||||
|
||||
|
||||
The ``alias`` method is the primary interface used to determine whether or not
|
||||
two memory objects alias each other. It takes two memory objects as input and
|
||||
returns MustAlias, PartialAlias, MayAlias, or NoAlias as appropriate.
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ A "little endian" layout has the least significant byte first (lowest in memory
|
|||
|
||||
.. figure:: ARM-BE-ldr.png
|
||||
:align: right
|
||||
|
||||
|
||||
Big endian vector load using ``LDR``.
|
||||
|
||||
|
||||
|
|
@ -82,7 +82,7 @@ Because ``LD1 == LDR + REV`` and similarly ``LDR == LD1 + REV`` (on a big endian
|
|||
.. container:: clearer
|
||||
|
||||
Note that throughout this section we only mention loads. Stores have exactly the same problems as their associated loads, so have been skipped for brevity.
|
||||
|
||||
|
||||
|
||||
Considerations
|
||||
==============
|
||||
|
|
@ -156,7 +156,7 @@ Implementation
|
|||
|
||||
There are 3 parts to the implementation:
|
||||
|
||||
1. Predicate ``LDR`` and ``STR`` instructions so that they are never allowed to be selected to generate vector loads and stores. The exception is one-lane vectors [1]_ - these by definition cannot have lane ordering problems so are fine to use ``LDR``/``STR``.
|
||||
1. Predicate ``LDR`` and ``STR`` instructions so that they are never allowed to be selected to generate vector loads and stores. The exception is one-lane vectors [1]_ - these by definition cannot have lane ordering problems so are fine to use ``LDR``/``STR``.
|
||||
|
||||
2. Create code generation patterns for bitconverts that create ``REV`` instructions.
|
||||
|
||||
|
|
@ -191,7 +191,7 @@ For the previous example, this would be::
|
|||
|
||||
LD1 v0.4s, [x]
|
||||
|
||||
REV64 v0.4s, v0.4s // There is no REV128 instruction, so it must be synthesizedcd
|
||||
REV64 v0.4s, v0.4s // There is no REV128 instruction, so it must be synthesizedcd
|
||||
EXT v0.16b, v0.16b, v0.16b, #8 // with a REV64 then an EXT to swap the two 64-bit elements.
|
||||
|
||||
REV64 v0.2d, v0.2d
|
||||
|
|
@ -202,4 +202,3 @@ For the previous example, this would be::
|
|||
It turns out that these ``REV`` pairs can, in almost all cases, be squashed together into a single ``REV``. For the example above, a ``REV128 4s`` + ``REV128 2d`` is actually a ``REV64 4s``, as shown in the figure on the right.
|
||||
|
||||
.. [1] One lane vectors may seem useless as a concept but they serve to distinguish between values held in general purpose registers and values held in NEON/VFP registers. For example, an ``i64`` would live in an ``x`` register, but ``<1 x i64>`` would live in a ``d`` register.
|
||||
|
||||
|
|
|
|||
|
|
@ -840,7 +840,7 @@ function. The operand fields are:
|
|||
plus 1.
|
||||
|
||||
* *preemptionspecifier*: If present, an encoding of the :ref:`runtime preemption specifier<bcpreemptionspecifier>` of this function.
|
||||
|
||||
|
||||
MODULE_CODE_ALIAS Record
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ that are already documented include: *LLVM_TARGETS_TO_BUILD*,
|
|||
components. LLVM library components are either library names with the LLVM
|
||||
prefix removed (i.e. Support, Demangle...), LLVM target names, or special
|
||||
purpose component names. The special purpose component names are:
|
||||
|
||||
|
||||
#. ``all`` - All LLVM available component libraries
|
||||
#. ``Native`` - The LLVM target for the Native system
|
||||
#. ``AllTargetsAsmParsers`` - All the included target ASM parsers libraries
|
||||
|
|
|
|||
|
|
@ -536,8 +536,8 @@ enabled sub-projects. Nearly all of these variable names begin with
|
|||
Defaults to ON.
|
||||
|
||||
**LLVM_EXPERIMENTAL_TARGETS_TO_BUILD**:STRING
|
||||
Semicolon-separated list of experimental targets to build and linked into
|
||||
llvm. This will build the experimental target without needing it to add to the
|
||||
Semicolon-separated list of experimental targets to build and linked into
|
||||
llvm. This will build the experimental target without needing it to add to the
|
||||
list of all the targets available in the LLVM's main CMakeLists.txt.
|
||||
|
||||
**LLVM_EXTERNAL_{CLANG,LLD,POLLY}_SOURCE_DIR**:PATH
|
||||
|
|
@ -615,7 +615,7 @@ enabled sub-projects. Nearly all of these variable names begin with
|
|||
|
||||
$ D:\git> git clone https://github.com/mjansson/rpmalloc
|
||||
$ D:\llvm-project> cmake ... -DLLVM_INTEGRATED_CRT_ALLOC=D:\git\rpmalloc
|
||||
|
||||
|
||||
This flag needs to be used along with the static CRT, ie. if building the
|
||||
Release target, add -DLLVM_USE_CRT_RELEASE=MT.
|
||||
|
||||
|
|
|
|||
|
|
@ -178,10 +178,10 @@ Header Guard
|
|||
""""""""""""
|
||||
|
||||
The header file's guard should be the all-caps path that a user of this header
|
||||
would #include, using '_' instead of path separator and extension marker.
|
||||
would #include, using '_' instead of path separator and extension marker.
|
||||
For example, the header file
|
||||
``llvm/include/llvm/Analysis/Utils/Local.h`` would be ``#include``-ed as
|
||||
``#include "llvm/Analysis/Utils/Local.h"``, so its guard is
|
||||
``llvm/include/llvm/Analysis/Utils/Local.h`` would be ``#include``-ed as
|
||||
``#include "llvm/Analysis/Utils/Local.h"``, so its guard is
|
||||
``LLVM_ANALYSIS_UTILS_LOCAL_H``.
|
||||
|
||||
Class overviews
|
||||
|
|
|
|||
|
|
@ -25,32 +25,32 @@ archive files. If an SVR4 format archive is used with the :option:`r`
|
|||
(quick update) operations, the archive will be reconstructed in the format
|
||||
defined by :option:`--format`.
|
||||
|
||||
Here's where :program:`llvm-ar` departs from previous :program:`ar`
|
||||
Here's where :program:`llvm-ar` departs from previous :program:`ar`
|
||||
implementations:
|
||||
|
||||
*The following option is not supported*
|
||||
|
||||
|
||||
[f] - truncate inserted filenames
|
||||
|
||||
|
||||
*The following options are ignored for compatibility*
|
||||
|
||||
--plugin=<string> - load a plugin which adds support for other file formats
|
||||
|
||||
[l] - ignored in :program:`ar`
|
||||
|
||||
[l] - ignored in :program:`ar`
|
||||
|
||||
*Symbol Table*
|
||||
|
||||
Since :program:`llvm-ar` supports bitcode files, the symbol table it creates
|
||||
includes both native and bitcode symbols.
|
||||
|
||||
|
||||
*Deterministic Archives*
|
||||
|
||||
By default, :program:`llvm-ar` always uses zero for timestamps and UIDs/GIDs
|
||||
to write archives in a deterministic mode. This is equivalent to the
|
||||
to write archives in a deterministic mode. This is equivalent to the
|
||||
:option:`D` modifier being enabled by default. If you wish to maintain
|
||||
compatibility with other :program:`ar` implementations, you can pass the
|
||||
:option:`U` modifier to write actual timestamps and UIDs/GIDs.
|
||||
|
||||
|
||||
*Windows Paths*
|
||||
|
||||
When on Windows :program:`llvm-ar` treats the names of archived *files* in the same
|
||||
|
|
@ -62,7 +62,7 @@ OPTIONS
|
|||
|
||||
:program:`llvm-ar` operations are compatible with other :program:`ar`
|
||||
implementations. However, there are a few modifiers (:option:`L`) that are not
|
||||
found in other :program:`ar` implementations. The options for
|
||||
found in other :program:`ar` implementations. The options for
|
||||
:program:`llvm-ar` specify a single basic Operation to perform on the archive,
|
||||
a variety of Modifiers for that Operation, the name of the archive file, and an
|
||||
optional list of file names. If the *files* option is not specified, it
|
||||
|
|
@ -127,7 +127,7 @@ Operations
|
|||
they do not exist. The :option:`a`, :option:`b`, :option:`T` and :option:`u`
|
||||
modifiers apply to this operation. If no *files* are specified, the archive
|
||||
is not modified.
|
||||
|
||||
|
||||
t[v]
|
||||
.. option:: t [vO]
|
||||
|
||||
|
|
@ -139,10 +139,10 @@ t[v]
|
|||
size, and the date. With the :option:`O` modifier, display member offsets. If
|
||||
any *files* are specified, the listing is only for those files. If no *files*
|
||||
are specified, the table of contents for the whole archive is printed.
|
||||
|
||||
|
||||
.. option:: V
|
||||
|
||||
A synonym for the :option:`--version` option.
|
||||
A synonym for the :option:`--version` option.
|
||||
|
||||
.. option:: x [oP]
|
||||
|
||||
|
|
@ -174,7 +174,7 @@ section to determine which modifiers are applicable to which operations.
|
|||
|
||||
.. option:: i
|
||||
|
||||
A synonym for the :option:`b` option.
|
||||
A synonym for the :option:`b` option.
|
||||
|
||||
.. option:: L
|
||||
|
||||
|
|
@ -188,13 +188,13 @@ section to determine which modifiers are applicable to which operations.
|
|||
selects the instance of the given name, with "1" indicating the first
|
||||
instance. If :option:`N` is not specified the first member of that name will
|
||||
be selected. If *count* is not supplied, the operation fails.*count* cannot be
|
||||
|
||||
|
||||
.. option:: o
|
||||
|
||||
When extracting files, use the modification times of any *files* as they
|
||||
appear in the ``archive``. By default *files* extracted from the archive
|
||||
use the time of extraction.
|
||||
|
||||
|
||||
.. option:: O
|
||||
|
||||
Display member offsets inside the archive.
|
||||
|
|
@ -248,12 +248,12 @@ The modifiers below may be applied to any operation.
|
|||
This modifier is the opposite of the :option:`s` modifier. It instructs
|
||||
:program:`llvm-ar` to not build the symbol table. If both :option:`s` and
|
||||
:option:`S` are used, the last modifier to occur in the options will prevail.
|
||||
|
||||
|
||||
.. option:: u
|
||||
|
||||
Only update ``archive`` members with *files* that have more recent
|
||||
timestamps.
|
||||
|
||||
|
||||
.. option:: U
|
||||
|
||||
Use actual timestamps and UIDs/GIDs.
|
||||
|
|
@ -277,7 +277,7 @@ Other
|
|||
stream. No other options are compatible with this option.
|
||||
|
||||
.. option:: --rsp-quoting=<type>
|
||||
This option selects the quoting style ``<type>`` for response files, either
|
||||
This option selects the quoting style ``<type>`` for response files, either
|
||||
``posix`` or ``windows``. The default when on Windows is ``windows``, otherwise the
|
||||
default is ``posix``.
|
||||
|
||||
|
|
@ -296,11 +296,11 @@ MRI SCRIPTS
|
|||
supported by archivers following in the ar tradition. An MRI script contains a
|
||||
sequence of commands to be executed by the archiver. The :option:`-M` option
|
||||
allows for an MRI script to be passed to :program:`llvm-ar` through the
|
||||
standard input stream.
|
||||
|
||||
standard input stream.
|
||||
|
||||
Note that :program:`llvm-ar` has known limitations regarding the use of MRI
|
||||
scripts:
|
||||
|
||||
|
||||
* Each script can only create one archive.
|
||||
* Existing archives can not be modified.
|
||||
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ Code regions can have names. For example:
|
|||
|
||||
# LLVM-MCA-BEGIN A simple example
|
||||
add %eax, %eax
|
||||
# LLVM-MCA-END
|
||||
# LLVM-MCA-END
|
||||
|
||||
The code from the example above defines a region named "A simple example" with a
|
||||
single instruction in it. Note how the region name doesn't have to be repeated
|
||||
|
|
@ -627,26 +627,26 @@ Below is an example of ``-bottleneck-analysis`` output generated by
|
|||
|
||||
|
||||
Cycles with backend pressure increase [ 48.07% ]
|
||||
Throughput Bottlenecks:
|
||||
Throughput Bottlenecks:
|
||||
Resource Pressure [ 47.77% ]
|
||||
- JFPA [ 47.77% ]
|
||||
- JFPU0 [ 47.77% ]
|
||||
Data Dependencies: [ 0.30% ]
|
||||
- Register Dependencies [ 0.30% ]
|
||||
- Memory Dependencies [ 0.00% ]
|
||||
|
||||
|
||||
Critical sequence based on the simulation:
|
||||
|
||||
|
||||
Instruction Dependency Information
|
||||
+----< 2. vhaddps %xmm3, %xmm3, %xmm4
|
||||
|
|
||||
| < loop carried >
|
||||
| < loop carried >
|
||||
|
|
||||
| 0. vmulps %xmm0, %xmm1, %xmm2
|
||||
+----> 1. vhaddps %xmm2, %xmm2, %xmm3 ## RESOURCE interference: JFPA [ probability: 74% ]
|
||||
+----> 2. vhaddps %xmm3, %xmm3, %xmm4 ## REGISTER dependency: %xmm3
|
||||
|
|
||||
| < loop carried >
|
||||
| < loop carried >
|
||||
|
|
||||
+----> 1. vhaddps %xmm2, %xmm2, %xmm3 ## RESOURCE interference: JFPA [ probability: 74% ]
|
||||
|
||||
|
|
|
|||
|
|
@ -383,7 +383,7 @@ them.
|
|||
represents a single symbol, with leading and trailing whitespace ignored, as is
|
||||
anything following a '#'. Can be specified multiple times to read names from
|
||||
multiple files.
|
||||
|
||||
|
||||
.. option:: --new-symbol-visibility <visibility>
|
||||
|
||||
Specify the visibility of the symbols automatically created when using binary
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ combined with other commands:
|
|||
.. option:: -D, --disassemble-all
|
||||
|
||||
Disassemble all sections found in the input files.
|
||||
|
||||
|
||||
.. option:: --disassemble-symbols=<symbol1[,symbol2,...]>
|
||||
|
||||
Disassemble only the specified symbols. Takes demangled symbol names when
|
||||
|
|
@ -92,7 +92,7 @@ combined with other commands:
|
|||
.. option:: -u, --unwind-info
|
||||
|
||||
Display the unwind info of the input(s).
|
||||
|
||||
|
||||
This operation is only currently supported for COFF and Mach-O object files.
|
||||
|
||||
.. option:: -v, --version
|
||||
|
|
|
|||
|
|
@ -94,13 +94,13 @@ OPTIONS
|
|||
.. option:: -sample
|
||||
|
||||
Specify that the input profile is a sample-based profile.
|
||||
|
||||
|
||||
The format of the generated file can be generated in one of three ways:
|
||||
|
||||
.. option:: -binary (default)
|
||||
|
||||
Emit the profile using a binary encoding. For instrumentation-based profile
|
||||
the output format is the indexed binary format.
|
||||
the output format is the indexed binary format.
|
||||
|
||||
.. option:: -extbinary
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ OPTIONS
|
|||
.. option:: --demangle, -C
|
||||
|
||||
Display demangled symbol names in the output.
|
||||
|
||||
|
||||
.. option:: --dependent-libraries
|
||||
|
||||
Display the dependent libraries section.
|
||||
|
|
@ -118,7 +118,7 @@ OPTIONS
|
|||
.. option:: --needed-libs
|
||||
|
||||
Display the needed libraries.
|
||||
|
||||
|
||||
.. option:: --no-demangle
|
||||
|
||||
Do not display demangled symbol names in the output. On by default.
|
||||
|
|
@ -196,11 +196,11 @@ OPTIONS
|
|||
.. option:: --version-info, -V
|
||||
|
||||
Display version sections.
|
||||
|
||||
|
||||
.. option:: --wide, -W
|
||||
|
||||
Ignored for GNU readelf compatibility. The output is already similar to when using -W with GNU readelf.
|
||||
|
||||
|
||||
.. option:: @<FILE>
|
||||
|
||||
Read command-line options from response file `<FILE>`.
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ file formats.
|
|||
section index or section name.
|
||||
|
||||
.. option:: --string-table
|
||||
|
||||
|
||||
Display contents of the string table.
|
||||
|
||||
.. option:: --symbols, --syms, -s
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ OPTIONS
|
|||
|
||||
Print just the file's name without any directories, instead of the
|
||||
absolute path.
|
||||
|
||||
|
||||
.. _llvm-symbolizer-opt-C:
|
||||
|
||||
.. option:: --demangle, -C
|
||||
|
|
@ -241,7 +241,7 @@ OPTIONS
|
|||
Specify the preferred output style. Defaults to ``LLVM``. When the output
|
||||
style is set to ``GNU``, the tool follows the style of GNU's **addr2line**.
|
||||
The differences from the ``LLVM`` style are:
|
||||
|
||||
|
||||
* Does not print the column of a source code location.
|
||||
|
||||
* Does not add an empty line after the report for an address.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ Coroutines in LLVM
|
|||
:depth: 3
|
||||
|
||||
.. warning::
|
||||
This is a work in progress. Compatibility across LLVM releases is not
|
||||
This is a work in progress. Compatibility across LLVM releases is not
|
||||
guaranteed.
|
||||
|
||||
Introduction
|
||||
|
|
@ -15,13 +15,13 @@ Introduction
|
|||
|
||||
.. _coroutine handle:
|
||||
|
||||
LLVM coroutines are functions that have one or more `suspend points`_.
|
||||
LLVM coroutines are functions that have one or more `suspend points`_.
|
||||
When a suspend point is reached, the execution of a coroutine is suspended and
|
||||
control is returned back to its caller. A suspended coroutine can be resumed
|
||||
to continue execution from the last suspend point or it can be destroyed.
|
||||
control is returned back to its caller. A suspended coroutine can be resumed
|
||||
to continue execution from the last suspend point or it can be destroyed.
|
||||
|
||||
In the following example, we call function `f` (which may or may not be a
|
||||
coroutine itself) that returns a handle to a suspended coroutine
|
||||
In the following example, we call function `f` (which may or may not be a
|
||||
coroutine itself) that returns a handle to a suspended coroutine
|
||||
(**coroutine handle**) that is used by `main` to resume the coroutine twice and
|
||||
then destroy it:
|
||||
|
||||
|
|
@ -38,8 +38,8 @@ then destroy it:
|
|||
|
||||
.. _coroutine frame:
|
||||
|
||||
In addition to the function stack frame which exists when a coroutine is
|
||||
executing, there is an additional region of storage that contains objects that
|
||||
In addition to the function stack frame which exists when a coroutine is
|
||||
executing, there is an additional region of storage that contains objects that
|
||||
keep the coroutine state when a coroutine is suspended. This region of storage
|
||||
is called the **coroutine frame**. It is created when a coroutine is called
|
||||
and destroyed when a coroutine either runs to completion or is destroyed
|
||||
|
|
@ -273,12 +273,12 @@ by the following pseudo-code.
|
|||
for(;;) {
|
||||
print(n++);
|
||||
<suspend> // returns a coroutine handle on first suspend
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
This coroutine calls some function `print` with value `n` as an argument and
|
||||
suspends execution. Every time this coroutine resumes, it calls `print` again with an argument one bigger than the last time. This coroutine never completes by itself and must be destroyed explicitly. If we use this coroutine with
|
||||
a `main` shown in the previous section. It will call `print` with values 4, 5
|
||||
suspends execution. Every time this coroutine resumes, it calls `print` again with an argument one bigger than the last time. This coroutine never completes by itself and must be destroyed explicitly. If we use this coroutine with
|
||||
a `main` shown in the previous section. It will call `print` with values 4, 5
|
||||
and 6 after which the coroutine will be destroyed.
|
||||
|
||||
The LLVM IR for this coroutine looks like this:
|
||||
|
|
@ -309,28 +309,28 @@ The LLVM IR for this coroutine looks like this:
|
|||
}
|
||||
|
||||
The `entry` block establishes the coroutine frame. The `coro.size`_ intrinsic is
|
||||
lowered to a constant representing the size required for the coroutine frame.
|
||||
The `coro.begin`_ intrinsic initializes the coroutine frame and returns the
|
||||
coroutine handle. The second parameter of `coro.begin` is given a block of memory
|
||||
lowered to a constant representing the size required for the coroutine frame.
|
||||
The `coro.begin`_ intrinsic initializes the coroutine frame and returns the
|
||||
coroutine handle. The second parameter of `coro.begin` is given a block of memory
|
||||
to be used if the coroutine frame needs to be allocated dynamically.
|
||||
The `coro.id`_ intrinsic serves as coroutine identity useful in cases when the
|
||||
`coro.begin`_ intrinsic get duplicated by optimization passes such as
|
||||
`coro.begin`_ intrinsic get duplicated by optimization passes such as
|
||||
jump-threading.
|
||||
|
||||
The `cleanup` block destroys the coroutine frame. The `coro.free`_ intrinsic,
|
||||
The `cleanup` block destroys the coroutine frame. The `coro.free`_ intrinsic,
|
||||
given the coroutine handle, returns a pointer of the memory block to be freed or
|
||||
`null` if the coroutine frame was not allocated dynamically. The `cleanup`
|
||||
`null` if the coroutine frame was not allocated dynamically. The `cleanup`
|
||||
block is entered when coroutine runs to completion by itself or destroyed via
|
||||
call to the `coro.destroy`_ intrinsic.
|
||||
|
||||
The `suspend` block contains code to be executed when coroutine runs to
|
||||
completion or suspended. The `coro.end`_ intrinsic marks the point where
|
||||
a coroutine needs to return control back to the caller if it is not an initial
|
||||
invocation of the coroutine.
|
||||
The `suspend` block contains code to be executed when coroutine runs to
|
||||
completion or suspended. The `coro.end`_ intrinsic marks the point where
|
||||
a coroutine needs to return control back to the caller if it is not an initial
|
||||
invocation of the coroutine.
|
||||
|
||||
The `loop` blocks represents the body of the coroutine. The `coro.suspend`_
|
||||
intrinsic in combination with the following switch indicates what happens to
|
||||
control flow when a coroutine is suspended (default case), resumed (case 0) or
|
||||
The `loop` blocks represents the body of the coroutine. The `coro.suspend`_
|
||||
intrinsic in combination with the following switch indicates what happens to
|
||||
control flow when a coroutine is suspended (default case), resumed (case 0) or
|
||||
destroyed (case 1).
|
||||
|
||||
Coroutine Transformation
|
||||
|
|
@ -338,24 +338,24 @@ Coroutine Transformation
|
|||
|
||||
One of the steps of coroutine lowering is building the coroutine frame. The
|
||||
def-use chains are analyzed to determine which objects need be kept alive across
|
||||
suspend points. In the coroutine shown in the previous section, use of virtual register
|
||||
`%inc` is separated from the definition by a suspend point, therefore, it
|
||||
cannot reside on the stack frame since the latter goes away once the coroutine
|
||||
is suspended and control is returned back to the caller. An i32 slot is
|
||||
suspend points. In the coroutine shown in the previous section, use of virtual register
|
||||
`%inc` is separated from the definition by a suspend point, therefore, it
|
||||
cannot reside on the stack frame since the latter goes away once the coroutine
|
||||
is suspended and control is returned back to the caller. An i32 slot is
|
||||
allocated in the coroutine frame and `%inc` is spilled and reloaded from that
|
||||
slot as needed.
|
||||
|
||||
We also store addresses of the resume and destroy functions so that the
|
||||
We also store addresses of the resume and destroy functions so that the
|
||||
`coro.resume` and `coro.destroy` intrinsics can resume and destroy the coroutine
|
||||
when its identity cannot be determined statically at compile time. For our
|
||||
when its identity cannot be determined statically at compile time. For our
|
||||
example, the coroutine frame will be:
|
||||
|
||||
.. code-block:: llvm
|
||||
|
||||
%f.frame = type { void (%f.frame*)*, void (%f.frame*)*, i32 }
|
||||
|
||||
After resume and destroy parts are outlined, function `f` will contain only the
|
||||
code responsible for creation and initialization of the coroutine frame and
|
||||
After resume and destroy parts are outlined, function `f` will contain only the
|
||||
code responsible for creation and initialization of the coroutine frame and
|
||||
execution of the coroutine until a suspend point is reached:
|
||||
|
||||
.. code-block:: llvm
|
||||
|
|
@ -370,12 +370,12 @@ execution of the coroutine until a suspend point is reached:
|
|||
store void (%f.frame*)* @f.resume, void (%f.frame*)** %1
|
||||
%2 = getelementptr %f.frame, %f.frame* %frame, i32 0, i32 1
|
||||
store void (%f.frame*)* @f.destroy, void (%f.frame*)** %2
|
||||
|
||||
|
||||
%inc = add nsw i32 %n, 1
|
||||
%inc.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 2
|
||||
store i32 %inc, i32* %inc.spill.addr
|
||||
call void @print(i32 %n)
|
||||
|
||||
|
||||
ret i8* %frame
|
||||
}
|
||||
|
||||
|
|
@ -406,16 +406,16 @@ Whereas function `f.destroy` will contain the cleanup code for the coroutine:
|
|||
|
||||
Avoiding Heap Allocations
|
||||
-------------------------
|
||||
|
||||
A particular coroutine usage pattern, which is illustrated by the `main`
|
||||
function in the overview section, where a coroutine is created, manipulated and
|
||||
|
||||
A particular coroutine usage pattern, which is illustrated by the `main`
|
||||
function in the overview section, where a coroutine is created, manipulated and
|
||||
destroyed by the same calling function, is common for coroutines implementing
|
||||
RAII idiom and is suitable for allocation elision optimization which avoid
|
||||
dynamic allocation by storing the coroutine frame as a static `alloca` in its
|
||||
RAII idiom and is suitable for allocation elision optimization which avoid
|
||||
dynamic allocation by storing the coroutine frame as a static `alloca` in its
|
||||
caller.
|
||||
|
||||
In the entry block, we will call `coro.alloc`_ intrinsic that will return `true`
|
||||
when dynamic allocation is required, and `false` if dynamic allocation is
|
||||
when dynamic allocation is required, and `false` if dynamic allocation is
|
||||
elided.
|
||||
|
||||
.. code-block:: llvm
|
||||
|
|
@ -496,9 +496,9 @@ as the code in the previous section):
|
|||
switch i8 %3, label %suspend [i8 0, label %loop
|
||||
i8 1, label %cleanup]
|
||||
|
||||
In this case, the coroutine frame would include a suspend index that will
|
||||
indicate at which suspend point the coroutine needs to resume. The resume
|
||||
function will use an index to jump to an appropriate basic block and will look
|
||||
In this case, the coroutine frame would include a suspend index that will
|
||||
indicate at which suspend point the coroutine needs to resume. The resume
|
||||
function will use an index to jump to an appropriate basic block and will look
|
||||
as follows:
|
||||
|
||||
.. code-block:: llvm
|
||||
|
|
@ -528,25 +528,25 @@ as follows:
|
|||
ret void
|
||||
}
|
||||
|
||||
If different cleanup code needs to get executed for different suspend points,
|
||||
If different cleanup code needs to get executed for different suspend points,
|
||||
a similar switch will be in the `f.destroy` function.
|
||||
|
||||
.. note ::
|
||||
|
||||
Using suspend index in a coroutine state and having a switch in `f.resume` and
|
||||
`f.destroy` is one of the possible implementation strategies. We explored
|
||||
`f.destroy` is one of the possible implementation strategies. We explored
|
||||
another option where a distinct `f.resume1`, `f.resume2`, etc. are created for
|
||||
every suspend point, and instead of storing an index, the resume and destroy
|
||||
every suspend point, and instead of storing an index, the resume and destroy
|
||||
function pointers are updated at every suspend. Early testing showed that the
|
||||
current approach is easier on the optimizer than the latter so it is a
|
||||
current approach is easier on the optimizer than the latter so it is a
|
||||
lowering strategy implemented at the moment.
|
||||
|
||||
Distinct Save and Suspend
|
||||
-------------------------
|
||||
|
||||
In the previous example, setting a resume index (or some other state change that
|
||||
In the previous example, setting a resume index (or some other state change that
|
||||
needs to happen to prepare a coroutine for resumption) happens at the same time as
|
||||
a suspension of a coroutine. However, in certain cases, it is necessary to control
|
||||
a suspension of a coroutine. However, in certain cases, it is necessary to control
|
||||
when coroutine is prepared for resumption and when it is suspended.
|
||||
|
||||
In the following example, a coroutine represents some activity that is driven
|
||||
|
|
@ -571,10 +571,10 @@ operation is finished.
|
|||
}
|
||||
}
|
||||
|
||||
In this case, coroutine should be ready for resumption prior to a call to
|
||||
In this case, coroutine should be ready for resumption prior to a call to
|
||||
`async_op1` and `async_op2`. The `coro.save`_ intrinsic is used to indicate a
|
||||
point when coroutine should be ready for resumption (namely, when a resume index
|
||||
should be stored in the coroutine frame, so that it can be resumed at the
|
||||
should be stored in the coroutine frame, so that it can be resumed at the
|
||||
correct resume point):
|
||||
|
||||
.. code-block:: llvm
|
||||
|
|
@ -599,7 +599,7 @@ Coroutine Promise
|
|||
|
||||
A coroutine author or a frontend may designate a distinguished `alloca` that can
|
||||
be used to communicate with the coroutine. This distinguished alloca is called
|
||||
**coroutine promise** and is provided as the second parameter to the
|
||||
**coroutine promise** and is provided as the second parameter to the
|
||||
`coro.id`_ intrinsic.
|
||||
|
||||
The following coroutine designates a 32 bit integer `promise` and uses it to
|
||||
|
|
@ -685,17 +685,17 @@ Such a suspend point has two properties:
|
|||
* it is possible to check whether a suspended coroutine is at the final suspend
|
||||
point via `coro.done`_ intrinsic;
|
||||
|
||||
* a resumption of a coroutine stopped at the final suspend point leads to
|
||||
* a resumption of a coroutine stopped at the final suspend point leads to
|
||||
undefined behavior. The only possible action for a coroutine at a final
|
||||
suspend point is destroying it via `coro.destroy`_ intrinsic.
|
||||
|
||||
From the user perspective, the final suspend point represents an idea of a
|
||||
From the user perspective, the final suspend point represents an idea of a
|
||||
coroutine reaching the end. From the compiler perspective, it is an optimization
|
||||
opportunity for reducing number of resume points (and therefore switch cases) in
|
||||
the resume function.
|
||||
|
||||
The following is an example of a function that keeps resuming the coroutine
|
||||
until the final suspend point is reached after which point the coroutine is
|
||||
until the final suspend point is reached after which point the coroutine is
|
||||
destroyed:
|
||||
|
||||
.. code-block:: llvm
|
||||
|
|
@ -729,7 +729,7 @@ looks like this:
|
|||
.. code-block:: c
|
||||
|
||||
void* coroutine(int n) {
|
||||
int current_value;
|
||||
int current_value;
|
||||
<designate current_value to be coroutine promise>
|
||||
<SUSPEND> // injected suspend point, so that the coroutine starts suspended
|
||||
for (int i = 0; i < n; ++i) {
|
||||
|
|
@ -785,8 +785,8 @@ The argument is a coroutine handle to a suspended coroutine.
|
|||
Semantics:
|
||||
""""""""""
|
||||
|
||||
When possible, the `coro.destroy` intrinsic is replaced with a direct call to
|
||||
the coroutine destroy function. Otherwise it is replaced with an indirect call
|
||||
When possible, the `coro.destroy` intrinsic is replaced with a direct call to
|
||||
the coroutine destroy function. Otherwise it is replaced with an indirect call
|
||||
based on the function pointer for the destroy function stored in the coroutine
|
||||
frame. Destroying a coroutine that is not suspended leads to undefined behavior.
|
||||
|
||||
|
|
@ -813,8 +813,8 @@ Semantics:
|
|||
""""""""""
|
||||
|
||||
When possible, the `coro.resume` intrinsic is replaced with a direct call to the
|
||||
coroutine resume function. Otherwise it is replaced with an indirect call based
|
||||
on the function pointer for the resume function stored in the coroutine frame.
|
||||
coroutine resume function. Otherwise it is replaced with an indirect call based
|
||||
on the function pointer for the resume function stored in the coroutine frame.
|
||||
Resuming a coroutine that is not suspended leads to undefined behavior.
|
||||
|
||||
.. _coro.done:
|
||||
|
|
@ -840,7 +840,7 @@ The argument is a handle to a suspended coroutine.
|
|||
Semantics:
|
||||
""""""""""
|
||||
|
||||
Using this intrinsic on a coroutine that does not have a `final suspend`_ point
|
||||
Using this intrinsic on a coroutine that does not have a `final suspend`_ point
|
||||
or on a coroutine that is not suspended leads to undefined behavior.
|
||||
|
||||
.. _coro.promise:
|
||||
|
|
@ -855,25 +855,25 @@ or on a coroutine that is not suspended leads to undefined behavior.
|
|||
Overview:
|
||||
"""""""""
|
||||
|
||||
The '``llvm.coro.promise``' intrinsic obtains a pointer to a
|
||||
The '``llvm.coro.promise``' intrinsic obtains a pointer to a
|
||||
`coroutine promise`_ given a switched-resume coroutine handle and vice versa.
|
||||
|
||||
Arguments:
|
||||
""""""""""
|
||||
|
||||
The first argument is a handle to a coroutine if `from` is false. Otherwise,
|
||||
The first argument is a handle to a coroutine if `from` is false. Otherwise,
|
||||
it is a pointer to a coroutine promise.
|
||||
|
||||
The second argument is an alignment requirements of the promise.
|
||||
If a frontend designated `%promise = alloca i32` as a promise, the alignment
|
||||
argument to `coro.promise` should be the alignment of `i32` on the target
|
||||
platform. If a frontend designated `%promise = alloca i32, align 16` as a
|
||||
The second argument is an alignment requirements of the promise.
|
||||
If a frontend designated `%promise = alloca i32` as a promise, the alignment
|
||||
argument to `coro.promise` should be the alignment of `i32` on the target
|
||||
platform. If a frontend designated `%promise = alloca i32, align 16` as a
|
||||
promise, the alignment argument should be 16.
|
||||
This argument only accepts constants.
|
||||
|
||||
The third argument is a boolean indicating a direction of the transformation.
|
||||
If `from` is true, the intrinsic returns a coroutine handle given a pointer
|
||||
to a promise. If `from` is false, the intrinsics return a pointer to a promise
|
||||
If `from` is true, the intrinsic returns a coroutine handle given a pointer
|
||||
to a promise. If `from` is false, the intrinsics return a pointer to a promise
|
||||
from a coroutine handle. This argument only accepts constants.
|
||||
|
||||
Semantics:
|
||||
|
|
@ -907,7 +907,7 @@ Example:
|
|||
entry:
|
||||
%hdl = call i8* @f(i32 4) ; starts the coroutine and returns its handle
|
||||
%promise.addr.raw = call i8* @llvm.coro.promise(i8* %hdl, i32 4, i1 false)
|
||||
%promise.addr = bitcast i8* %promise.addr.raw to i32*
|
||||
%promise.addr = bitcast i8* %promise.addr.raw to i32*
|
||||
%val = load i32, i32* %promise.addr ; load a value from the promise
|
||||
call void @print(i32 %val)
|
||||
call void @llvm.coro.destroy(i8* %hdl)
|
||||
|
|
@ -946,7 +946,7 @@ Semantics:
|
|||
""""""""""
|
||||
|
||||
The `coro.size` intrinsic is lowered to a constant representing the size of
|
||||
the coroutine frame.
|
||||
the coroutine frame.
|
||||
|
||||
.. _coro.begin:
|
||||
|
||||
|
|
@ -964,7 +964,7 @@ The '``llvm.coro.begin``' intrinsic returns an address of the coroutine frame.
|
|||
Arguments:
|
||||
""""""""""
|
||||
|
||||
The first argument is a token returned by a call to '``llvm.coro.id``'
|
||||
The first argument is a token returned by a call to '``llvm.coro.id``'
|
||||
identifying the coroutine.
|
||||
|
||||
The second argument is a pointer to a block of memory where coroutine frame
|
||||
|
|
@ -975,9 +975,9 @@ Semantics:
|
|||
""""""""""
|
||||
|
||||
Depending on the alignment requirements of the objects in the coroutine frame
|
||||
and/or on the codegen compactness reasons the pointer returned from `coro.begin`
|
||||
may be at offset to the `%mem` argument. (This could be beneficial if
|
||||
instructions that express relative access to data can be more compactly encoded
|
||||
and/or on the codegen compactness reasons the pointer returned from `coro.begin`
|
||||
may be at offset to the `%mem` argument. (This could be beneficial if
|
||||
instructions that express relative access to data can be more compactly encoded
|
||||
with small positive and negative offsets).
|
||||
|
||||
A frontend should emit exactly one `coro.begin` intrinsic per coroutine.
|
||||
|
|
@ -993,7 +993,7 @@ A frontend should emit exactly one `coro.begin` intrinsic per coroutine.
|
|||
Overview:
|
||||
"""""""""
|
||||
|
||||
The '``llvm.coro.free``' intrinsic returns a pointer to a block of memory where
|
||||
The '``llvm.coro.free``' intrinsic returns a pointer to a block of memory where
|
||||
coroutine frame is stored or `null` if this instance of a coroutine did not use
|
||||
dynamically allocated memory for its coroutine frame. This intrinsic is not
|
||||
supported for returned-continuation coroutines.
|
||||
|
|
@ -1001,7 +1001,7 @@ supported for returned-continuation coroutines.
|
|||
Arguments:
|
||||
""""""""""
|
||||
|
||||
The first argument is a token returned by a call to '``llvm.coro.id``'
|
||||
The first argument is a token returned by a call to '``llvm.coro.id``'
|
||||
identifying the coroutine.
|
||||
|
||||
The second argument is a pointer to the coroutine frame. This should be the same
|
||||
|
|
@ -1050,7 +1050,7 @@ This is not supported for returned-continuation coroutines.
|
|||
Arguments:
|
||||
""""""""""
|
||||
|
||||
The first argument is a token returned by a call to '``llvm.coro.id``'
|
||||
The first argument is a token returned by a call to '``llvm.coro.id``'
|
||||
identifying the coroutine.
|
||||
|
||||
Semantics:
|
||||
|
|
@ -1137,7 +1137,7 @@ coroutine frame.
|
|||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
::
|
||||
|
||||
declare token @llvm.coro.id(i32 <align>, i8* <promise>, i8* <coroaddr>,
|
||||
declare token @llvm.coro.id(i32 <align>, i8* <promise>, i8* <coroaddr>,
|
||||
i8* <fnaddrs>)
|
||||
|
||||
Overview:
|
||||
|
|
@ -1149,8 +1149,8 @@ switched-resume coroutine.
|
|||
Arguments:
|
||||
""""""""""
|
||||
|
||||
The first argument provides information on the alignment of the memory returned
|
||||
by the allocation function and given to `coro.begin` by the first argument. If
|
||||
The first argument provides information on the alignment of the memory returned
|
||||
by the allocation function and given to `coro.begin` by the first argument. If
|
||||
this argument is 0, the memory is assumed to be aligned to 2 * sizeof(i8*).
|
||||
This argument only accepts constants.
|
||||
|
||||
|
|
@ -1158,10 +1158,10 @@ The second argument, if not `null`, designates a particular alloca instruction
|
|||
to be a `coroutine promise`_.
|
||||
|
||||
The third argument is `null` coming out of the frontend. The CoroEarly pass sets
|
||||
this argument to point to the function this coro.id belongs to.
|
||||
this argument to point to the function this coro.id belongs to.
|
||||
|
||||
The fourth argument is `null` before coroutine is split, and later is replaced
|
||||
to point to a private global constant array containing function pointers to
|
||||
The fourth argument is `null` before coroutine is split, and later is replaced
|
||||
to point to a private global constant array containing function pointers to
|
||||
outlined resume and destroy parts of the coroutine.
|
||||
|
||||
|
||||
|
|
@ -1298,7 +1298,7 @@ coroutine's return type.
|
|||
Overview:
|
||||
"""""""""
|
||||
|
||||
The '``llvm.coro.end``' marks the point where execution of the resume part of
|
||||
The '``llvm.coro.end``' marks the point where execution of the resume part of
|
||||
the coroutine should end and control should return to the caller.
|
||||
|
||||
|
||||
|
|
@ -1307,18 +1307,18 @@ Arguments:
|
|||
|
||||
The first argument should refer to the coroutine handle of the enclosing
|
||||
coroutine. A frontend is allowed to supply null as the first parameter, in this
|
||||
case `coro-early` pass will replace the null with an appropriate coroutine
|
||||
case `coro-early` pass will replace the null with an appropriate coroutine
|
||||
handle value.
|
||||
|
||||
The second argument should be `true` if this coro.end is in the block that is
|
||||
part of the unwind sequence leaving the coroutine body due to an exception and
|
||||
The second argument should be `true` if this coro.end is in the block that is
|
||||
part of the unwind sequence leaving the coroutine body due to an exception and
|
||||
`false` otherwise.
|
||||
|
||||
Semantics:
|
||||
""""""""""
|
||||
The purpose of this intrinsic is to allow frontends to mark the cleanup and
|
||||
other code that is only relevant during the initial invocation of the coroutine
|
||||
and should not be present in resume and destroy parts.
|
||||
and should not be present in resume and destroy parts.
|
||||
|
||||
In returned-continuation lowering, ``llvm.coro.end`` fully destroys the
|
||||
coroutine frame. If the second argument is `false`, it also returns from
|
||||
|
|
@ -1335,11 +1335,11 @@ This intrinsic is lowered when a coroutine is split into
|
|||
the start, resume and destroy parts. In the start part, it is a no-op,
|
||||
in resume and destroy parts, it is replaced with `ret void` instruction and
|
||||
the rest of the block containing `coro.end` instruction is discarded.
|
||||
In landing pads it is replaced with an appropriate instruction to unwind to
|
||||
caller. The handling of coro.end differs depending on whether the target is
|
||||
In landing pads it is replaced with an appropriate instruction to unwind to
|
||||
caller. The handling of coro.end differs depending on whether the target is
|
||||
using landingpad or WinEH exception model.
|
||||
|
||||
For landingpad based exception model, it is expected that frontend uses the
|
||||
For landingpad based exception model, it is expected that frontend uses the
|
||||
`coro.end`_ intrinsic as follows:
|
||||
|
||||
.. code-block:: llvm
|
||||
|
|
@ -1368,12 +1368,12 @@ referring to an enclosing cleanuppad as follows:
|
|||
|
||||
.. code-block:: llvm
|
||||
|
||||
ehcleanup:
|
||||
ehcleanup:
|
||||
%tok = cleanuppad within none []
|
||||
%unused = call i1 @llvm.coro.end(i8* null, i1 true) [ "funclet"(token %tok) ]
|
||||
cleanupret from %tok unwind label %RestOfTheCleanup
|
||||
|
||||
The `CoroSplit` pass, if the funclet bundle is present, will insert
|
||||
The `CoroSplit` pass, if the funclet bundle is present, will insert
|
||||
``cleanupret from %tok unwind to caller`` before
|
||||
the `coro.end`_ intrinsic and will remove the rest of the block.
|
||||
|
||||
|
|
@ -1452,7 +1452,7 @@ suspended (-1), resumed (0) or destroyed (1).
|
|||
Arguments:
|
||||
""""""""""
|
||||
|
||||
The first argument refers to a token of `coro.save` intrinsic that marks the
|
||||
The first argument refers to a token of `coro.save` intrinsic that marks the
|
||||
point when coroutine state is prepared for suspension. If `none` token is passed,
|
||||
the intrinsic behaves as if there were a `coro.save` immediately preceding
|
||||
the `coro.suspend` intrinsic.
|
||||
|
|
@ -1480,7 +1480,7 @@ Example (final suspend point):
|
|||
%s.final = call i8 @llvm.coro.suspend(token none, i1 true)
|
||||
switch i8 %s.final, label %suspend [i8 0, label %trap
|
||||
i8 1, label %cleanup]
|
||||
trap:
|
||||
trap:
|
||||
call void @llvm.trap()
|
||||
unreachable
|
||||
|
||||
|
|
@ -1490,7 +1490,7 @@ Semantics:
|
|||
If a coroutine that was suspended at the suspend point marked by this intrinsic
|
||||
is resumed via `coro.resume`_ the control will transfer to the basic block
|
||||
of the 0-case. If it is resumed via `coro.destroy`_, it will proceed to the
|
||||
basic block indicated by the 1-case. To suspend, coroutine proceed to the
|
||||
basic block indicated by the 1-case. To suspend, coroutine proceed to the
|
||||
default label.
|
||||
|
||||
If suspend intrinsic is marked as final, it can consider the `true` branch
|
||||
|
|
@ -1507,9 +1507,9 @@ unreachable and can perform optimizations that can take advantage of that fact.
|
|||
Overview:
|
||||
"""""""""
|
||||
|
||||
The '``llvm.coro.save``' marks the point where a coroutine need to update its
|
||||
state to prepare for resumption to be considered suspended (and thus eligible
|
||||
for resumption).
|
||||
The '``llvm.coro.save``' marks the point where a coroutine need to update its
|
||||
state to prepare for resumption to be considered suspended (and thus eligible
|
||||
for resumption).
|
||||
|
||||
Arguments:
|
||||
""""""""""
|
||||
|
|
@ -1520,17 +1520,17 @@ Semantics:
|
|||
""""""""""
|
||||
|
||||
Whatever coroutine state changes are required to enable resumption of
|
||||
the coroutine from the corresponding suspend point should be done at the point
|
||||
the coroutine from the corresponding suspend point should be done at the point
|
||||
of `coro.save` intrinsic.
|
||||
|
||||
Example:
|
||||
""""""""
|
||||
|
||||
Separate save and suspend points are necessary when a coroutine is used to
|
||||
Separate save and suspend points are necessary when a coroutine is used to
|
||||
represent an asynchronous control flow driven by callbacks representing
|
||||
completions of asynchronous operations.
|
||||
|
||||
In such a case, a coroutine should be ready for resumption prior to a call to
|
||||
In such a case, a coroutine should be ready for resumption prior to a call to
|
||||
`async_op` function that may trigger resumption of a coroutine from the same or
|
||||
a different thread possibly prior to `async_op` call returning control back
|
||||
to the coroutine:
|
||||
|
|
@ -1664,8 +1664,8 @@ with `i1 false` and replacing any use of the `copy` with the `original`.
|
|||
Arguments:
|
||||
""""""""""
|
||||
|
||||
The first argument points to an `alloca` storing the value of a parameter to a
|
||||
coroutine.
|
||||
The first argument points to an `alloca` storing the value of a parameter to a
|
||||
coroutine.
|
||||
|
||||
The second argument points to an `alloca` storing the value of the copy of that
|
||||
parameter.
|
||||
|
|
@ -1675,12 +1675,12 @@ Semantics:
|
|||
|
||||
The optimizer is free to always replace this intrinsic with `i1 true`.
|
||||
|
||||
The optimizer is also allowed to replace it with `i1 false` provided that the
|
||||
The optimizer is also allowed to replace it with `i1 false` provided that the
|
||||
parameter copy is only used prior to control flow reaching any of the suspend
|
||||
points. The code that would be DCE'd if the `coro.param` is replaced with
|
||||
points. The code that would be DCE'd if the `coro.param` is replaced with
|
||||
`i1 false` is not considered to be a use of the parameter copy.
|
||||
|
||||
The frontend can emit this intrinsic if its language rules allow for this
|
||||
The frontend can emit this intrinsic if its language rules allow for this
|
||||
optimization.
|
||||
|
||||
Example:
|
||||
|
|
@ -1702,7 +1702,7 @@ that has a destructor and a move constructor.
|
|||
}
|
||||
|
||||
Note that, uses of `b` is used after a suspend point and thus must be copied
|
||||
into a coroutine frame, whereas `a` does not have to, since it never used
|
||||
into a coroutine frame, whereas `a` does not have to, since it never used
|
||||
after suspend.
|
||||
|
||||
A frontend can create parameter copies for `a` and `b` as follows:
|
||||
|
|
@ -1733,24 +1733,24 @@ CoroEarly
|
|||
---------
|
||||
The pass CoroEarly lowers coroutine intrinsics that hide the details of the
|
||||
structure of the coroutine frame, but, otherwise not needed to be preserved to
|
||||
help later coroutine passes. This pass lowers `coro.frame`_, `coro.done`_,
|
||||
help later coroutine passes. This pass lowers `coro.frame`_, `coro.done`_,
|
||||
and `coro.promise`_ intrinsics.
|
||||
|
||||
.. _CoroSplit:
|
||||
|
||||
CoroSplit
|
||||
---------
|
||||
The pass CoroSplit buides coroutine frame and outlines resume and destroy parts
|
||||
The pass CoroSplit buides coroutine frame and outlines resume and destroy parts
|
||||
into separate functions.
|
||||
|
||||
CoroElide
|
||||
---------
|
||||
The pass CoroElide examines if the inlined coroutine is eligible for heap
|
||||
allocation elision optimization. If so, it replaces
|
||||
The pass CoroElide examines if the inlined coroutine is eligible for heap
|
||||
allocation elision optimization. If so, it replaces
|
||||
`coro.begin` intrinsic with an address of a coroutine frame placed on its caller
|
||||
and replaces `coro.alloc` and `coro.free` intrinsics with `false` and `null`
|
||||
respectively to remove the deallocation code.
|
||||
This pass also replaces `coro.resume` and `coro.destroy` intrinsics with direct
|
||||
respectively to remove the deallocation code.
|
||||
This pass also replaces `coro.resume` and `coro.destroy` intrinsics with direct
|
||||
calls to resume and destroy functions for a particular coroutine where possible.
|
||||
|
||||
CoroCleanup
|
||||
|
|
@ -1773,7 +1773,7 @@ Areas Requiring Attention
|
|||
allocas.
|
||||
|
||||
#. The CoroElide optimization pass relies on coroutine ramp function to be
|
||||
inlined. It would be beneficial to split the ramp function further to
|
||||
inlined. It would be beneficial to split the ramp function further to
|
||||
increase the chance that it will get inlined into its caller.
|
||||
|
||||
#. Design a convention that would make it possible to apply coroutine heap
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ code via ``lli`` inside LLDB:
|
|||
7 f *= n;
|
||||
8 return f;
|
||||
-> 9 }
|
||||
10
|
||||
10
|
||||
11 int main(int argc, char** argv)
|
||||
12 {
|
||||
(lldb) p f
|
||||
|
|
@ -156,7 +156,7 @@ code via ``lli`` inside LLDB:
|
|||
14 return -1;
|
||||
15 char firstletter = argv[1][0];
|
||||
-> 16 int result = compute_factorial(firstletter - '0');
|
||||
17
|
||||
17
|
||||
18 // Returned result is clipped at 255...
|
||||
19 return result;
|
||||
(lldb) p result
|
||||
|
|
@ -166,7 +166,7 @@ code via ``lli`` inside LLDB:
|
|||
* thread #1, name = 'lli', stop reason = step over
|
||||
frame #0: 0x00007ffff7fd0098 JIT(0x45c2cb0)`main(argc=2, argv=0x00000000046122f0) at showdebug.c:19:12
|
||||
16 int result = compute_factorial(firstletter - '0');
|
||||
17
|
||||
17
|
||||
18 // Returned result is clipped at 255...
|
||||
-> 19 return result;
|
||||
20 }
|
||||
|
|
|
|||
|
|
@ -27,12 +27,12 @@ def-use dependency between them into larger nodes that contain multiple-
|
|||
instructions.
|
||||
|
||||
As described in [1]_ the DDG uses graph abstraction to group nodes
|
||||
that are part of a strongly connected component of the graph
|
||||
that are part of a strongly connected component of the graph
|
||||
into special nodes called pi-blocks. pi-blocks represent cycles of data
|
||||
dependency that prevent reordering transformations. Since any strongly
|
||||
connected component of the graph is a maximal subgraph of all the nodes
|
||||
that form a cycle, pi-blocks are at most one level deep. In other words,
|
||||
no pi-blocks are nested inside another pi-block, resulting in a
|
||||
no pi-blocks are nested inside another pi-block, resulting in a
|
||||
hierarchical representation that is at most one level deep.
|
||||
|
||||
|
||||
|
|
@ -130,7 +130,7 @@ The current implementation of DDG differs slightly from the dependence
|
|||
graph described in [1]_ in the following ways:
|
||||
|
||||
1. The graph nodes in the paper represent three main program components, namely *assignment statements*, *for loop headers* and *while loop headers*. In this implementation, DDG nodes naturally represent LLVM IR instructions. An assignment statement in this implementation typically involves a node representing the ``store`` instruction along with a number of individual nodes computing the right-hand-side of the assignment that connect to the ``store`` node via a def-use edge. The loop header instructions are not represented as special nodes in this implementation because they have limited uses and can be easily identified, for example, through ``LoopAnalysis``.
|
||||
2. The paper describes five types of dependency edges between nodes namely *loop dependency*, *flow-*, *anti-*, *output-*, and *input-* dependencies. In this implementation *memory* edges represent the *flow-*, *anti-*, *output-*, and *input-* dependencies. However, *loop dependencies* are not made explicit, because they mainly represent association between a loop structure and the program elements inside the loop and this association is fairly obvious in LLVM IR itself.
|
||||
2. The paper describes five types of dependency edges between nodes namely *loop dependency*, *flow-*, *anti-*, *output-*, and *input-* dependencies. In this implementation *memory* edges represent the *flow-*, *anti-*, *output-*, and *input-* dependencies. However, *loop dependencies* are not made explicit, because they mainly represent association between a loop structure and the program elements inside the loop and this association is fairly obvious in LLVM IR itself.
|
||||
3. The paper describes two types of pi-blocks; *recurrences* whose bodies are SCCs and *IN* nodes whose bodies are not part of any SCC. In this implementation, pi-blocks are only created for *recurrences*. *IN* nodes remain as simple DDG nodes in the graph.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -357,7 +357,7 @@ What are the expectations around a revert?
|
|||
* It is customary to respond to the original commit email mentioning the
|
||||
revert. This serves as both a notice to the original author that their
|
||||
patch was reverted, and helps others following llvm-commits track context.
|
||||
* Ideally, you should have a publicly reproducible test case ready to share.
|
||||
* Ideally, you should have a publicly reproducible test case ready to share.
|
||||
Where possible, we encourage sharing of test cases in commit threads, or
|
||||
in PRs. We encourage the reverter to minimize the test case and to prune
|
||||
dependencies where practical. This even applies when reverting your own
|
||||
|
|
@ -648,17 +648,17 @@ Here's a `sample RFC
|
|||
Working with the CI system
|
||||
--------------------------
|
||||
|
||||
The main continuous integration (CI) tool for the LLVM project is the
|
||||
`LLVM Buildbot <https://lab.llvm.org/buildbot/>`_. It uses different *builders*
|
||||
to cover a wide variety of sub-projects and configurations. The builds are
|
||||
executed on different *workers*. Builders and workers are configured and
|
||||
The main continuous integration (CI) tool for the LLVM project is the
|
||||
`LLVM Buildbot <https://lab.llvm.org/buildbot/>`_. It uses different *builders*
|
||||
to cover a wide variety of sub-projects and configurations. The builds are
|
||||
executed on different *workers*. Builders and workers are configured and
|
||||
provided by community members.
|
||||
|
||||
The Buildbot tracks the commits on the main branch and the release branches.
|
||||
The Buildbot tracks the commits on the main branch and the release branches.
|
||||
This means that patches are built and tested after they are merged to the these
|
||||
branches (aka post-merge testing). This also means it's okay to break the build
|
||||
occasionally, as it's unreasonable to expect contributors to build and test
|
||||
their patch with every possible configuration.
|
||||
their patch with every possible configuration.
|
||||
|
||||
*If your commit broke the build:*
|
||||
|
||||
|
|
@ -669,7 +669,7 @@ their patch with every possible configuration.
|
|||
|
||||
*If someone else broke the build and this blocks your work*
|
||||
|
||||
* Comment on the code review in `Phabricator <https://reviews.llvm.org/>`_
|
||||
* Comment on the code review in `Phabricator <https://reviews.llvm.org/>`_
|
||||
(if available) or email the author, explain the problem and how this impacts
|
||||
you. Add a link to the broken build and the error message so folks can
|
||||
understand the problem.
|
||||
|
|
@ -678,14 +678,14 @@ their patch with every possible configuration.
|
|||
*If a build/worker is permanently broken*
|
||||
|
||||
* 1st step: contact the owner of the worker. You can find the name and contact
|
||||
information for the *Admin* of worker on the page of the build in the
|
||||
information for the *Admin* of worker on the page of the build in the
|
||||
*Worker* tab:
|
||||
|
||||
.. image:: buildbot_worker_contact.png
|
||||
|
||||
* 2nd step: If the owner does not respond or fix the worker, please escalate
|
||||
* 2nd step: If the owner does not respond or fix the worker, please escalate
|
||||
to Galina Kostanova, the maintainer of the BuildBot master.
|
||||
* 3rd step: If Galina could not help you, please escalate to the
|
||||
* 3rd step: If Galina could not help you, please escalate to the
|
||||
`Infrastructure Working Group <mailto:iwg@llvm.org>`_.
|
||||
|
||||
.. _new-llvm-components:
|
||||
|
|
|
|||
|
|
@ -71,15 +71,15 @@ checking if a pointer is ``null``, like:
|
|||
%ptr = call i32* @get_ptr()
|
||||
%ptr_is_null = icmp i32* %ptr, null
|
||||
br i1 %ptr_is_null, label %is_null, label %not_null, !make.implicit !0
|
||||
|
||||
|
||||
not_null:
|
||||
%t = load i32, i32* %ptr
|
||||
br label %do_something_with_t
|
||||
|
||||
|
||||
is_null:
|
||||
call void @HFC()
|
||||
unreachable
|
||||
|
||||
|
||||
!0 = !{}
|
||||
|
||||
to control flow implicit in the instruction loading or storing through
|
||||
|
|
@ -90,7 +90,7 @@ the pointer being null checked:
|
|||
%ptr = call i32* @get_ptr()
|
||||
%t = load i32, i32* %ptr ;; handler-pc = label %is_null
|
||||
br label %do_something_with_t
|
||||
|
||||
|
||||
is_null:
|
||||
call void @HFC()
|
||||
unreachable
|
||||
|
|
|
|||
|
|
@ -9,20 +9,20 @@ Abstract
|
|||
========
|
||||
|
||||
This document covers how to integrate LLVM into a compiler for a language which
|
||||
supports garbage collection. **Note that LLVM itself does not provide a
|
||||
garbage collector.** You must provide your own.
|
||||
supports garbage collection. **Note that LLVM itself does not provide a
|
||||
garbage collector.** You must provide your own.
|
||||
|
||||
Quick Start
|
||||
============
|
||||
|
||||
First, you should pick a collector strategy. LLVM includes a number of built
|
||||
First, you should pick a collector strategy. LLVM includes a number of built
|
||||
in ones, but you can also implement a loadable plugin with a custom definition.
|
||||
Note that the collector strategy is a description of how LLVM should generate
|
||||
Note that the collector strategy is a description of how LLVM should generate
|
||||
code such that it interacts with your collector and runtime, not a description
|
||||
of the collector itself.
|
||||
|
||||
Next, mark your generated functions as using your chosen collector strategy.
|
||||
From c++, you can call:
|
||||
Next, mark your generated functions as using your chosen collector strategy.
|
||||
From c++, you can call:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
|
|
@ -38,37 +38,37 @@ This will produce IR like the following fragment:
|
|||
|
||||
When generating LLVM IR for your functions, you will need to:
|
||||
|
||||
* Use ``@llvm.gcread`` and/or ``@llvm.gcwrite`` in place of standard load and
|
||||
store instructions. These intrinsics are used to represent load and store
|
||||
barriers. If you collector does not require such barriers, you can skip
|
||||
this step.
|
||||
* Use ``@llvm.gcread`` and/or ``@llvm.gcwrite`` in place of standard load and
|
||||
store instructions. These intrinsics are used to represent load and store
|
||||
barriers. If you collector does not require such barriers, you can skip
|
||||
this step.
|
||||
|
||||
* Use the memory allocation routines provided by your garbage collector's
|
||||
* Use the memory allocation routines provided by your garbage collector's
|
||||
runtime library.
|
||||
|
||||
* If your collector requires them, generate type maps according to your
|
||||
runtime's binary interface. LLVM is not involved in the process. In
|
||||
particular, the LLVM type system is not suitable for conveying such
|
||||
* If your collector requires them, generate type maps according to your
|
||||
runtime's binary interface. LLVM is not involved in the process. In
|
||||
particular, the LLVM type system is not suitable for conveying such
|
||||
information though the compiler.
|
||||
|
||||
* Insert any coordination code required for interacting with your collector.
|
||||
* Insert any coordination code required for interacting with your collector.
|
||||
Many collectors require running application code to periodically check a
|
||||
flag and conditionally call a runtime function. This is often referred to
|
||||
as a safepoint poll.
|
||||
flag and conditionally call a runtime function. This is often referred to
|
||||
as a safepoint poll.
|
||||
|
||||
You will need to identify roots (i.e. references to heap objects your collector
|
||||
needs to know about) in your generated IR, so that LLVM can encode them into
|
||||
your final stack maps. Depending on the collector strategy chosen, this is
|
||||
accomplished by using either the ``@llvm.gcroot`` intrinsics or an
|
||||
``gc.statepoint`` relocation sequence.
|
||||
You will need to identify roots (i.e. references to heap objects your collector
|
||||
needs to know about) in your generated IR, so that LLVM can encode them into
|
||||
your final stack maps. Depending on the collector strategy chosen, this is
|
||||
accomplished by using either the ``@llvm.gcroot`` intrinsics or an
|
||||
``gc.statepoint`` relocation sequence.
|
||||
|
||||
Don't forget to create a root for each intermediate value that is generated when
|
||||
evaluating an expression. In ``h(f(), g())``, the result of ``f()`` could
|
||||
evaluating an expression. In ``h(f(), g())``, the result of ``f()`` could
|
||||
easily be collected if evaluating ``g()`` triggers a collection.
|
||||
|
||||
Finally, you need to link your runtime library with the generated program
|
||||
executable (for a static compiler) or ensure the appropriate symbols are
|
||||
available for the runtime linker (for a JIT compiler).
|
||||
Finally, you need to link your runtime library with the generated program
|
||||
executable (for a static compiler) or ensure the appropriate symbols are
|
||||
available for the runtime linker (for a JIT compiler).
|
||||
|
||||
|
||||
Introduction
|
||||
|
|
@ -136,15 +136,15 @@ instance, the intrinsics permit:
|
|||
|
||||
* reference counting
|
||||
|
||||
We hope that the support built into the LLVM IR is sufficient to support a
|
||||
broad class of garbage collected languages including Scheme, ML, Java, C#,
|
||||
We hope that the support built into the LLVM IR is sufficient to support a
|
||||
broad class of garbage collected languages including Scheme, ML, Java, C#,
|
||||
Perl, Python, Lua, Ruby, other scripting languages, and more.
|
||||
|
||||
Note that LLVM **does not itself provide a garbage collector** --- this should
|
||||
be part of your language's runtime library. LLVM provides a framework for
|
||||
describing the garbage collectors requirements to the compiler. In particular,
|
||||
LLVM provides support for generating stack maps at call sites, polling for a
|
||||
safepoint, and emitting load and store barriers. You can also extend LLVM -
|
||||
LLVM provides support for generating stack maps at call sites, polling for a
|
||||
safepoint, and emitting load and store barriers. You can also extend LLVM -
|
||||
possibly through a loadable :ref:`code generation plugins <plugin>` - to
|
||||
generate code and data structures which conforms to the *binary interface*
|
||||
specified by the *runtime library*. This is similar to the relationship between
|
||||
|
|
@ -183,12 +183,12 @@ There are additional areas that LLVM does not directly address:
|
|||
In general, LLVM's support for GC does not include features which can be
|
||||
adequately addressed with other features of the IR and does not specify a
|
||||
particular binary interface. On the plus side, this means that you should be
|
||||
able to integrate LLVM with an existing runtime. On the other hand, it can
|
||||
have the effect of leaving a lot of work for the developer of a novel
|
||||
language. We try to mitigate this by providing built in collector strategy
|
||||
descriptions that can work with many common collector designs and easy
|
||||
extension points. If you don't already have a specific binary interface
|
||||
you need to support, we recommend trying to use one of these built in collector
|
||||
able to integrate LLVM with an existing runtime. On the other hand, it can
|
||||
have the effect of leaving a lot of work for the developer of a novel
|
||||
language. We try to mitigate this by providing built in collector strategy
|
||||
descriptions that can work with many common collector designs and easy
|
||||
extension points. If you don't already have a specific binary interface
|
||||
you need to support, we recommend trying to use one of these built in collector
|
||||
strategies.
|
||||
|
||||
.. _gc_intrinsics:
|
||||
|
|
@ -198,8 +198,8 @@ LLVM IR Features
|
|||
|
||||
This section describes the garbage collection facilities provided by the
|
||||
:doc:`LLVM intermediate representation <LangRef>`. The exact behavior of these
|
||||
IR features is specified by the selected :ref:`GC strategy description
|
||||
<plugin>`.
|
||||
IR features is specified by the selected :ref:`GC strategy description
|
||||
<plugin>`.
|
||||
|
||||
Specifying GC code generation: ``gc "..."``
|
||||
-------------------------------------------
|
||||
|
|
@ -212,9 +212,9 @@ The ``gc`` function attribute is used to specify the desired GC strategy to the
|
|||
compiler. Its programmatic equivalent is the ``setGC`` method of ``Function``.
|
||||
|
||||
Setting ``gc "name"`` on a function triggers a search for a matching subclass
|
||||
of GCStrategy. Some collector strategies are built in. You can add others
|
||||
of GCStrategy. Some collector strategies are built in. You can add others
|
||||
using either the loadable plugin mechanism, or by patching your copy of LLVM.
|
||||
It is the selected GC strategy which defines the exact nature of the code
|
||||
It is the selected GC strategy which defines the exact nature of the code
|
||||
generated to support GC. If none is found, the compiler will raise an error.
|
||||
|
||||
Specifying the GC style on a per-function basis allows LLVM to link together
|
||||
|
|
@ -226,17 +226,17 @@ Identifying GC roots on the stack
|
|||
----------------------------------
|
||||
|
||||
LLVM currently supports two different mechanisms for describing references in
|
||||
compiled code at safepoints. ``llvm.gcroot`` is the older mechanism;
|
||||
``gc.statepoint`` has been added more recently. At the moment, you can choose
|
||||
either implementation (on a per :ref:`GC strategy <plugin>` basis). Longer
|
||||
term, we will probably either migrate away from ``llvm.gcroot`` entirely, or
|
||||
substantially merge their implementations. Note that most new development
|
||||
work is focused on ``gc.statepoint``.
|
||||
compiled code at safepoints. ``llvm.gcroot`` is the older mechanism;
|
||||
``gc.statepoint`` has been added more recently. At the moment, you can choose
|
||||
either implementation (on a per :ref:`GC strategy <plugin>` basis). Longer
|
||||
term, we will probably either migrate away from ``llvm.gcroot`` entirely, or
|
||||
substantially merge their implementations. Note that most new development
|
||||
work is focused on ``gc.statepoint``.
|
||||
|
||||
Using ``gc.statepoint``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
:doc:`This page <Statepoints>` contains detailed documentation for
|
||||
``gc.statepoint``.
|
||||
:doc:`This page <Statepoints>` contains detailed documentation for
|
||||
``gc.statepoint``.
|
||||
|
||||
Using ``llvm.gcwrite``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -247,8 +247,8 @@ Using ``llvm.gcwrite``
|
|||
|
||||
The ``llvm.gcroot`` intrinsic is used to inform LLVM that a stack variable
|
||||
references an object on the heap and is to be tracked for garbage collection.
|
||||
The exact impact on generated code is specified by the Function's selected
|
||||
:ref:`GC strategy <plugin>`. All calls to ``llvm.gcroot`` **must** reside
|
||||
The exact impact on generated code is specified by the Function's selected
|
||||
:ref:`GC strategy <plugin>`. All calls to ``llvm.gcroot`` **must** reside
|
||||
inside the first basic block.
|
||||
|
||||
The first argument **must** be a value referring to an alloca instruction or a
|
||||
|
|
@ -256,12 +256,12 @@ bitcast of an alloca. The second contains a pointer to metadata that should be
|
|||
associated with the pointer, and **must** be a constant or global value
|
||||
address. If your target collector uses tags, use a null pointer for metadata.
|
||||
|
||||
A compiler which performs manual SSA construction **must** ensure that SSA
|
||||
A compiler which performs manual SSA construction **must** ensure that SSA
|
||||
values representing GC references are stored in to the alloca passed to the
|
||||
respective ``gcroot`` before every call site and reloaded after every call.
|
||||
A compiler which uses mem2reg to raise imperative code using ``alloca`` into
|
||||
SSA form need only add a call to ``@llvm.gcroot`` for those variables which
|
||||
are pointers into the GC heap.
|
||||
respective ``gcroot`` before every call site and reloaded after every call.
|
||||
A compiler which uses mem2reg to raise imperative code using ``alloca`` into
|
||||
SSA form need only add a call to ``@llvm.gcroot`` for those variables which
|
||||
are pointers into the GC heap.
|
||||
|
||||
It is also important to mark intermediate values with ``llvm.gcroot``. For
|
||||
example, consider ``h(f(), g())``. Beware leaking the result of ``f()`` in the
|
||||
|
|
@ -343,13 +343,13 @@ LLVM does not enforce this relationship between the object and derived pointer
|
|||
(although a particular :ref:`collector strategy <plugin>` might). However, it
|
||||
would be an unusual collector that violated it.
|
||||
|
||||
The use of these intrinsics is naturally optional if the target GC does not
|
||||
require the corresponding barrier. The GC strategy used with such a collector
|
||||
should replace the intrinsic calls with the corresponding ``load`` or
|
||||
The use of these intrinsics is naturally optional if the target GC does not
|
||||
require the corresponding barrier. The GC strategy used with such a collector
|
||||
should replace the intrinsic calls with the corresponding ``load`` or
|
||||
``store`` instruction if they are used.
|
||||
|
||||
One known deficiency with the current design is that the barrier intrinsics do
|
||||
not include the size or alignment of the underlying operation performed. It is
|
||||
One known deficiency with the current design is that the barrier intrinsics do
|
||||
not include the size or alignment of the underlying operation performed. It is
|
||||
currently assumed that the operation is of pointer size and the alignment is
|
||||
assumed to be the target machine's default alignment.
|
||||
|
||||
|
|
@ -391,7 +391,7 @@ greater performance impact since pointer reads are more frequent than writes.
|
|||
Built In GC Strategies
|
||||
======================
|
||||
|
||||
LLVM includes built in support for several varieties of garbage collectors.
|
||||
LLVM includes built in support for several varieties of garbage collectors.
|
||||
|
||||
The Shadow Stack GC
|
||||
----------------------
|
||||
|
|
@ -484,15 +484,15 @@ data structure, but there are only 20 lines of meaningful code.)
|
|||
The 'Erlang' and 'Ocaml' GCs
|
||||
-----------------------------
|
||||
|
||||
LLVM ships with two example collectors which leverage the ``gcroot``
|
||||
mechanisms. To our knowledge, these are not actually used by any language
|
||||
runtime, but they do provide a reasonable starting point for someone interested
|
||||
in writing an ``gcroot`` compatible GC plugin. In particular, these are the
|
||||
only in tree examples of how to produce a custom binary stack map format using
|
||||
LLVM ships with two example collectors which leverage the ``gcroot``
|
||||
mechanisms. To our knowledge, these are not actually used by any language
|
||||
runtime, but they do provide a reasonable starting point for someone interested
|
||||
in writing an ``gcroot`` compatible GC plugin. In particular, these are the
|
||||
only in tree examples of how to produce a custom binary stack map format using
|
||||
a ``gcroot`` strategy.
|
||||
|
||||
As there names imply, the binary format produced is intended to model that
|
||||
used by the Erlang and OCaml compilers respectively.
|
||||
As there names imply, the binary format produced is intended to model that
|
||||
used by the Erlang and OCaml compilers respectively.
|
||||
|
||||
.. _statepoint_example_gc:
|
||||
|
||||
|
|
@ -503,19 +503,19 @@ The Statepoint Example GC
|
|||
|
||||
F.setGC("statepoint-example");
|
||||
|
||||
This GC provides an example of how one might use the infrastructure provided
|
||||
by ``gc.statepoint``. This example GC is compatible with the
|
||||
:ref:`PlaceSafepoints` and :ref:`RewriteStatepointsForGC` utility passes
|
||||
which simplify ``gc.statepoint`` sequence insertion. If you need to build a
|
||||
This GC provides an example of how one might use the infrastructure provided
|
||||
by ``gc.statepoint``. This example GC is compatible with the
|
||||
:ref:`PlaceSafepoints` and :ref:`RewriteStatepointsForGC` utility passes
|
||||
which simplify ``gc.statepoint`` sequence insertion. If you need to build a
|
||||
custom GC strategy around the ``gc.statepoints`` mechanisms, it is recommended
|
||||
that you use this one as a starting point.
|
||||
|
||||
This GC strategy does not support read or write barriers. As a result, these
|
||||
This GC strategy does not support read or write barriers. As a result, these
|
||||
intrinsics are lowered to normal loads and stores.
|
||||
|
||||
The stack map format generated by this GC strategy can be found in the
|
||||
:ref:`stackmap-section` using a format documented :ref:`here
|
||||
<statepoint-stackmap-format>`. This format is intended to be the standard
|
||||
The stack map format generated by this GC strategy can be found in the
|
||||
:ref:`stackmap-section` using a format documented :ref:`here
|
||||
<statepoint-stackmap-format>`. This format is intended to be the standard
|
||||
format supported by LLVM going forward.
|
||||
|
||||
The CoreCLR GC
|
||||
|
|
@ -525,15 +525,15 @@ The CoreCLR GC
|
|||
|
||||
F.setGC("coreclr");
|
||||
|
||||
This GC leverages the ``gc.statepoint`` mechanism to support the
|
||||
This GC leverages the ``gc.statepoint`` mechanism to support the
|
||||
`CoreCLR <https://github.com/dotnet/coreclr>`__ runtime.
|
||||
|
||||
Support for this GC strategy is a work in progress. This strategy will
|
||||
differ from
|
||||
:ref:`statepoint-example GC<statepoint_example_gc>` strategy in
|
||||
Support for this GC strategy is a work in progress. This strategy will
|
||||
differ from
|
||||
:ref:`statepoint-example GC<statepoint_example_gc>` strategy in
|
||||
certain aspects like:
|
||||
|
||||
* Base-pointers of interior pointers are not explicitly
|
||||
* Base-pointers of interior pointers are not explicitly
|
||||
tracked and reported.
|
||||
|
||||
* A different format is used for encoding stack maps.
|
||||
|
|
@ -545,24 +545,24 @@ Custom GC Strategies
|
|||
====================
|
||||
|
||||
If none of the built in GC strategy descriptions met your needs above, you will
|
||||
need to define a custom GCStrategy and possibly, a custom LLVM pass to perform
|
||||
lowering. Your best example of where to start defining a custom GCStrategy
|
||||
need to define a custom GCStrategy and possibly, a custom LLVM pass to perform
|
||||
lowering. Your best example of where to start defining a custom GCStrategy
|
||||
would be to look at one of the built in strategies.
|
||||
|
||||
You may be able to structure this additional code as a loadable plugin library.
|
||||
Loadable plugins are sufficient if all you need is to enable a different
|
||||
combination of built in functionality, but if you need to provide a custom
|
||||
lowering pass, you will need to build a patched version of LLVM. If you think
|
||||
you need a patched build, please ask for advice on llvm-dev. There may be an
|
||||
easy way we can extend the support to make it work for your use case without
|
||||
requiring a custom build.
|
||||
Loadable plugins are sufficient if all you need is to enable a different
|
||||
combination of built in functionality, but if you need to provide a custom
|
||||
lowering pass, you will need to build a patched version of LLVM. If you think
|
||||
you need a patched build, please ask for advice on llvm-dev. There may be an
|
||||
easy way we can extend the support to make it work for your use case without
|
||||
requiring a custom build.
|
||||
|
||||
Collector Requirements
|
||||
----------------------
|
||||
|
||||
You should be able to leverage any existing collector library that includes the following elements:
|
||||
|
||||
#. A memory allocator which exposes an allocation function your compiled
|
||||
#. A memory allocator which exposes an allocation function your compiled
|
||||
code can call.
|
||||
|
||||
#. A binary format for the stack map. A stack map describes the location
|
||||
|
|
@ -571,14 +571,14 @@ You should be able to leverage any existing collector library that includes the
|
|||
which conservatively scan the stack don't require such a structure.
|
||||
|
||||
#. A stack crawler to discover functions on the call stack, and enumerate the
|
||||
references listed in the stack map for each call site.
|
||||
references listed in the stack map for each call site.
|
||||
|
||||
#. A mechanism for identifying references in global locations (e.g. global
|
||||
#. A mechanism for identifying references in global locations (e.g. global
|
||||
variables).
|
||||
|
||||
#. If you collector requires them, an LLVM IR implementation of your collectors
|
||||
load and store barriers. Note that since many collectors don't require
|
||||
barriers at all, LLVM defaults to lowering such barriers to normal loads
|
||||
load and store barriers. Note that since many collectors don't require
|
||||
barriers at all, LLVM defaults to lowering such barriers to normal loads
|
||||
and stores unless you arrange otherwise.
|
||||
|
||||
|
||||
|
|
@ -852,12 +852,12 @@ Custom lowering of intrinsics
|
|||
For GCs which use barriers or unusual treatment of stack roots, the
|
||||
implementor is responsibly for providing a custom pass to lower the
|
||||
intrinsics with the desired semantics. If you have opted in to custom
|
||||
lowering of a particular intrinsic your pass **must** eliminate all
|
||||
lowering of a particular intrinsic your pass **must** eliminate all
|
||||
instances of the corresponding intrinsic in functions which opt in to
|
||||
your GC. The best example of such a pass is the ShadowStackGC and it's
|
||||
ShadowStackGCLowering pass.
|
||||
your GC. The best example of such a pass is the ShadowStackGC and it's
|
||||
ShadowStackGCLowering pass.
|
||||
|
||||
There is currently no way to register such a custom lowering pass
|
||||
There is currently no way to register such a custom lowering pass
|
||||
without building a custom copy of LLVM.
|
||||
|
||||
.. _safe-points:
|
||||
|
|
|
|||
|
|
@ -102,8 +102,8 @@ Mailing Lists
|
|||
-------------
|
||||
|
||||
If you can't find what you need in these docs, try consulting the mailing
|
||||
lists. In addition to the traditional mailing lists there is also a
|
||||
`Discourse server <https://llvm.discourse.group>`_ available.
|
||||
lists. In addition to the traditional mailing lists there is also a
|
||||
`Discourse server <https://llvm.discourse.group>`_ available.
|
||||
|
||||
`Developer's List (llvm-dev)`__
|
||||
This list is for people who want to be included in technical discussions of
|
||||
|
|
@ -161,7 +161,7 @@ writing, the following sync-ups are organized:
|
|||
- Every 2 weeks on Thursday
|
||||
- `ics <https://calendar.google.com/calendar/ical/lowrisc.org_0n5pkesfjcnp0bh5hps1p0bd80%40group.calendar.google.com/public/basic.ics>`__
|
||||
`gcal <https://calendar.google.com/calendar/b/1?cid=bG93cmlzYy5vcmdfMG41cGtlc2ZqY25wMGJoNWhwczFwMGJkODBAZ3JvdXAuY2FsZW5kYXIuZ29vZ2xlLmNvbQ>`__
|
||||
-
|
||||
-
|
||||
* - Scalable Vectors and Arm SVE
|
||||
- Monthly, every 3rd Tuesday
|
||||
- `ics <https://calendar.google.com/calendar/ical/bjms39pe6k6bo5egtsp7don414%40group.calendar.google.com/public/basic.ics>`__
|
||||
|
|
@ -178,27 +178,27 @@ writing, the following sync-ups are organized:
|
|||
- `Minutes/docs <https://docs.google.com/document/d/1GLCE8cl7goCaLSiM9j1eIq5IqeXt6_YTY2UEcC4jmsg/edit?usp=sharing>`__
|
||||
* - `CIRCT <https://github.com/llvm/circt>`__
|
||||
- Weekly, on Wednesday
|
||||
-
|
||||
-
|
||||
- `Minutes/docs <https://docs.google.com/document/d/1fOSRdyZR2w75D87yU2Ma9h2-_lEPL4NxvhJGJd-s5pk/edit#heading=h.mulvhjtr8dk9>`__
|
||||
* - `MLIR <https://mlir.llvm.org>`__ design meetings
|
||||
- Weekly, on Thursdays
|
||||
-
|
||||
-
|
||||
- `Minutes/docs <https://docs.google.com/document/d/1y_9f1AbfgcoVdJh4_aM6-BaSHvrHl8zuA5G4jv_94K8/edit#heading=h.cite1kolful9>`__
|
||||
* - flang
|
||||
- Multiple meeting series, `documented here <https://github.com/llvm/llvm-project/blob/main/flang/docs/GettingInvolved.md#calls>`__
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
* - OpenMP
|
||||
- Multiple meeting series, `documented here <https://openmp.llvm.org/docs/SupportAndFAQ.html>`__
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
* - LLVM Alias Analysis
|
||||
- Every 4 weeks on Tuesdays
|
||||
- `ics <http://lists.llvm.org/pipermail/llvm-dev/attachments/20201103/a3499a67/attachment-0001.ics>`__
|
||||
- `Minutes/docs <https://docs.google.com/document/d/17U-WvX8qyKc3S36YUKr3xfF-GHunWyYowXbxEdpHscw>`__
|
||||
* - Windows/COFF related developments
|
||||
- Every 2 months on Thursday
|
||||
-
|
||||
-
|
||||
- `Minutes/docs <https://docs.google.com/document/d/1A-W0Sas_oHWTEl_x_djZYoRtzAdTONMW_6l1BH9G6Bo/edit?usp=sharing>`__
|
||||
* - Vector Predication
|
||||
- Every 2 weeks on Tuesdays, 3pm UTC
|
||||
|
|
@ -233,11 +233,11 @@ This channel has several bots.
|
|||
* clang-bot - A `geordi <http://www.eelis.net/geordi/>`_ instance running
|
||||
near-trunk clang instead of gcc.
|
||||
|
||||
In addition to the traditional IRC there is a
|
||||
`Discord <https://discord.com/channels/636084430946959380/636725486533345280>`_
|
||||
chat server available. To sign up, please use this
|
||||
In addition to the traditional IRC there is a
|
||||
`Discord <https://discord.com/channels/636084430946959380/636725486533345280>`_
|
||||
chat server available. To sign up, please use this
|
||||
`invitation link <https://discord.com/invite/xS7Z362>`_.
|
||||
|
||||
|
||||
|
||||
.. _meetups-social-events:
|
||||
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ These instruction were tested with Visual Studio 2019 and Python 3.9.6:
|
|||
|
||||
pip install psutil
|
||||
git clone https://github.com/llvm/llvm-project.git llvm
|
||||
|
||||
|
||||
Instead of ``git clone`` you may download a compressed source distribution
|
||||
from the `releases page <https://github.com/llvm/llvm-project/releases>`_.
|
||||
Select the last link: ``Source code (zip)`` and unpack the downloaded file using
|
||||
|
|
@ -170,7 +170,7 @@ These instruction were tested with Visual Studio 2019 and Python 3.9.6:
|
|||
You can run LLVM tests by merely building the project "check-all". The test
|
||||
results will be shown in the VS output window. Once the build succeeds, you
|
||||
have verified a working LLVM development environment!
|
||||
|
||||
|
||||
You should not see any unexpected failures, but will see many unsupported
|
||||
tests and expected failures:
|
||||
|
||||
|
|
@ -195,10 +195,10 @@ run these commands in an admin shell to install the required tools:
|
|||
choco install -y git cmake python3
|
||||
pip3 install psutil
|
||||
|
||||
There is also a Windows
|
||||
`Dockerfile <https://github.com/llvm/llvm-zorg/blob/main/buildbot/google/docker/windows-base-vscode2019/Dockerfile>`_
|
||||
There is also a Windows
|
||||
`Dockerfile <https://github.com/llvm/llvm-zorg/blob/main/buildbot/google/docker/windows-base-vscode2019/Dockerfile>`_
|
||||
with the entire build tool chain. This can be used to test the build with a
|
||||
tool chain different from your host installation or to create build servers.
|
||||
tool chain different from your host installation or to create build servers.
|
||||
|
||||
Next steps
|
||||
==========
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ directory that makes clang crash at trunk, but it worked fine at revision
|
|||
|
||||
To make sure your run script works, it's a good idea to run ``./run.sh`` by
|
||||
hand and tweak the script until it works, then run ``git bisect good`` or
|
||||
``git bisect bad`` manually once based on the result of the script
|
||||
``git bisect bad`` manually once based on the result of the script
|
||||
(check ``echo $?`` after your script ran), and only then run ``git bisect run
|
||||
./run.sh``. Don't forget to mark your run script as executable -- ``git bisect
|
||||
run`` doesn't check for that, it just assumes the run script failed each time.
|
||||
|
|
@ -85,7 +85,7 @@ Here's how LLVM's history currently looks:
|
|||
A-o-o-......-o-D-o-o-HEAD
|
||||
/
|
||||
B-o-...-o-C-
|
||||
|
||||
|
||||
``A`` is the first commit in LLVM ever, ``97724f18c79c``.
|
||||
|
||||
``B`` is the first commit in MLIR, ``aed0d21a62db``.
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue