aboutsummaryrefslogtreecommitdiff
path: root/clang/docs
diff options
context:
space:
mode:
Diffstat (limited to 'clang/docs')
-rw-r--r--clang/docs/AllocToken.rst29
-rw-r--r--clang/docs/DebuggingCoroutines.rst431
-rw-r--r--clang/docs/ReleaseNotes.rst6
-rw-r--r--clang/docs/UsersManual.rst18
-rw-r--r--clang/docs/analyzer/developer-docs/Statistics.rst1
5 files changed, 316 insertions, 169 deletions
diff --git a/clang/docs/AllocToken.rst b/clang/docs/AllocToken.rst
index 7f3a128..bda8466 100644
--- a/clang/docs/AllocToken.rst
+++ b/clang/docs/AllocToken.rst
@@ -122,6 +122,35 @@ which encodes the token ID hint in the allocation function name.
This ABI provides a more efficient alternative where
``-falloc-token-max`` is small.
+Instrumenting Non-Standard Allocation Functions
+-----------------------------------------------
+
+By default, AllocToken only instruments standard library allocation functions.
+This simplifies adoption, as a compatible allocator only needs to provide
+token-enabled variants for a well-defined set of standard functions.
+
+To extend instrumentation to custom allocation functions, enable broader
+coverage with ``-fsanitize-alloc-token-extended``. Such functions require being
+marked with the `malloc
+<https://clang.llvm.org/docs/AttributeReference.html#malloc>`_ or `alloc_size
+<https://clang.llvm.org/docs/AttributeReference.html#alloc-size>`_ attributes
+(or a combination).
+
+For example:
+
+.. code-block:: c
+
+ void *custom_malloc(size_t size) __attribute__((malloc));
+ void *my_malloc(size_t size) __attribute__((alloc_size(1)));
+
+ // Original:
+ ptr1 = custom_malloc(size);
+ ptr2 = my_malloc(size);
+
+ // Instrumented:
+ ptr1 = __alloc_token_custom_malloc(size, token_id);
+ ptr2 = __alloc_token_my_malloc(size, token_id);
+
Disabling Instrumentation
-------------------------
diff --git a/clang/docs/DebuggingCoroutines.rst b/clang/docs/DebuggingCoroutines.rst
index 9eaf8d4..c62e2ea 100644
--- a/clang/docs/DebuggingCoroutines.rst
+++ b/clang/docs/DebuggingCoroutines.rst
@@ -179,8 +179,8 @@ generator and its internal state.
To do so, we can simply look into the ``gen.hdl`` variable. LLDB comes with a
pretty printer for ``std::coroutine_handle`` which will show us the internal
-state of the coroutine. For GDB, you will have to use the ``show-coro-frame``
-command provided by the :ref:`gdb-script`.
+state of the coroutine. For GDB, the pretty printer is provided by a script,
+see :ref:`gdb-script` for setup instructions.
.. image:: ./coro-generator-suspended.png
@@ -206,23 +206,16 @@ Tracking the exact suspension point
Among the compiler-generated members, the ``__coro_index`` is particularly
important. This member identifies the suspension point at which the coroutine
-is currently suspended.
+is currently suspended. However, it is non-trivial to map this number back to
+a source code location.
-However, it is non-trivial to map this number back to a source code location.
-The compiler emits debug info labels for the suspension points. This allows us
-to map the suspension point index back to a source code location. In gdb, we
-can use the ``info line`` command to get the source code location of the
-suspension point.
+For GDB, the provided :ref:`gdb-script` already takes care of this and provides
+the exact line number of the suspension point as part of the coroutine handle's
+summary string. Unfortunately, LLDB's pretty-printer does not support this, yet.
+Furthermore, those labels are only emitted starting with clang 21.0.
-::
-
- (gdb) info line -function coro_task -label __coro_resume_2
- Line 45 of "llvm-example.cpp" starts at address 0x1b1b <_ZL9coro_taski.resume+555> and ends at 0x1b46 <_ZL9coro_taski.resume+598>.
- Line 45 of "llvm-example.cpp" starts at address 0x201b <_ZL9coro_taski.destroy+555> and ends at 0x2046 <_ZL9coro_taski.destroy+598>.
- Line 45 of "llvm-example.cpp" starts at address 0x253b <_ZL9coro_taski.cleanup+555> and ends at 0x2566 <_ZL9coro_taski.cleanup+598>.
-
-LLDB does not support looking up labels. Furthermore, those labels are only emitted
-starting with clang 21.0.
+When debugging with LLDB or when using older clang versions, we will have to use
+a different approach.
For simple cases, you might still be able to guess the suspension point correctly.
Alternatively, you might also want to modify your coroutine library to store
@@ -655,33 +648,17 @@ There are two possible approaches to do so:
We can lookup their types and thereby get the types of promise
and coroutine frame.
-In gdb, one can use the following approach to devirtualize a coroutine type,
-assuming we have a ``std::coroutine_handle`` is at address 0x418eb0:
-
-::
+In general, the second approach is preferred, as it is more portable.
- (gdb) # Get the address of coroutine frame
- (gdb) print/x *0x418eb0
- $1 = 0x4019e0
- (gdb) # Get the linkage name for the coroutine
- (gdb) x 0x4019e0
- 0x4019e0 <_ZL9coro_taski>: 0xe5894855
- (gdb) # Turn off the demangler temporarily to avoid the debugger misunderstanding the name.
- (gdb) set demangle-style none
- (gdb) # The coroutine frame type is 'linkage_name.coro_frame_ty'
- (gdb) print ('_ZL9coro_taski.coro_frame_ty')*(0x418eb0)
- $2 = {__resume_fn = 0x4019e0 <coro_task(int)>, __destroy_fn = 0x402000 <coro_task(int)>, __promise = {...}, ...}
-
-In practice, one would use the ``show-coro-frame`` command provided by the
-:ref:`gdb-script`.
+To do so, we look up the types in the destroy function and not the resume function
+because the resume function pointer will be set to a ``nullptr`` as soon as a
+coroutine reaches its final suspension point. If we used the resume function,
+devirtualization would hence fail for all coroutines that have reached their final
+suspension point.
LLDB comes with devirtualization support out of the box, as part of the
-pretty-printer for ``std::coroutine_handle``. Internally, this pretty-printer
-uses the second approach. We look up the types in the destroy function and not
-the resume function because the resume function pointer will be set to a
-``nullptr`` as soon as a coroutine reaches its final suspension point. If we used
-the resume function, devirtualization would hence fail for all coroutines that
-have reached their final suspension point.
+pretty-printer for ``std::coroutine_handle``. For GDB, a similar pretty-printer
+is provided by the :ref:`gdb-script`.
Interpreting the coroutine frame in optimized builds
----------------------------------------------------
@@ -756,6 +733,26 @@ should not be thought of as directly representing the variables in the C++
source.
+Mapping suspension point indices to source code locations
+---------------------------------------------------------
+
+To aid in mapping a ``__coro_index`` back to a source code location, clang 21.0
+and newer emit special, compiler-generated labels for the suspension points.
+
+In gdb, we can use the ``info line`` command to get the source code location of
+the suspension point.
+
+::
+
+ (gdb) info line -function coro_task -label __coro_resume_2
+ Line 45 of "llvm-example.cpp" starts at address 0x1b1b <_ZL9coro_taski.resume+555> and ends at 0x1b46 <_ZL9coro_taski.resume+598>.
+ Line 45 of "llvm-example.cpp" starts at address 0x201b <_ZL9coro_taski.destroy+555> and ends at 0x2046 <_ZL9coro_taski.destroy+598>.
+ Line 45 of "llvm-example.cpp" starts at address 0x253b <_ZL9coro_taski.cleanup+555> and ends at 0x2566 <_ZL9coro_taski.cleanup+598>.
+
+LLDB does not support looking up labels, yet. For this reason, LLDB's pretty-printer
+does not show the exact line number of the suspension point.
+
+
Resources
=========
@@ -1017,156 +1014,270 @@ Note that this script requires LLDB 21.0 or newer.
GDB Debugger Script
-------------------
-For GDB, the following script provides a couple of useful commands:
+The following script provides:
-* ``async-bt`` to print the stack trace of a coroutine
-* ``show-coro-frame`` to print the coroutine frame, similar to
- LLDB's builtin pretty-printer for coroutine frames
+* a pretty-printer for coroutine handles
+* a frame filter to add coroutine frames to the built-in ``bt`` command
+* the ``get_coro_frame`` and ``get_coro_promise`` functions to be used in
+ expressions, e.g. ``p get_coro_promise(fib.coro_hdl)->current_state``
+
+It can be loaded into GDB using ``source gdb_coro_debugging.py``.
+To load this by default, add this command to your ``~/.gdbinit`` file.
.. code-block:: python
- # debugging-helper.py
+ # gdb_coro_debugging.py
import gdb
from gdb.FrameDecorator import FrameDecorator
- class SymValueWrapper():
- def __init__(self, symbol, value):
- self.sym = symbol
- self.val = value
+ import typing
+ import re
- def __str__(self):
- return str(self.sym) + " = " + str(self.val)
+ def _load_pointer_at(addr: int):
+ return gdb.Value(addr).reinterpret_cast(gdb.lookup_type('void').pointer().pointer()).dereference()
- def get_long_pointer_size():
- return gdb.lookup_type('long').pointer().sizeof
+ """
+ Devirtualized coroutine frame.
- def cast_addr2long_pointer(addr):
- return gdb.Value(addr).cast(gdb.lookup_type('long').pointer())
+ Devirtualizes the promise and frame pointer types by inspecting
+ the destroy function.
- def dereference(addr):
- return long(cast_addr2long_pointer(addr).dereference())
+ Implements `to_string` and `children` to be used by `gdb.printing.PrettyPrinter`.
+ Base class for `CoroutineHandlePrinter`.
+ """
+ class DevirtualizedCoroFrame:
+ def __init__(self, frame_ptr_raw: int, val: gdb.Value | None = None):
+ self.val = val
+ self.frame_ptr_raw = frame_ptr_raw
- class CoroutineFrame(object):
- def __init__(self, task_addr):
- self.frame_addr = task_addr
- self.resume_addr = task_addr
- self.destroy_addr = task_addr + get_long_pointer_size()
- self.promise_addr = task_addr + get_long_pointer_size() * 2
- # In the example, the continuation is the first field member of the promise_type.
- # So they have the same addresses.
- # If we want to generalize the scripts to other coroutine types, we need to be sure
- # the continuation field is the first member of promise_type.
- self.continuation_addr = self.promise_addr
+ # Get the resume and destroy pointers.
+ if frame_ptr_raw == 0:
+ self.resume_ptr = None
+ self.destroy_ptr = None
+ self.promise_ptr = None
+ self.frame_ptr = gdb.Value(frame_ptr_raw).reinterpret_cast(gdb.lookup_type("void").pointer())
+ return
- def next_task_addr(self):
- return dereference(self.continuation_addr)
+ # Get the resume and destroy pointers.
+ self.resume_ptr = _load_pointer_at(frame_ptr_raw)
+ self.destroy_ptr = _load_pointer_at(frame_ptr_raw + 8)
+
+ # Devirtualize the promise and frame pointer types.
+ frame_type = gdb.lookup_type("void")
+ promise_type = gdb.lookup_type("void")
+ self.destroy_func = gdb.block_for_pc(int(self.destroy_ptr))
+ if self.destroy_func is not None:
+ frame_var = gdb.lookup_symbol("__coro_frame", self.destroy_func, gdb.SYMBOL_VAR_DOMAIN)[0]
+ if frame_var is not None:
+ frame_type = frame_var.type
+ promise_var = gdb.lookup_symbol("__promise", self.destroy_func, gdb.SYMBOL_VAR_DOMAIN)[0]
+ if promise_var is not None:
+ promise_type = promise_var.type.strip_typedefs()
+
+ # If the type has a template argument, prefer it over the devirtualized type.
+ if self.val is not None:
+ promise_type_template_arg = self.val.type.template_argument(0)
+ if promise_type_template_arg is not None and promise_type_template_arg.code != gdb.TYPE_CODE_VOID:
+ promise_type = promise_type_template_arg
+
+ self.promise_ptr = gdb.Value(frame_ptr_raw + 16).reinterpret_cast(promise_type.pointer())
+ self.frame_ptr = gdb.Value(frame_ptr_raw).reinterpret_cast(frame_type.pointer())
+
+ # Try to get the suspension point index and look up the exact line entry.
+ self.suspension_point_index = int(self.frame_ptr.dereference()["__coro_index"]) if frame_type.code == gdb.TYPE_CODE_STRUCT else None
+ self.resume_func = gdb.block_for_pc(int(self.resume_ptr))
+ self.resume_label = None
+ if self.resume_func is not None and self.suspension_point_index is not None:
+ label_name = f"__coro_resume_{self.suspension_point_index}"
+ self.resume_label = gdb.lookup_symbol(label_name, self.resume_func, gdb.SYMBOL_LABEL_DOMAIN)[0]
+
+ def get_function_name(self):
+ if self.destroy_func is None:
+ return None
+ name = self.destroy_func.function.name
+ # Strip the "clone" suffix if it exists.
+ if "() [clone " in name:
+ name = name[:name.index("() [clone ")]
+ return name
+
+ def to_string(self):
+ result = "coro(" + str(self.frame_ptr_raw) + ")"
+ if self.destroy_func is not None:
+ result += ": " + self.get_function_name()
+ if self.resume_label is not None:
+ result += ", line " + str(self.resume_label.line)
+ if self.suspension_point_index is not None:
+ result += ", suspension point " + str(self.suspension_point_index)
+ return result
+
+ def children(self):
+ if self.resume_ptr is None:
+ return [
+ ("coro_frame", self.frame_ptr),
+ ]
+ else:
+ return [
+ ("resume", self.resume_ptr),
+ ("destroy", self.destroy_ptr),
+ ("promise", self.promise_ptr),
+ ("coro_frame", self.frame_ptr)
+ ]
- class CoroutineFrameDecorator(FrameDecorator):
- def __init__(self, coro_frame):
- super(CoroutineFrameDecorator, self).__init__(None)
- self.coro_frame = coro_frame
- self.resume_func = dereference(self.coro_frame.resume_addr)
- self.resume_func_block = gdb.block_for_pc(self.resume_func)
- if self.resume_func_block is None:
- raise Exception('Not stackless coroutine.')
- self.line_info = gdb.find_pc_line(self.resume_func)
- def address(self):
- return self.resume_func
+ # Works for both libc++ and libstdc++.
+ libcxx_corohdl_regex = re.compile('^std::__[A-Za-z0-9]+::coroutine_handle<.+>$|^std::coroutine_handle<.+>(( )?&)?$')
- def filename(self):
- return self.line_info.symtab.filename
+ def _extract_coro_frame_ptr_from_handle(val: gdb.Value):
+ if libcxx_corohdl_regex.match(val.type.strip_typedefs().name) is None:
+ raise ValueError("Expected a std::coroutine_handle, got %s" % val.type.strip_typedefs().name)
- def frame_args(self):
- return [SymValueWrapper("frame_addr", cast_addr2long_pointer(self.coro_frame.frame_addr)),
- SymValueWrapper("promise_addr", cast_addr2long_pointer(self.coro_frame.promise_addr)),
- SymValueWrapper("continuation_addr", cast_addr2long_pointer(self.coro_frame.continuation_addr))
- ]
+ # We expect the coroutine handle to have a single field, which is the frame pointer.
+ # This heuristic works for both libc++ and libstdc++.
+ fields = val.type.fields()
+ if len(fields) != 1:
+ raise ValueError("Expected 1 field, got %d" % len(fields))
+ return int(val[fields[0]])
- def function(self):
- return self.resume_func_block.function.print_name
- def line(self):
- return self.line_info.line
-
- class StripDecorator(FrameDecorator):
- def __init__(self, frame):
- super(StripDecorator, self).__init__(frame)
- self.frame = frame
- f = frame.function()
- self.function_name = f
-
- def __str__(self, shift = 2):
- addr = "" if self.address() is None else '%#x' % self.address() + " in "
- location = "" if self.filename() is None else " at " + self.filename() + ":" + str(self.line())
- return addr + self.function() + " " + str([str(args) for args in self.frame_args()]) + location
-
- class CoroutineFilter:
- def create_coroutine_frames(self, task_addr):
- frames = []
- while task_addr != 0:
- coro_frame = CoroutineFrame(task_addr)
- frames.append(CoroutineFrameDecorator(coro_frame))
- task_addr = coro_frame.next_task_addr()
- return frames
-
- class AsyncStack(gdb.Command):
+ """
+ Pretty printer for `std::coroutine_handle<T>`
+
+ Works for both libc++ and libstdc++.
+
+ It prints the coroutine handle as a struct with the following fields:
+ - resume: the resume function pointer
+ - destroy: the destroy function pointer
+ - promise: the promise pointer
+ - coro_frame: the coroutine frame pointer
+
+ Most of the functionality is implemented in `DevirtualizedCoroFrame`.
+ """
+ class CoroutineHandlePrinter(DevirtualizedCoroFrame):
+ def __init__(self, val : gdb.Value):
+ frame_ptr_raw = _extract_coro_frame_ptr_from_handle(val)
+ super(CoroutineHandlePrinter, self).__init__(frame_ptr_raw, val)
+
+
+ def build_pretty_printer():
+ pp = gdb.printing.RegexpCollectionPrettyPrinter("coroutine")
+ pp.add_printer('std::coroutine_handle', libcxx_corohdl_regex, CoroutineHandlePrinter)
+ return pp
+
+ gdb.printing.register_pretty_printer(
+ gdb.current_objfile(),
+ build_pretty_printer())
+
+
+ """
+ Get the coroutine frame pointer from a coroutine handle.
+
+ Usage:
+ ```
+ p *get_coro_frame(coroutine_hdl)
+ ```
+ """
+ class GetCoroFrame(gdb.Function):
def __init__(self):
- super(AsyncStack, self).__init__("async-bt", gdb.COMMAND_USER)
+ super(GetCoroFrame, self).__init__("get_coro_frame")
- def invoke(self, arg, from_tty):
- coroutine_filter = CoroutineFilter()
- argv = gdb.string_to_argv(arg)
- if len(argv) == 0:
- try:
- task = gdb.parse_and_eval('__coro_frame')
- task = int(str(task.address), 16)
- except Exception:
- print ("Can't find __coro_frame in current context.\n" +
- "Please use `async-bt` in stackless coroutine context.")
- return
- elif len(argv) != 1:
- print("usage: async-bt <pointer to task>")
- return
- else:
- task = int(argv[0], 16)
+ def invoke(self, coroutine_hdl_raw):
+ return CoroutineHandlePrinter(coroutine_hdl_raw).frame_ptr
+
+ GetCoroFrame()
- frames = coroutine_filter.create_coroutine_frames(task)
- i = 0
- for f in frames:
- print '#'+ str(i), str(StripDecorator(f))
- i += 1
- return
- AsyncStack()
+ """
+ Get the coroutine frame pointer from a coroutine handle.
- class ShowCoroFrame(gdb.Command):
+ Usage:
+ ```
+ p *get_coro_promise(coroutine_hdl)
+ ```
+ """
+ class GetCoroFrame(gdb.Function):
def __init__(self):
- super(ShowCoroFrame, self).__init__("show-coro-frame", gdb.COMMAND_USER)
+ super(GetCoroFrame, self).__init__("get_coro_promise")
- def invoke(self, arg, from_tty):
- argv = gdb.string_to_argv(arg)
- if len(argv) != 1:
- print("usage: show-coro-frame <address of coroutine frame>")
- return
+ def invoke(self, coroutine_hdl_raw):
+ return CoroutineHandlePrinter(coroutine_hdl_raw).promise_ptr
- addr = int(argv[0], 16)
- block = gdb.block_for_pc(long(cast_addr2long_pointer(addr).dereference()))
- if block is None:
- print "block " + str(addr) + " is None."
- return
+ GetCoroFrame()
+
+
+ """
+ Decorator for coroutine frames.
+
+ Used by `CoroutineFrameFilter` to add the coroutine frames to the built-in `bt` command.
+ """
+ class CoroutineFrameDecorator(FrameDecorator):
+ def __init__(self, coro_frame: DevirtualizedCoroFrame, inferior_frame: gdb.Frame):
+ super(CoroutineFrameDecorator, self).__init__(inferior_frame)
+ self.coro_frame = coro_frame
+
+ def function(self):
+ func_name = self.coro_frame.get_function_name()
+ if func_name is not None:
+ return "[async] " + func_name
+ return "[async] coroutine (coro_frame=" + str(self.coro_frame.frame_ptr_raw) + ")"
+
+ def address(self):
+ return None
+
+ def filename(self):
+ if self.coro_frame.destroy_func is not None:
+ return self.coro_frame.destroy_func.function.symtab.filename
+ return None
+
+ def line(self):
+ if self.coro_frame.resume_label is not None:
+ return self.coro_frame.resume_label.line
+ return None
+
+ def frame_args(self):
+ return []
+
+ def frame_locals(self):
+ return []
+
+
+ def _get_continuation(promise: gdb.Value) -> DevirtualizedCoroFrame | None:
+ try:
+ # TODO: adjust this according for your coroutine framework
+ return DevirtualizedCoroFrame(_extract_coro_frame_ptr_from_handle(promise["continuation"]))
+ except Exception as e:
+ return None
- # Disable demangling since gdb will treat names starting with `_Z`(The marker for Itanium ABI) specially.
- gdb.execute("set demangle-style none")
- coro_frame_type = gdb.lookup_type(block.function.linkage_name + ".coro_frame_ty")
- coro_frame_ptr_type = coro_frame_type.pointer()
- coro_frame = gdb.Value(addr).cast(coro_frame_ptr_type).dereference()
+ def _create_coroutine_frames(coro_frame: DevirtualizedCoroFrame, inferior_frame: gdb.Frame):
+ while coro_frame is not None:
+ yield CoroutineFrameDecorator(coro_frame, inferior_frame)
+ coro_frame = _get_continuation(coro_frame.promise_ptr)
- gdb.execute("set demangle-style auto")
- gdb.write(coro_frame.format_string(pretty_structs = True))
- ShowCoroFrame()
+ """
+ Frame filter to add coroutine frames to the built-in `bt` command.
+ """
+ class CppCoroutineFrameFilter():
+ def __init__(self):
+ self.name = "CppCoroutineFrameFilter"
+ self.priority = 50
+ self.enabled = True
+ # Register this frame filter with the global frame_filters dictionary.
+ gdb.frame_filters[self.name] = self
+
+ def filter(self, frame_iter: typing.Iterable[gdb.FrameDecorator]):
+ for frame in frame_iter:
+ yield frame
+ inferior_frame = frame.inferior_frame()
+ try:
+ promise_ptr = inferior_frame.read_var("__promise")
+ except Exception:
+ continue
+ parent_coro = _get_continuation(promise_ptr)
+ if parent_coro is not None:
+ yield from _create_coroutine_frames(parent_coro, inferior_frame)
+
+ CppCoroutineFrameFilter()
Further Reading
---------------
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 9a0d69c..99aa545 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -357,6 +357,11 @@ Improvements to Clang's diagnostics
properly being rejected when used at compile-time. It was not implemented
and caused assertion failures before (#GH158471).
+- Closed a loophole in the diagnosis of function pointer conversions changing
+ extended function type information in C mode (#GH41465). Function conversions
+ that were previously incorrectly accepted in case of other irrelevant
+ conditions are now consistently diagnosed, identical to C++ mode.
+
Improvements to Clang's time-trace
----------------------------------
@@ -455,6 +460,7 @@ Bug Fixes to C++ Support
- Fix a crash when attempting to deduce a deduction guide from a non deducible template template parameter. (#130604)
- Fix for clang incorrectly rejecting the default construction of a union with
nontrivial member when another member has an initializer. (#GH81774)
+- Diagnose unresolved overload sets in non-dependent compound requirements. (#GH51246) (#GH97753)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index 12c2ada..5745e4b 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -2778,7 +2778,7 @@ usual build cycle when using sample profilers for optimization:
> clang-cl /O2 -gdwarf -gline-tables-only ^
/clang:-fdebug-info-for-profiling /clang:-funique-internal-linkage-names ^
- code.cc /Fe:code /fuse-ld=lld /link /debug:dwarf
+ code.cc /Fe:code -fuse-ld=lld /link /debug:dwarf
.. note::
@@ -2861,13 +2861,15 @@ usual build cycle when using sample profilers for optimization:
that executes faster than the original one. Note that you are not
required to build the code with the exact same arguments that you
used in the first step. The only requirement is that you build the code
- with the same debug info options and ``-fprofile-sample-use``.
+ with the same debug info options and ``-fprofile-sample-use``. ``-gdwarf``
+ and ``-gline-tables-only`` can be omitted if you do not need debug info
+ in the final binary.
On Linux:
.. code-block:: console
- $ clang++ -O2 -gline-tables-only \
+ $ clang++ -O2 \
-fdebug-info-for-profiling -funique-internal-linkage-names \
-fprofile-sample-use=code.prof code.cc -o code
@@ -2875,9 +2877,9 @@ usual build cycle when using sample profilers for optimization:
.. code-block:: winbatch
- > clang-cl /O2 -gdwarf -gline-tables-only ^
+ > clang-cl /O2 ^
/clang:-fdebug-info-for-profiling /clang:-funique-internal-linkage-names ^
- -fprofile-sample-use=code.prof code.cc /Fe:code -fuse-ld=lld /link /debug:dwarf
+ -fprofile-sample-use=code.prof code.cc /Fe:code
[OPTIONAL] Sampling-based profiles can have inaccuracies or missing block/
edge counters. The profile inference algorithm (profi) can be used to infer
@@ -2886,7 +2888,7 @@ usual build cycle when using sample profilers for optimization:
.. code-block:: console
- $ clang++ -fsample-profile-use-profi -O2 -gline-tables-only \
+ $ clang++ -fsample-profile-use-profi -O2 \
-fdebug-info-for-profiling -funique-internal-linkage-names \
-fprofile-sample-use=code.prof code.cc -o code
@@ -2894,9 +2896,9 @@ usual build cycle when using sample profilers for optimization:
.. code-block:: winbatch
- > clang-cl /clang:-fsample-profile-use-profi /O2 -gdwarf -gline-tables-only ^
+ > clang-cl /clang:-fsample-profile-use-profi /O2 ^
/clang:-fdebug-info-for-profiling /clang:-funique-internal-linkage-names ^
- -fprofile-sample-use=code.prof code.cc /Fe:code -fuse-ld=lld /link /debug:dwarf
+ -fprofile-sample-use=code.prof code.cc /Fe:code
Sample Profile Formats
""""""""""""""""""""""
diff --git a/clang/docs/analyzer/developer-docs/Statistics.rst b/clang/docs/analyzer/developer-docs/Statistics.rst
index 595b44d..4f2484a 100644
--- a/clang/docs/analyzer/developer-docs/Statistics.rst
+++ b/clang/docs/analyzer/developer-docs/Statistics.rst
@@ -22,7 +22,6 @@ However, note that with ``LLVM_ENABLE_STATS`` disabled, only storage of the valu
If you want to define a statistic only for entry point, EntryPointStats.h has four classes at your disposal:
-- ``BoolEPStat`` - a boolean value assigned at most once per entry point. For example: "has the inline limit been reached".
- ``UnsignedEPStat`` - an unsigned value assigned at most once per entry point. For example: "the number of source characters in an entry-point body".
- ``CounterEPStat`` - an additive statistic. It starts with 0 and you can add to it as many times as needed. For example: "the number of bugs discovered".
- ``UnsignedMaxEPStat`` - a maximizing statistic. It starts with 0 and when you join it with a value, it picks the maximum of the previous value and the new one. For example, "the longest execution path of a bug".