<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr">> end up generating this IR after optimisation</div><div dir="ltr"><br></div><div>AFAICT, that's the IR before optimization, as seen from `clang -S -emit-llvm -O0 -o - -x c -`.</div><div><br></div><div>> I strongly suggest to emit nocapture with sret in the frontend instead.</div></div><div dir="ltr"><br></div><div>It seems like `clang -x c` doesn't emit nocapture for even trivial cases I tried (like the above, but without function `x`). Is that a bug then, or just not applicable to C?</div><div><br></div><div>Regardless, I don't think this should be a verifier error for passing nocapture to maycapture, since it may be valid for a source language to know that a particular use of an argument is nocapture, even if the general function contract doesn't promise it.</div></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Feb 22, 2021 at 4:51 AM David Chisnall via llvm-dev <<a href="mailto:llvm-dev@lists.llvm.org">llvm-dev@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">On 21/02/2021 18:39, Johannes Doerfert via llvm-dev wrote:<br>
> I strongly suggest to emit nocapture with sret in the frontend<br>
> instead.<br>
<br>
I don't think that is actually feasible. For example, consider this C++ <br>
file:<br>
<br>
```c++<br>
#include <set><br>
<br>
struct Example;<br>
std::set<Example*> live_examples;<br>
struct Example {<br>
Example()<br>
{<br>
live_examples.insert(this);<br>
}<br>
~Example()<br>
{<br>
live_examples.erase(live_examples.find(this));<br>
}<br>
};<br>
<br>
Example somefn()<br>
{<br>
Example e;<br>
return e;<br>
}<br>
```<br>
<br>
In this example, guaranteed copy elision means that somefn allocates `e` <br>
in the space provided for it in the caller, calling the constructor, <br>
which then captures the value. In the generated IR, the space for `e` <br>
has the `sret` attribute but it is definitely not nocapture.<br>
<br>
You can also trigger this in C, though in the C case it is undefined <br>
behaviour. Consider this example:<br>
<br>
```c<br>
struct Foo<br>
{<br>
int a[5];<br>
};<br>
<br>
int x(struct Foo *);<br>
<br>
struct Foo f(void)<br>
{<br>
struct Foo foo;<br>
x(&foo);<br>
return foo;<br>
}<br>
```<br>
<br>
The source-language semantics guarantee that no pointers to `foo` <br>
outlive the invocation of `f`, which implies that `x` must not capture <br>
the argument. The optimisers take advantage of the fact that it would <br>
be UB to compare the address of foo after the end of `f` to any other <br>
allocation and we end up generating this IR after optimisation, eliding <br>
the copy:<br>
<br>
```<br>
; Function Attrs: nounwind uwtable<br>
define dso_local void @f(%struct.Foo* noalias sret(%struct.Foo) align 4 <br>
%0) local_unnamed_addr #0 {<br>
%2 = tail call i32 @x(%struct.Foo* %0) #2<br>
ret void<br>
}<br>
```<br>
<br>
Nothing in the IR says that `x`'s argument is nocapture. Whether this <br>
is permitted depends on what we want nocapture to mean. There are two <br>
possible interpretations:<br>
<br>
- The callee does not capture the argument, if the callee does capture <br>
the argument then the IR is ill-formed and we have a compiler bug.<br>
- The caller is free to assume that the callee does not capture the <br>
argument, if the callee does capture the argument then it is UB.<br>
<br>
The former allows the absence of nocapture to be interpreted as 'we <br>
can't statically prove that the argument is not captured'. This is very <br>
useful for memory-safety work, because it allows us to trust `nocapture` <br>
as a security property: we can emit any further analysis.<br>
<br>
The latter allows optimisations to be more aggressive but will sometimes <br>
generate more surprising code for users and may break some security <br>
properties if security-related transforms depend on this information.<br>
<br>
My personal bias is towards the former: we would like to be able to use <br>
`nocapture` in stack temporal safety work as a strong guarantee. As <br>
such, the front end could not insert it because transforms may later <br>
insert a capture. Alternatively, the module verifier should be updated <br>
to ensure that a nocapture argument is not passed to any other function <br>
except via a nocapture argument.<br>
<br>
David<br>
<br>
<br>
_______________________________________________<br>
LLVM Developers mailing list<br>
<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev</a><br>
</blockquote></div>