<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Hi Roman,</div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><blockquote type="cite" class=""><div class=""><span class="" style="float: none; display: inline !important;">Is "test" actually an implementation of a 64-bit-wide multiplication</span><br class=""><span class="" style="float: none; display: inline !important;">compiler-rt builtin?</span><br class=""><span class="" style="float: none; display: inline !important;">Then i'd think the main problem is that it is being optimized in the</span><br class=""><span class="" style="float: none; display: inline !important;">first place, you could end up with endless recursion…</span></div></blockquote><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">No, this is not a compiler-rt builtin. My example is of course incidentally taken from the implementation of a signed multiply, but as said, it has nothing to do with rt-builtins, I'm just using that code to show the issue. This function can’t create a recursion because it’s named ’test’, unlike any rt-buitin. You can replace the multiply in the source code by an addition, if you want to avoid calling rt-functions, but this does not change what I attempt to show. Also It’s not meant to be 64 bit wide, but 32 bit wide, because the targets I’m testing are 16 bit, so ints are 16 bit and longs are 32 bit. This is again the function I am testing:</div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class=""><span style="color: #ba2da2" class="">long</span> test (<span style="color: #ba2da2" class="">long</span> a, <span style="color: #ba2da2" class="">long</span> b) </div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">{ </div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  <span style="color: #ba2da2" class="">int</span> neg = <span style="color: #272ad8" class="">0</span>;</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  <span style="color: #ba2da2" class="">long</span> res; </div><div style="margin: 0px; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  <span style="color: #ba2da2" class="">if</span> (a < <span style="color: #272ad8" class="">0</span>)</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  {</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">    a = -a;  </div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">    neg = <span style="color: #272ad8" class="">1</span>;</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  }</div><div style="margin: 0px; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  <span style="color: #ba2da2" class="">if</span> (b < <span style="color: #272ad8" class="">0</span>)</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  {</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">    b = -b;</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">    neg = !neg;</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  }</div><div style="margin: 0px; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  res = a*b;</div><div style="margin: 0px; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  <span style="color: #ba2da2" class="">if</span> (neg)</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">    res = -res;</div><div style="margin: 0px; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  <span style="color: #ba2da2" class="">return</span> res;</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">}</div></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><blockquote type="cite" class=""><div class=""><span class="" style="display: inline !important;">LLVM, not clang.</span></div></blockquote><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">I’m not sure about what you mean by that. The shown LLVM IR code is created by executing "clang” command line, so that’s what I attempt to show. So it’s actually the front-end that does such undesired optimisations sometimes, not only the LLVM back-end. This is in part why I am saying this is not right. See copied again the IR code that gets generated for the C code that I posted before. This IR code, including the presence of expensive shifts ( <span style="font-family: Monaco; font-size: 11px; background-color: rgb(255, 255, 255);" class="">%a.lobit = lshr i32 %a, 31)</span>  is generated when <span style="font-family: Monaco; font-size: 11px; background-color: rgb(255, 255, 255);" class="">-mllvm -phi-node-folding-threshold=1 </span>is specified in the command line, or when the Target implements <span style="font-family: Monaco; font-size: 11px; background-color: rgb(255, 255, 255);" class="">getOperationCost(</span><span style="font-family: Monaco; font-size: 11px; background-color: rgb(255, 255, 255); color: rgb(186, 45, 162);" class="">unsigned</span><span style="font-family: Monaco; font-size: 11px; background-color: rgb(255, 255, 255);" class=""> Opcode, </span><span style="font-family: Monaco; font-size: 11px; background-color: rgb(255, 255, 255); color: rgb(79, 129, 135);" class="">Type</span><span style="font-family: Monaco; font-size: 11px; background-color: rgb(255, 255, 255);" class=""> *Ty, </span><span style="font-family: Monaco; font-size: 11px; background-color: rgb(255, 255, 255); color: rgb(79, 129, 135);" class="">Type</span><span style="font-family: Monaco; font-size: 11px; background-color: rgb(255, 255, 255);" class=""> *OpTy)</span> to return <span style="color: rgb(49, 89, 93); font-family: Monaco; font-size: 11px; background-color: rgb(255, 255, 255);" class="">TCC_Expensive </span>for operator types that are bigger than the default target register size. </div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><span style="font-family: Monaco; font-size: 11px; background-color: rgb(255, 255, 255);" class=""><br class=""></span></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><span style="font-family: Monaco; font-size: 11px; background-color: rgb(255, 255, 255);" class=""><br class=""></span></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">; ModuleID = 'main.c'</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">source_filename = "main.c"</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">target datalayout = "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16"</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">target triple = "msp430"</div><div style="margin: 0px; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">; Function Attrs: norecurse nounwind optsize readnone</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">define dso_local i32 @test(i32 %a, i32 %b) local_unnamed_addr #0 {</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">entry:</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  %cmp = icmp slt i32 %a, 0</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  %sub = sub nsw i32 0, %a</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  %spec.select = select i1 %cmp, i32 %sub, i32 %a</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  %a.lobit = lshr i32 %a, 31</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  %0 = trunc i32 %a.lobit to i16</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  %cmp1 = icmp slt i32 %b, 0</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  br i1 %cmp1, label %if.then2, label %if.end4</div><div style="margin: 0px; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">if.then2:                                         ; preds = %entry</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  %sub3 = sub nsw i32 0, %b</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  %1 = xor i16 %0, 1</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  br label %if.end4</div><div style="margin: 0px; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">if.end4:                                          ; preds = %if.then2, %entry</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  %b.addr.0 = phi i32 [ %sub3, %if.then2 ], [ %b, %entry ]</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  %neg.1 = phi i16 [ %1, %if.then2 ], [ %0, %entry ]</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  %mul = mul nsw i32 %b.addr.0, %spec.select</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  %tobool5 = icmp eq i16 %neg.1, 0</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  %sub7 = sub nsw i32 0, %mul</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  %spec.select18 = select i1 %tobool5, i32 %mul, i32 %sub7</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  ret i32 %spec.select18</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">}</div><div style="margin: 0px; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">attributes #0 = { norecurse nounwind optsize readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }</div><div style="margin: 0px; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">!llvm.module.flags = !{!0}</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">!llvm.ident = !{!1}</div><div style="margin: 0px; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">!0 = !{i32 1, !"wchar_size", i32 2}</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">!1 = !{!"clang version 9.0.0 (<a href="https://github.com/llvm/llvm-project.git" class="">https://github.com/llvm/llvm-project.git</a> 6f7deba43dd25fb7b3eca70f9c388ec9174f455a)"}</div><div class=""><br class=""></div></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">As you can see, Clang produces a 31 bit wide shift right ( <span style="background-color: rgb(255, 255, 255);" class=""><font face="Monaco" class=""><span style="font-size: 11px;" class="">%a.lobit = lshr i32 %a, 31) </span></font></span>That’s the fourth instruction on the IR code above. So a shift is produced instead of creating a jump to a new block, as it should be the case as per the C source code.</div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Just as a matter of information. This is the implementation of the getOperationCost function that causes ‘clang’ to correctly replace selects by branches (desirable), but to generate shifts to fold expensive selects (undesirable)</div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class=""><span style="color: #ba2da2" class="">unsigned</span> <span style="color: #4f8187" class="">CPU74TTIImpl</span>::getOperationCost(<span style="color: #ba2da2" class="">unsigned</span> Opcode, <span style="color: #4f8187" class="">Type</span> *Ty, <span style="color: #4f8187" class="">Type</span> *OpTy)</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">{</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; color: rgb(0, 132, 0); background-color: rgb(255, 255, 255);" class=""><span style="color: #000000" class="">  </span>// Big types are expensive</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; color: rgb(49, 89, 93); background-color: rgb(255, 255, 255);" class=""><span style="color: #000000" class="">  </span><span style="color: #ba2da2" class="">unsigned</span><span style="color: #000000" class=""> OpSize = Ty-></span>getScalarSizeInBits<span style="color: #000000" class="">();</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  <span style="color: #ba2da2" class="">if</span> ( OpSize > <span style="color: #272ad8" class="">16</span> )</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; color: rgb(49, 89, 93); background-color: rgb(255, 255, 255);" class=""><span style="color: #000000" class="">    </span><span style="color: #ba2da2" class="">return</span><span style="color: #000000" class=""> </span><span style="color: #4f8187" class="">TTI</span><span style="color: #000000" class="">::</span>TCC_Expensive<span style="color: #000000" class="">;</span></div><div style="margin: 0px; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">  <span style="color: #ba2da2" class="">return</span> <span style="color: #4f8187" class="">BaseT</span>::<span style="color: #31595d" class="">getOperationCost</span>(Opcode, Ty, OpTy);</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">}</div></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">If the getOperationCost above function was not implemented, then clang would generate the usual series of ‘selects’. But this is even worse because selects imply speculative execution of expensive instructions, or duplicate branching created by the backend, which can’t be easily avoided.</div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Ideally, the IR code above should just place an ‘if.then' block for the <span style="font-family: Monaco; font-size: 11px; background-color: rgb(255, 255, 255); color: rgb(186, 45, 162);" class="">if</span><span style="font-family: Monaco; font-size: 11px; background-color: rgb(255, 255, 255);" class=""> (a < </span><span style="font-family: Monaco; font-size: 11px; background-color: rgb(255, 255, 255); color: rgb(39, 42, 216);" class="">0</span><span style="font-family: Monaco; font-size: 11px; background-color: rgb(255, 255, 255);" class="">)</span> statement in the C source code, instead of attempting to replace a select by a shift (!)</div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">If you want to play with these two scenarios, (1) IR code generated with branches, and (2) IR code generated with selects. This can easily be reproduced for the MSP430 target by compiling with the following options</div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">(1)  <span style="font-family: Monaco; font-size: 11px; background-color: rgb(255, 255, 255);" class="">-mllvm -phi-node-folding-threshold=1 -c -S -Os</span>  </div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">(2)  <span style="font-family: Monaco; font-size: 11px; background-color: rgb(255, 255, 255);" class="">-mllvm -phi-node-folding-threshold=2 -c -S -Os</span></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">For 16 bit targets without selects, or expensive selects, the overall code is better with (1) because that prevents the creation of a different jump for every ‘select’ that (2) would cause. However, the presence of the ‘shift’ instruction for (1) spoils it all. </div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Again, ideally, the use of shifts as a replacement of selects should be avoided, and an “if.then" block should be used as per the original C code.</div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">I hope this is clear now.</div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">John.</div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On 29 Sep 2019, at 15:57, Roman Lebedev <<a href="mailto:lebedev.ri@gmail.com" class="">lebedev.ri@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">On Sun, Sep 29, 2019 at 3:35 PM Joan Lluch via llvm-dev</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""><</span><a href="mailto:llvm-dev@lists.llvm.org" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">llvm-dev@lists.llvm.org</a><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">> wrote:</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class=""><br class="">Hi Sanjay,<br class=""><br class="">Actually, the CodeGenPrepare::optimizeSelectInst is not doing the best it could do in some circumstances: The case of “OptSize" for targets not supporting Select was already mentioned to be detrimental.<br class=""><br class="">For targets that actually have selects, but branches are cheap and generally profitable, particularly for expensive operators, the optimizeSelectInst function does not do good either. The function tries to identify consecutive selects with the same condition in order to avoid duplicate branches, which is ok, but then this effort is discarded in isFormingBranchFromSelectProfitable because the identified condition is used more than once (on the said two consecutive selects, of course), which defeats the whole purpose of checking for them, resulting in poor codegen.<br class=""><br class="">Yet another issue is that Clang attempts to replace ‘selects’ in the source code, by supposedly optimised code that is not ok for all targets. One example is this:<br class=""></blockquote><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">LLVM, not clang.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">long test (long a, long b)<br class="">{<br class=""> int neg = 0;<br class=""> long res;<br class=""><br class=""> if (a < 0)<br class=""> {<br class="">   a = -a;<br class="">   neg = 1;<br class=""> }<br class=""><br class=""> if (b < 0)<br class=""> {<br class="">   b = -b;<br class="">   neg = !neg;<br class=""> }<br class=""><br class=""> res = a*b; //(unsigned long)a / (unsigned long)b;  // will call __udivsi3<br class=""><br class=""> if (neg)<br class="">   res = -res;<br class=""><br class=""> return res;<br class="">}<br class=""><br class=""><br class="">This gets compiled into<br class=""><br class="">; Function Attrs: norecurse nounwind readnone<br class="">define dso_local i32 @test(i32 %a, i32 %b) local_unnamed_addr #0 {<br class="">entry:<br class=""> %cmp = icmp slt i32 %a, 0<br class=""> %sub = sub nsw i32 0, %a<br class=""> %a.addr.0 = select i1 %cmp, i32 %sub, i32 %a<br class=""> %a.lobit = lshr i32 %a, 31<br class=""> %0 = trunc i32 %a.lobit to i16<br class=""> %cmp1 = icmp slt i32 %b, 0<br class=""> br i1 %cmp1, label %if.then2, label %if.end4<br class=""><br class="">if.then2:                                         ; preds = %entry<br class=""> %sub3 = sub nsw i32 0, %b<br class=""> %1 = xor i16 %0, 1<br class=""> br label %if.end4<br class=""><br class="">if.end4:                                          ; preds = %if.then2, %entry<br class=""> %b.addr.0 = phi i32 [ %sub3, %if.then2 ], [ %b, %entry ]<br class=""> %neg.1 = phi i16 [ %1, %if.then2 ], [ %0, %entry ]<br class=""> %mul = mul nsw i32 %b.addr.0, %a.addr.0<br class=""> %tobool5 = icmp eq i16 %neg.1, 0<br class=""> %sub7 = sub nsw i32 0, %mul<br class=""> %res.0 = select i1 %tobool5, i32 %mul, i32 %sub7<br class=""> ret i32 %res.0<br class="">}<br class=""><br class="">The offending part here is this:  %a.lobit = lshr i32 %a, 31 . Instead of just creating a “select” instruction, as the original code suggested with the if (a < 0) { neg = 1;} statements, the front-end produces a lshr which is very expensive for small architectures, and makes it very difficult for the backend to fold it again into an actual select (or branch). In my opinion, the original C code should have produced a “select” and give the backend the opportunity to optimise it if required. I think that the frontend should perform only target independent optimisations.<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">You didn't specify how you compile that code.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">We could also get:<span class="Apple-converted-space"> </span></span><a href="https://godbolt.org/z/B-5lj1" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">https://godbolt.org/z/B-5lj1</a><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Which can actually be folded further to just</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""> long test(long a, long b) {</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">   return a * b;</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""> }</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Is "test" actually an implementation of a 64-bit-wide multiplication</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">compiler-rt builtin?</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Then i'd think the main problem is that it is being optimized in the</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">first place, you could end up with endless recursion...</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">I posted before my view that LLVM is clearly designed to satisfy big boys such as the x86 and ARM targets. This means that, unfortunately, it makes too many general assumptions about what’s cheap, without providing enough hooks to cancel arbitrary optimisations. As I am implementing backends for 8 or 16 bit targets, I find myself doing a lot of work just to reverse optimisations that should have not been applied in the first place. My example above is an instance of a code mutation performed by the frontend that is not desirable. Existing 8 and 16 bit trunk targets (particularly the MSP430 and the AVR) are also negatively affected by the excessively liberal use of shifts by LLVM.<br class=""><br class="">The CodeGenPrepare::optimizeSelectInst function needs some changes to respect targets with no selects, and targets that may want to avoid expensive speculative executions.<br class=""><br class="">John<br class=""></blockquote><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Roman</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">On 25 Sep 2019, at 16:00, Sanjay Patel <<a href="mailto:spatel@rotateright.com" class="">spatel@rotateright.com</a>> wrote:<br class=""><br class="">Changing the order of the checks in CodeGenPrepare::optimizeSelectInst() sounds good to me.<br class=""><br class="">But you may need to go further for optimum performance. For example, we may be canonicalizing math/logic IR patterns into 'select' such as in the recent:<br class=""><a href="https://reviews.llvm.org/D67799" class="">https://reviews.llvm.org/D67799</a><br class=""><br class="">So if you want those to become ALU ops again rather than branches, then you need to do the transform later in the backend. That is, you want to let DAGCombiner run its set of transforms on 'select' nodes.<br class=""><br class="">On Wed, Sep 25, 2019 at 4:03 AM Joan Lluch via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" class="">cfe-dev@lists.llvm.org</a>> wrote:<br class=""><blockquote type="cite" class=""><br class="">Hi Craig,<br class=""><br class="">Thank you for your reply. I have started looking at “CodeGenPrepare” and I assume you reffer to CodeGenPrepare::optimizeSelectInst. I will try to play a bit with that possibly later today. At first glance, it looks to me that for targets that do not support ’select’ at all, the fact that the function exits early for ‘OptSize’ can be detrimental, because this will just leave ALL existing selects in the code anyway. As said, I will try to play with that later, but right now it looks to me that maybe we should check  for TLI->isSelectSupported earlier in the function, to get some more opportunities to such targets without explicit ’select’ support?<br class=""><br class="">Thanks<br class=""><br class="">John<br class=""><br class=""><br class="">On 25 Sep 2019, at 08:59, Craig Topper <<a href="mailto:craig.topper@gmail.com" class="">craig.topper@gmail.com</a>> wrote:<br class=""><br class="">There is code in CodeGenPrepare.cpp that can turn selects into branches that tries to account for multiple selects sharing the same condition. It doesn't look like either AVR or MSP430 enable that code though.<br class=""><br class="">~Craig<br class=""><br class=""><br class="">On Tue, Sep 24, 2019 at 11:27 PM Joan Lluch via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" class="">cfe-dev@lists.llvm.org</a>> wrote:<br class=""><blockquote type="cite" class=""><br class="">Hi Roman,<br class=""><br class="">Thank you for your reply. I understand your point. I just want to add something to clarify my original post in relation to your reply.<br class=""><br class="">There are already implemented 8-bit and 16-bit backends, namely the AVR and the MSP430, which already "aggressively convert selects into branches”, which already benefit (as they are) from setting "phi-node-folding-threshold’ to 1 or zero. This is because otherwise Clang will generate several selects depending on the same “icmp”. These backends are unable to optimise that, and they just create a comparison and a conditional branch for every “select” in the IR code, in spite that the original C code was already written in a much better way. So the resulting effect is the presence of redundant comparisons and branches in the final code, with a detrimental of generated code quality.<br class=""><br class="">The above gets improved by setting "phi-node-folding-threshold’ to 1 because some of these extra ‘selects' are no longer there so the backend stops generating redundant code.<br class=""><br class="">John.<br class=""><br class=""><br class=""><br class=""><br class=""><blockquote type="cite" class="">On 21 Sep 2019, at 14:48, Roman Lebedev <<a href="mailto:lebedev.ri@gmail.com" class="">lebedev.ri@gmail.com</a>> wrote:<br class=""><br class="">On Sat, Sep 21, 2019 at 3:18 PM Joan Lluch via cfe-dev<br class=""><<a href="mailto:cfe-dev@lists.llvm.org" class="">cfe-dev@lists.llvm.org</a>> wrote:<br class=""><blockquote type="cite" class=""><br class="">Hi all,<br class=""><br class="">For my custom architecture, I want to relax the CFG simplification pass, and any other passes replacing conditional branches.<br class=""><br class="">I found that the replacement of conditional branches by “select" and other instructions is often too aggressive, and this causes inefficient code for my target as in most cases branches would be cheaper.<br class=""><br class="">For example, considering the following c code:<br class=""><br class="">long test (long a, long b)<br class="">{<br class="">int neg = 0;<br class="">long res;<br class=""><br class="">if (a < 0)<br class="">{<br class="">  a = -a;<br class="">  neg = 1;<br class="">}<br class=""><br class="">res = a*b;<br class=""><br class="">if (neg)<br class="">  res = -res;<br class=""><br class="">return res;<br class="">}<br class=""><br class=""><br class="">This code can be simplified in c, but it’s just an example to show the point.<br class=""><br class="">The code above gets compiled like this (-Oz flag):<br class=""><br class="">; Function Attrs: minsize norecurse nounwind optsize readnone<br class="">define dso_local i32 @test(i32 %a, i32 %b) local_unnamed_addr #0 {<br class="">entry:<br class="">%cmp = icmp slt i32 %a, 0<br class="">%sub = sub nsw i32 0, %a<br class="">%a.addr.0 = select i1 %cmp, i32 %sub, i32 %a<br class="">%mul = mul nsw i32 %a.addr.0, %b<br class="">%sub2 = sub nsw i32 0, %mul<br class="">%res.0 = select i1 %cmp, i32 %sub2, i32 %mul<br class="">ret i32 %res.0<br class="">}<br class=""><br class=""><br class="">All branching was removed and replaced by ‘select’ instructions. For my architecture, it would be desirable to keep the original branches in most cases, because even simple 32 bit operations are too expensive to speculatively execute them, and branches are cheap.<br class=""><br class="">Setting  'phi-node-folding-threshold’ to 1 or even 0 (instead of the default 2), definitely improves the situation in many cases, but Clang still creates many instances of ‘select’ instructions, which are detrimental to my target. I am unsure about where are they created, as I believe that the simplifycfg pass does not longer create them.<br class=""></blockquote>You definitively can't ban llvm passes/clang from creating select's.<br class=""><br class=""><blockquote type="cite" class="">So the question is: Are there any other hooks in clang, or custom code that I can implement, to relax the creation of ’select’ instructions and make it preserve branches in the original c code?<br class=""></blockquote>I think this is backwards.<br class="">Sure, you could maybe disable most of the folds that produce selects.<br class="">That may be good for final codegen, but will also affect other passes<br class="">since not everything deals with 2-node PHI as good as wit selects.<br class=""><br class="">But, what happens if you still get the select-y IR?<br class="">Doesn't matter how, could be hand-written.<br class=""><br class="">I think you might want to instead aggressively convert selects into<br class="">branches in backend.<br class=""><br class=""><blockquote type="cite" class="">Thanks,<br class=""><br class="">John<br class=""></blockquote>Roman<br class=""><br class=""><blockquote type="cite" class="">_______________________________________________<br class="">LLVM Developers mailing list<br class=""><a href="mailto:llvm-dev@lists.llvm.org" class="">llvm-dev@lists.llvm.org</a><br class="">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev<br class="">_______________________________________________<br class="">cfe-dev mailing list<br class="">cfe-dev@lists.llvm.org<br class="">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev<br class=""></blockquote></blockquote><br class="">_______________________________________________<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=""></blockquote><br class=""><br class="">_______________________________________________<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=""></blockquote><br class=""><br class="">_______________________________________________<br class="">LLVM Developers mailing list<br class=""><a href="mailto:llvm-dev@lists.llvm.org" class="">llvm-dev@lists.llvm.org</a><br class="">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev</blockquote></div></blockquote></div><br class=""></div></body></html>