[LangRef] clarify the semantics of nocapture

This patch clarifies the semantics of nocapture attribute.

A 'Pointer Capture' subsection is added to describe the semantics of pointer capture first.

For the nocapture example with two same pointer arguments, it is consistent with the semantics that Alive2 used to run lit tests.

Reviewed By: nlopes

Differential Revision: https://reviews.llvm.org/D97924
This commit is contained in:
Juneyoung Lee 2021-04-13 13:57:06 +09:00
parent 98b114d480
commit 1bcadb0984
1 changed files with 89 additions and 5 deletions

View File

@ -1198,12 +1198,23 @@ Currently, only the following parameter attributes are defined:
function, returning a pointer to allocated storage disjoint from the
storage for any other object accessible to the caller.
.. _nocapture:
``nocapture``
This indicates that the callee does not make any copies of the
pointer that outlive the callee itself in any form such as a pointer stored
in the memory or as a return value. This is not a valid
attribute for return values. Addresses used in volatile operations
are considered to be captured.
This indicates that the callee does not :ref:`capture <pointercapture>` the
pointer. This is not a valid attribute for return values.
This attribute applies only to the particular copy of the pointer passed in
this argument. A caller could pass two copies of the same pointer with one
being annotated nocapture and the other not, and the callee could validly
capture through the non annotated parameter.
.. code-block:: llvm
define void @f(i8* nocapture %a, i8* %b) {
; (capture %b)
}
call void @f(i8* @glb, i8* @glb) ; well-defined
``nofree``
This indicates that callee does not free the pointer argument. This is not
@ -2657,6 +2668,79 @@ Consequently, type-based alias analysis, aka TBAA, aka
which specialized optimization passes may use to implement type-based
alias analysis.
.. _pointercapture:
Pointer Capture
---------------
Given a function call and a pointer that is passed as an argument or stored in
the memory before the call, a pointer is *captured* by the call if it makes a
copy of any part of the pointer that outlives the call.
To be precise, a pointer is captured if one or more of the following conditions
hold:
1. The call stores any bit of the pointer carrying information into a place,
and the stored bits can be read from the place by the caller after this call
exits.
.. code-block:: llvm
@glb = global i8* null
@glb2 = global i8* null
@glb3 = global i8* null
@glbi = global i32 0
define i8* @f(i8* %a, i8* %b, i8* %c, i8* %d, i8* %e) {
store i8* %a, i8** @glb ; %a is captured by this call
store i8* %b, i8** @glb2 ; %b isn't captured because the stored value is overwritten by the store below
store i8* null, i8** @glb2
store i8* %c, i8** @glb3
call void @g() ; If @g makes a copy of %c that outlives this call (@f), %c is captured
store i8* null, i8** @glb3
%i = ptrtoint i8* %d to i64
%j = trunc i64 %i to i32
store i32 %j, i32* @glbi ; %d is captured
ret i8* %e ; %e is captured
}
2. The call stores any bit of the pointer carrying information into a place,
and the stored bits can be safely read from the place by another thread via
synchronization.
.. code-block:: llvm
@lock = global i1 true
define void @f(i8* %a) {
store i8* %a, i8** @glb
store atomic i1 false, i1* @lock release ; %a is captured because another
thread can safely read @glb
store i8* null, i8** @glb
ret void
}
3. The call's behavior depends on any bit of the pointer carrying information.
.. code-block:: llvm
@glb = global i8 0
define void @f(i8* %a) {
%c = icmp eq i8* %a, @glb
br i1 %c, BB_EXIT, BB_CONTINUE ; escapes %a
BB_EXIT:
call void exit()
unreachable
BB_CONTINUE:
ret void
}
4. The pointer is used in a volatile access as its address.
.. _volatile:
Volatile Memory Accesses