<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On Aug 25, 2020, at 4:16 PM, Richard Smith via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" class="">cfe-dev@lists.llvm.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div dir="auto" class=""><div class=""><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, 25 Aug 2020, 10:53 Florian Hahn via cfe-dev, <<a href="mailto:cfe-dev@lists.llvm.org" target="_blank" class="">cfe-dev@lists.llvm.org</a>> wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi,<br class="">
<br class="">
It appears that Clang generates calls to `llvm.memcpy` with potentially overlapping arguments in some cases.<br class="">
<br class="">
For the snippet below<br class="">
<br class="">
struct S<br class="">
{<br class="">
char s[25];<br class="">
};<br class="">
<br class="">
struct S *p;<br class="">
<br class="">
void test2() {<br class="">
...<br class="">
foo (&b, 1);<br class="">
b = a;<br class="">
b = *p;<br class="">
...<br class="">
}<br class="">
<br class="">
<br class="">
Clang uses `llvm.memcpy` to copy the struct:<br class="">
<br class="">
call void @foo(%struct.S* %2, i32 1)<br class="">
%7 = bitcast %struct.S* %2 to i8*<br class="">
%8 = bitcast %struct.S* %1 to i8*<br class="">
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %7, i8* align 1 %8, i64 25, i1 false)<br class="">
%9 = load %struct.S*, %struct.S** @p, align 8<br class="">
%10 = bitcast %struct.S* %2 to i8*<br class="">
%11 = bitcast %struct.S* %9 to i8*<br class="">
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %10, i8* align 1 %11, i64 25, i1 false)<br class="">
<br class="">
<br class="">
In the C example, `foo` could set `p = &b` and then `b = *p` would just copy the contents from `b` into `b`. This means that the the arguments to the second llvm.memcpy call may overlap, which seems not allowed according to the current version of the LangRef (<a href="https://llvm.org/docs/LangRef.html#llvm-memcpy-intrinsic" rel="noreferrer noreferrer" target="_blank" class="">https://llvm.org/docs/LangRef.html#llvm-memcpy-intrinsic</a>). This is problematic, because the fact is used in BasicAliasAnalysis for example (<a href="https://github.com/llvm/llvm-project/blob/master/llvm/lib/Analysis/BasicAliasAnalysis.cpp#L982" rel="noreferrer noreferrer" target="_blank" class="">https://github.com/llvm/llvm-project/blob/master/llvm/lib/Analysis/BasicAliasAnalysis.cpp#L982</a>).<br class="">
<br class="">
The full, build-able example can be found here: <a href="https://godbolt.org/z/PY1vKq" rel="noreferrer noreferrer" target="_blank" class="">https://godbolt.org/z/PY1vKq</a><br class="">
<br class="">
I might be missing something, but it appears that Clang should not create call to `llvm.memcpy` unless it can guarantee the arguments cannot overlap. I am not sure what the best alternative to `llvm.memcpy` would be in case the arguments overlap.<br class=""></blockquote></div></div><div dir="auto" class=""><br class=""></div><div dir="auto" class="">To be clear: the concern here is that the source and destination could be equal, not that they might partially overlap (which I'm pretty sure the relevant language rules disallow)?</div><div dir="auto" class=""><br class=""></div><div dir="auto" class="">This seems reminiscent of the issue that memcpy is formally undefined if given a size of zero and a null pointer argument, for which we changed the rules for @llvm.memcpy to define the behaviour in that case. Can we do the same here (or at least add another LLVM intrinsic that permits exact overlap, but not partial overlap)? Note that both GCC and Clang have pretty much always generated a memcpy for cases such as:</div><div dir="auto" class=""><br class=""></div><div dir="auto" class="">struct A { char buff[999999]; };</div><div dir="auto" class="">void f(struct A *p, struct A *q) { *p = *q; }<br class=""></div><div dir="auto" class=""><br class=""></div><div class="">in both C and C++ modes, and MSVC and ICC do roughly the same thing when optimizing (though in ICC's case it invokes an intel-specific function, and who knows if that explicitly defines the behavior for exact overlap), so one would imagine that if there are any memcpy implementations for which memcpy(p, p, n) doesn't work, we'd have seen program misbehavior by now. As a consequence, as with the memcpy(0, 0, 0) case, LLVM can probably lower a memcpy-with-exact-overlap-permitted to a memcpy libcall on ~all targets.</div></div></div></div></blockquote><div><br class=""></div><div>This was also discussed in <a href="https://bugs.llvm.org/show_bug.cgi?id=11763" class="">https://bugs.llvm.org/show_bug.cgi?id=11763</a>, I’ll copy and paste James’ comment at the end, which seems reasonable and also confirms the partial-overlap case is not an issue:</div><div><br class=""></div><div>***</div><div><div class="bz_comment_head" style="padding-top: 0.1em; padding-bottom: 0.1em; padding-left: 0.5em; background-color: rgb(224, 224, 224); font-family: Verdana, sans-serif;"><span class="bz_comment_user" style="margin: 0px 0.5em;"><span class="vcard"><span class="fn">James Y Knight</span> </span></span><span class="bz_comment_user_images"></span><span class="bz_comment_time" style="margin: 0px 0.5em;">2018-07-19 11:19:11 PDT</span></div><pre class="bz_comment_text" style="font-size: medium; white-space: pre-wrap; width: 50em;">In light of the last updates, it sounds like what's required here is just a documentation update.
1. LLVM requires that the platform provide a memcpy function which works when the two pointers are equal. That is not a requirement of the C standard for the user-visible memcpy function, but it is a requirement that LLVM has on platforms it compiles code for.
If there are any platform which provides a memcpy which does not satisfy that requirement, I believe that platform needs to be modified, not LLVM. I'd be surprised if there were any such platforms, since GCC has the same requirement.
2. Likewise, the same requirement exists for the llvm.memcpy IR intrinsic. The LangRef should be updated to state that.
3. Partially-overlapping calls from struct assignment are UB, so we're fine there, such issues correspond to actual bugs in user-code.</pre><div class="">***</div><div class=""><br class=""></div><div class="">Unless anyone disagrees with that approach, or anything has changed since, Florian perhaps you could update the relevant documentation via the noalias patch I believe you were working on, since this is in that same family of issues?</div><div class=""><br class=""></div><div class="">Dave</div><div class=""><br class=""></div></div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div dir="auto" class=""><div dir="auto" class=""><br class=""></div><div dir="auto" class=""><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Cheers,<br class="">
Florian<br class="">
_______________________________________________<br class="">
cfe-dev mailing list<br class="">
<a href="mailto:cfe-dev@lists.llvm.org" rel="noreferrer" target="_blank" class="">cfe-dev@lists.llvm.org</a><br class="">
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer noreferrer" target="_blank" class="">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br class="">
</blockquote></div></div></div>
</div>
_______________________________________________<br class="">cfe-dev mailing list<br class=""><a href="mailto:cfe-dev@lists.llvm.org" class="">cfe-dev@lists.llvm.org</a><br class="">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev<br class=""></div></blockquote></div><br class=""></body></html>