<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Fri, May 6, 2016 at 2:42 PM, David Majnemer <span dir="ltr"><<a href="mailto:david.majnemer@gmail.com" target="_blank">david.majnemer@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><div class="h5">On Fri, May 6, 2016 at 2:36 PM, Richard Smith via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><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"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span>On Fri, May 6, 2016 at 1:56 PM, Ettore Speziale via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><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">Hello,<br>
<span><br>
> In the case of foo, there could be a problem.<br>
> If you do not mark it convergent, the LLVM sink pass push the call to foo to the then branch of the ternary operator, hence the program has been incorrectly optimized.<br>
><br>
> Really? It looks like the problem is that you lied to the compiler by marking the function as 'pure'. The barrier is a side-effect that cannot be removed or duplicated, so it's not correct to mark this function as pure.<br>
<br>
</span>I was trying to write a very small example to trick LLVM and trigger the optimization. It is based on Transforms/Sink/convergent.ll:<br>
<br>
define i32 @foo(i1 %arg) {<br>
entry:<br>
  %c = call i32 @bar() readonly convergent<br>
  br i1 %arg, label %then, label %end<br>
<br>
then:<br>
  ret i32 %c<br>
<br>
end:<br>
  ret i32 0<br>
}<br>
<br>
declare i32 @bar() readonly convergent<br></blockquote><div><br></div></span><div>This example looks wrong to me. It doesn't seem meaningful for a function to be both readonly and convergent, because convergent means the call has some side-effect visible to other threads and readonly means the call has no side-effects visible outside the function.</div><span><div><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">
Here is another example:<br>
<br>
void foo0(void);<br>
void foo1(void);<br>
<br>
__attribute__((convergent)) void baz() {<br>
  barrier(CLK_GLOBAL_MEM_FENCE);<br>
}<br>
<br>
void bar(int x, global int *y) {<br>
  if (x < 5)<br>
    foo0();<br>
  else<br>
    foo1();<br>
<br>
  baz();<br>
<br>
  if (x < 5)<br>
    foo0();<br>
  else<br>
    foo1();<br>
}<br></blockquote><div><br></div></span><div>This one looks a lot more interesting. It looks like 'convergent' is a way of informing LLVM that the call cannot be duplicated, yes? That being the case, how is this attribute different from the existing [[clang::noduplicate]] / __attribute__((noduplicate)) attribute?</div></div></div></div></blockquote><div><br></div></div></div><div>I think it has more to do with LLVM's definition of convergent: that you really do not want control dependencies changing for a callsite.</div></div></div></div></blockquote><div><br></div><div>Hmm, so we can't transform:</div><div><br></div><div>  %a = complex_pure_operation1</div><div>  %b = complex_pure_operation2<br></div><div>  %c = select i1 %x, i32 %a, i32 %b</div><div>  call void @foo(i32 %c) convergent</div><div><br></div><div>... into ...</div><div><br></div><div>  br i1 %x, label %aa, label %bb</div><div><br></div><div>aa:</div><div><div>  %a = complex_pure_operation1</div><div>  br label %cont</div><div><br></div><div>bb:</div><div>  %b = complex_pure_operation2<br></div><div>  br label %cont</div><div><br></div><div>cont:</div><div>  %c = phi i32 [ %a, %aa ],  [ %b, %bb ]</div><div>  call void @foo(i32 %c) convergent</div></div><div><br></div><div>?</div><div><br></div><div>It looks like we added the noduplicate attribute to clang to support OpenCL's barrier function. Did we get the semantics for it wrong for its intended use case?</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><a href="http://llvm.org/docs/LangRef.html#function-attributes" target="_blank">http://llvm.org/docs/LangRef.html#function-attributes</a><br></div><div><div class="h5"><div> </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"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><div><div><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">
Based on Transforms/JumpThreading/basic.ll:<br>
<br>
define void @h_con(i32 %p) {<br>
  %x = icmp ult i32 %p, 5<br>
  br i1 %x, label %l1, label %l2<br>
<br>
l1:<br>
  call void @j()<br>
  br label %l3<br>
<br>
l2:<br>
  call void @k()<br>
  br label %l3<br>
<br>
l3:<br>
; CHECK: call void @g() [[CON:#[0-9]+]]<br>
; CHECK-NOT: call void @g() [[CON]]<br>
  call void @g() convergent<br>
  %y = icmp ult i32 %p, 5<br>
  br i1 %y, label %l4, label %l5<br>
<br>
l4:<br>
  call void @j()<br>
  ret void<br>
<br>
l5:<br>
  call void @k()<br>
  ret void<br>
; CHECK: }<br>
}<br>
<br>
If you do not mark baz convergent, you get this:<br>
<br>
clang -x cl -emit-llvm -S -o - test.c -O0 | opt -mem2reg -jump-threading -S<br>
<br>
define void @bar(i32 %x) #0 {<br>
entry:<br>
  %cmp = icmp slt i32 %x, 5<br>
  br i1 %cmp, label %if.then2, label %if.else3<br>
<br>
if.then2:                                         ; preds = %entry<br>
  call void @foo0()<br>
  call void @baz()<br>
  call void @foo0()<br>
  br label %if.end4<br>
<br>
if.else3:                                         ; preds = %entry<br>
  call void @foo1()<br>
  call void @baz()<br>
  call void @foo1()<br>
  br label %if.end4<br>
<br>
if.end4:                                          ; preds = %if.else3, %if.then2<br>
  ret void<br>
}<br>
<br>
Which is illegal, as the value of x might not be the same for all work-items.<br>
<br>
I’ll update the patch such as:<br>
<br>
* it uses the example about jump-threading<br>
* it marks the attribute available in OpenCL/Cuda<br>
* it provides the [[clang::convergent]] attribute<br>
<br>
Thanks,<br>
Ettore Speziale<br>
<div><div><br>
--------------------------------------------------<br>
Ettore Speziale — Compiler Engineer<br>
<a href="mailto:speziale.ettore@gmail.com" target="_blank">speziale.ettore@gmail.com</a><br>
<a href="mailto:espeziale@apple.com" target="_blank">espeziale@apple.com</a><br>
--------------------------------------------------<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</div></div></blockquote></div></div></div><br></div></div>
<br>_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
<br></blockquote></div></div></div><br></div></div>
</blockquote></div><br></div></div>