<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Mar 24, 2021 at 12:00 PM Nuno Lopes <<a href="mailto:nunoplopes@sapo.pt">nunoplopes@sapo.pt</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div lang="EN-US" style="overflow-wrap: break-word;"><div class="gmail-m_-7598846242694699819WordSection1"><p class="MsoNormal">In theory, inrange should be perfect for this job. If inrange was extended to non-const geps, I think it would work for all cases you care about, right? It<span style="font-family:"Times New Roman",serif">’</span>s also the most compact representation, so I would prefer that solution. Better than adding a new call instruction for every single pointer arithmetic instruction.<u></u><u></u></p><p class="MsoNormal">In terms of BasicAA, supporting inrange shouldn<span style="font-family:"Times New Roman",serif">’</span>t be any different from !range metadata I think.<u></u><u></u></p><p class="MsoNormal"><u></u> </p></div></div></blockquote><div><br></div><div>So I tried implementing this on top of `inrange`, and I found out that you can only have one `inrange` index, which doesn't allow us to represent access into multidimensional arrays : <a href="https://reviews.llvm.org/D99341">https://reviews.llvm.org/D99341</a></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div lang="EN-US" style="overflow-wrap: break-word;"><div class="gmail-m_-7598846242694699819WordSection1"><p class="MsoNormal"><u></u></p><p class="MsoNormal">Just my 2c.<u></u><u></u></p><p class="MsoNormal"><u></u> <u></u></p><p class="MsoNormal">Nuno<u></u><u></u></p><p class="MsoNormal"><u></u> <u></u></p><p class="MsoNormal"><u></u> <u></u></p><div style="border-right:none;border-bottom:none;border-left:none;border-top:1pt solid rgb(225,225,225);padding:3pt 0cm 0cm"><p class="MsoNormal"><b>From:</b> Clement Courbet<br><b>Sent:</b> 24 March 2021 09:15<br><b>To:</b> llvm-dev <<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a>><br><b>Subject:</b> [llvm-dev] [RFC] Adding range metadata to array subscripts.<u></u><u></u></p></div><p class="MsoNormal"><u></u> <u></u></p><div><p class="MsoNormal">Hi everyone,<u></u><u></u></p><div><p class="MsoNormal"><u></u> <u></u></p></div><div><p class="MsoNormal">tl;dr: I would like to teach clang to output range metadata so that LLVM can do better alias analysis. I have a proposal as <a href="https://reviews.llvm.org/D99248" target="_blank">D99248</a> (clang part) and <a href="https://reviews.llvm.org/D99247" target="_blank">D99247</a> (llvm part). But there are other possible options that I'm detailing below.<u></u><u></u></p></div><div><p class="MsoNormal"><u></u> <u></u></p></div><div><p class="MsoNormal">Consider the following code, adapted from <a href="https://en.wikipedia.org/wiki/Brotli" target="_blank">brotli</a>:<u></u><u></u></p></div><div><p class="MsoNormal"><u></u> <u></u></p></div><div><p class="MsoNormal">```<u></u><u></u></p></div><div><p style="margin:0cm"><span style="font-size:10pt;font-family:Consolas;color:rgb(156,39,176)">struct</span><span style="font-size:10pt;font-family:Consolas;color:black"> </span><span style="font-size:10pt;font-family:Consolas;color:rgb(51,103,214)">Histogram</span><span style="font-size:10pt;font-family:Consolas;color:black"> </span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">{</span><u></u><u></u></p><p style="margin:0cm"><span style="font-size:10pt;font-family:Consolas;color:black">  </span><span style="font-size:10pt;font-family:Consolas;color:rgb(156,39,176)">int</span><span style="font-size:10pt;font-family:Consolas;color:black"> values</span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">[</span><span style="font-size:10pt;font-family:Consolas;color:rgb(197,57,41)">256</span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">];</span><u></u><u></u></p><p style="margin:0cm"><span style="font-size:10pt;font-family:Consolas;color:black">  </span><span style="font-size:10pt;font-family:Consolas;color:rgb(156,39,176)">int</span><span style="font-size:10pt;font-family:Consolas;color:black"> total</span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">;</span><u></u><u></u></p><p style="margin:0cm"><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">};</span><u></u><u></u></p><p class="MsoNormal"><u></u> <u></u></p><p style="margin:0cm"><span style="font-size:10pt;font-family:Consolas;color:rgb(51,103,214)">Histogram</span><span style="font-size:10pt;font-family:Consolas;color:black"> </span><span style="font-size:10pt;font-family:Consolas;color:rgb(51,103,214)">DoIt</span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">(</span><span style="font-size:10pt;font-family:Consolas;color:rgb(156,39,176)">const</span><span style="font-size:10pt;font-family:Consolas;color:black"> </span><span style="font-size:10pt;font-family:Consolas;color:rgb(156,39,176)">int</span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">*</span><span style="font-size:10pt;font-family:Consolas;color:black"> image</span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">,</span><span style="font-size:10pt;font-family:Consolas;color:black"> </span><span style="font-size:10pt;font-family:Consolas;color:rgb(156,39,176)">int</span><span style="font-size:10pt;font-family:Consolas;color:black"> size</span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">)</span><span style="font-size:10pt;font-family:Consolas;color:black"> </span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">{</span><u></u><u></u></p><p style="margin:0cm"><span style="font-size:10pt;font-family:Consolas;color:black">  </span><span style="font-size:10pt;font-family:Consolas;color:rgb(51,103,214)">Histogram</span><span style="font-size:10pt;font-family:Consolas;color:black"> histogram</span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">;</span><u></u><u></u></p><p style="margin:0cm"><span style="font-size:10pt;font-family:Consolas;color:black">  </span><span style="font-size:10pt;font-family:Consolas;color:rgb(156,39,176)">for</span><span style="font-size:10pt;font-family:Consolas;color:black"> </span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">(</span><span style="font-size:10pt;font-family:Consolas;color:rgb(156,39,176)">int</span><span style="font-size:10pt;font-family:Consolas;color:black"> i </span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">=</span><span style="font-size:10pt;font-family:Consolas;color:black"> </span><span style="font-size:10pt;font-family:Consolas;color:rgb(197,57,41)">0</span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">;</span><span style="font-size:10pt;font-family:Consolas;color:black"> i </span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)"><</span><span style="font-size:10pt;font-family:Consolas;color:black"> size</span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">;</span><span style="font-size:10pt;font-family:Consolas;color:black"> </span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">++</span><span style="font-size:10pt;font-family:Consolas;color:black">i</span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">)</span><span style="font-size:10pt;font-family:Consolas;color:black"> </span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">{</span><u></u><u></u></p><p style="margin:0cm"><span style="font-size:10pt;font-family:Consolas;color:black">    </span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">++</span><span style="font-size:10pt;font-family:Consolas;color:black">histogram</span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">.</span><span style="font-size:10pt;font-family:Consolas;color:black">values</span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">[</span><span style="font-size:10pt;font-family:Consolas;color:black">image</span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">[</span><span style="font-size:10pt;font-family:Consolas;color:black">i</span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">]];</span><span style="font-size:10pt;font-family:Consolas;color:black">  </span><span style="font-size:10pt;font-family:Consolas;color:rgb(69,90,100)">// (A)</span><u></u><u></u></p><p style="margin:0cm"><span style="font-size:10pt;font-family:Consolas;color:black">    </span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">++</span><span style="font-size:10pt;font-family:Consolas;color:black">histogram</span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">.</span><span style="font-size:10pt;font-family:Consolas;color:black">total</span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">;</span><span style="font-size:10pt;font-family:Consolas;color:black">             </span><span style="font-size:10pt;font-family:Consolas;color:rgb(69,90,100)">// (B)</span><u></u><u></u></p><p style="margin:0cm"><span style="font-size:10pt;font-family:Consolas;color:black">  </span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">}</span><u></u><u></u></p><p style="margin:0cm"><span style="font-size:10pt;font-family:Consolas;color:black">  </span><span style="font-size:10pt;font-family:Consolas;color:rgb(156,39,176)">return</span><span style="font-size:10pt;font-family:Consolas;color:black"> histogram</span><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">;</span><u></u><u></u></p><p style="margin:0cm"><span style="font-size:10pt;font-family:Consolas;color:rgb(97,97,97)">}</span><u></u><u></u></p><div><p class="MsoNormal">```<u></u><u></u></p></div><div><p class="MsoNormal"><u></u> <u></u></p></div><div><p class="MsoNormal">In this code, the compiler does not know anything about the values of images[i], so it assumes that 256 is a possible value for it. In that case, (A) would change the value of histogram.total, so (B) has to load, add one and store [<a href="https://godbolt.org/z/KxE343" target="_blank">godbolt</a>].<u></u><u></u></p></div><div><p class="MsoNormal"><u></u> <u></u></p></div><div><p class="MsoNormal">Fortunately, C/C++ has a rule that it is invalid (actually, UB) to use values to form a pointer to total and dereference it. What valid C/C++ code is allowed to do with values is:<u></u><u></u></p></div><p class="MsoNormal"> - Form any pointer in [values, values + 256].<br> - Form and dereference any pointer in [values, values + 256)<u></u><u></u></p><div><p class="MsoNormal"><u></u> <u></u></p></div></div><div><p class="MsoNormal">Note that the LLVM memory model is much laxer than that of C/C++. It has no notion of types. In particular, given an LLVM aggregate definition:<br><br>```<br>%struct.S = type { [42 x i32], i32, i32 }<br>```<br><br>It is perfectly valid to use an address derived from a GEP(0,0,%i)  [gep reference] representing indexing into the [42 x i32] array to load the i32 member at index 2. It is also valid for %i to be 43 (though not 44 if an inbound GEP is used).<u></u><u></u></p></div><div><p class="MsoNormal">So clang has to give LLVM more information about the C/C++ rules.<u></u><u></u></p></div><div><p class="MsoNormal"><u></u> <u></u></p></div><div><p class="MsoNormal"><b>IR representation:</b><br>LLVM has several ways of representing ranges of values:<br> - <b>!range</b> metadata can be attached to integer call and load instructions to indicate the allowed range of values of the result. LLVM's ValueTracking provides a function for querying the range for any llvm::Variable.<br> - The <b>llvm.assume</b> intrinsic takes a boolean condition that can also be used by ValueTracking to infer range of values.<br> - The <b>inrange</b> attribute of GEP can be used to indicate C-like semantics for the structure field marked with the inrange attribute. It can only be used for GEP constantexprs (ie.e. GEPs defined inline), but not for standalone GEPs defining instructions.  <a href="https://reviews.llvm.org/D22793?id=65626#inline-194653" target="_blank">relevant discussion</a>. <u></u><u></u></p></div><div><p class="MsoNormal"><u></u> <u></u></p></div><div><p class="MsoNormal">Alternatives: <br><b>(1) </b>Annotate each array subscript index value with a range, e.g.:<u></u><u></u></p></div><div><p class="MsoNormal">```<br>%i = i64 …<br>%ri =  call i64 @llvm.annotation.i64(%index), !range !0<br>%gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 0, i32 %ri<br>...<br>!0 = !{i64 0, i64 42}<u></u><u></u></p></div><div><p class="MsoNormal">```<br><b>(2) </b>(variant of 1) relax the constraint that !range metadata can only be set on call and load instructions, and set the !range metadata on the index expression. We still need annotations for function parameters though:<u></u><u></u></p></div><div><p class="MsoNormal">```<br>%i = i64 … , !range !0<br>%gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 0, i32 %i<br>...<br>!0 = !{i64 0, i64 42}<u></u><u></u></p></div><div><p class="MsoNormal" style="margin-bottom:12pt">```<br>This is slightly more compact.<u></u><u></u></p></div><div><p class="MsoNormal"><b>(3)</b> Same as (1), with llvm.assume. This feels inferior to annotations.<br><b>(4)</b> Extend inrange to non-constantexprs GEPs. It is unclear how this will interfere with optimizations.<u></u><u></u></p></div><div><p class="MsoNormal"><u></u> <u></u></p></div><div><div><p class="MsoNormal"><u></u> <u></u></p></div><div><p class="MsoNormal"><b>On the clang side</b>:<u></u><u></u></p></div><div><p class="MsoNormal">The clang part is quite trivial as the infrastructure is already in place to emit dynamic ubsan guards: <a href="https://reviews.llvm.org/D99248" target="_blank">D99248</a><u></u><u></u></p></div></div><div><p class="MsoNormal"><u></u> <u></u></p></div><div><p class="MsoNormal"><b>On the LLVM Side:</b><u></u><u></u></p></div><div><p class="MsoNormal">Alternatives:<br><b>(A)</b> - (annotation or assume options) Simply enable scev-aa which knows how to handle value ranges in general. IIUC it's not enabled in clang because it has issues with invalidation when code changes, and is therefore not cacheable. This makes it too slow to be practical.<br><b>(B) </b>- (annotation or assume options) Teach BasicAA to honor !range metadata (<a href="https://reviews.llvm.org/D99247" target="_blank">D99247</a>)<br><b>(C)</b> - (inrange option) Teach BasicAA to honor inrange attributes of GEP.<u></u><u></u></p></div><div><p class="MsoNormal"><u></u> <u></u></p></div><div><p class="MsoNormal">I was leaning towards (1) and (B) because:<u></u><u></u></p></div><div><p class="MsoNormal"> - BasicAA already has basic support for value range analysis (zero/nonzero), this is a small and natural extension.<u></u><u></u></p></div><div><p class="MsoNormal"> - The BasicAA improvement already benefits some existing code (as evidenced by the test changes in <a href="https://reviews.llvm.org/D99247" target="_blank">D99247</a>)<u></u><u></u></p></div><div><p class="MsoNormal"> - Using range metadata rather than the `inrange` attribute means that BasicAA will automatically benefit from improvements in value tracking in the future.<u></u><u></u></p></div><div><p class="MsoNormal"><u></u> <u></u></p></div><div><p class="MsoNormal">Opinions ?<u></u><u></u></p></div></div></div></div></blockquote></div></div>