<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="">
<div class="">We have seen cases where it is profitable to widen at a given point in compilation, but after optimizations such as inlining (with more surrounding code), future opts after inlining do a better job with the non-widened code [1]</div>
<div class=""><br class="">
</div>
<div class="">Couple of concerns:</div>
<div class="">1. having inst combine rules for widening would need to take care of endian-ness, and interactions with other optimizations, since instcombine is run multiple times. From the above discussion there are couple of passes, such as PRE, LICM (probably
more), that can be affected negatively by the widening. I’m not sure if it’s a good idea to add as instcombine rule.</div>
<div class=""><br class="">
</div>
<div class="">2. I think identifying enough obvious cases to warrant a late fix-up pass, which would be improvements/neutral for all architectures may be difficult :) There’s also the question of maintainability - adding new rules to the pass. Widening rules
are perhaps best suited as back end optimizations, in the presence of profitability cost model specific to the architecture. For example, there is the store widening in Hexagon arch. I’m not sure if we have more of this in place. </div>
<div class=""><br class="">
</div>
<div class="">[1] <a href="http://lists.llvm.org/pipermail/llvm-dev/2016-June/101789.html" class="">http://lists.llvm.org/pipermail/llvm-dev/2016-June/101789.html</a></div>
<div class=""><br class="">
</div>
<div class=""><br class="">
</div>
<div class="">Anna</div>
<div class=""><br class="">
</div>
<div>
<blockquote type="cite" class="">
<div class="">On Sep 29, 2016, at 2:25 PM, Artur Pilipenko <<a href="mailto:apilipenko@azulsystems.com" class="">apilipenko@azulsystems.com</a>> wrote:</div>
<br class="Apple-interchange-newline">
<div class="">
<div class=""><br class="">
<blockquote type="cite" class="">On 29 Sep 2016, at 21:16, Sanjoy Das <<a href="mailto:sanjoy@playingwithpointers.com" class="">sanjoy@playingwithpointers.com</a>> wrote:<br class="">
<br class="">
Hi Artur,<br class="">
<br class="">
Artur Pilipenko wrote:<br class="">
<blockquote type="cite" class="">
<blockquote type="cite" class="">On 29 Sep 2016, at 21:01, Sanjoy Das<<a href="mailto:sanjoy@playingwithpointers.com" class="">sanjoy@playingwithpointers.com</a>> wrote:<br class="">
<br class="">
Hi Artur,<br class="">
<br class="">
Artur Pilipenko wrote:<br class="">
<br class="">
<blockquote type="cite" class="">BTW, do we really need to emit an atomic load if all the individual<br class="">
components are bytes?<br class="">
</blockquote>
Depends -- do you mean at the at the hardware level or at the IR<br class="">
level?<br class="">
<br class="">
If you mean at the IR level, then I think yes; since otherwise it is<br class="">
legal to do transforms that break byte-wise atomicity in the IR, e.g.:<br class="">
<br class="">
i32* ptr = ...<br class="">
i32 val = *ptr<br class="">
<br class="">
=> // Since no threads can be legally racing on *ptr<br class="">
<br class="">
i32* ptr = ...<br class="">
i32 val0 = *ptr<br class="">
i32 val1 = *ptr<br class="">
i32 val = (val0& 1) | (val1& ~1);<br class="">
<br class="">
<br class="">
If you're talking about the hardware level, then I'm not sure; and my<br class="">
guess is that the answer is almost certainly arch-dependent.<br class="">
</blockquote>
I meant the case when we have a load by bytes pattern like this:<br class="">
i8* p = ...<br class="">
i8 b0 = *p++;<br class="">
i8 b1 = *p++;<br class="">
i8 b2 = *p++;<br class="">
i8 b3 = *p++;<br class="">
i32 result = b0<< 24 | b1<< 16 | b2<< 8 | b<< 0;<br class="">
<br class="">
When we fold it to a i32 load, should this load be atomic?<br class="">
</blockquote>
<br class="">
If we do fold it to a non-atomic i32 load, then it would be legal for<br class="">
LLVM to do the IR transform I mentioned above. That breaks the<br class="">
byte-wise atomicity you had in the original program.<br class="">
<br class="">
That is, in:<br class="">
<br class="">
i8* p = ...<br class="">
i8 b0 = *p++;<br class="">
i8 b1 = *p++;<br class="">
i8 b2 = *p++;<br class="">
i8 b3 = *p++;<br class="">
// Note: I changed this to be little endian, and I've assumed<br class="">
// that we're compiling for a little endian system<br class="">
i32 result = b3<< 24 | b2<< 16 | b1<< 8 | b0<< 0;<br class="">
<br class="">
say all of p[0..3] are 0, and you have a thread racing to set b0 to<br class="">
-1. Then result can either be 0 or 255.<br class="">
<br class="">
However, say you first transform this to a non-atomic i32 load:<br class="">
<br class="">
i8* p = ...<br class="">
i32* p.i32 = (i32*)p<br class="">
i32 result = *p.i32<br class="">
<br class="">
and we do the transform above<br class="">
<br class="">
i8* p = ...<br class="">
i32* p.i32 = (i32*)p<br class="">
i32 result0 = *p.i32<br class="">
i32 result1 = *p.i32<br class="">
i32 result = (result0 & 1) | (result1 & ~1);<br class="">
<br class="">
then it is possible for result to be 254 (by result0 observing 0 and<br class="">
result observing 255).<br class="">
</blockquote>
I see. For some reason I was assuming byte-wise atomicity for non-atomic loads.<br class="">
<br class="">
So, if any of the components are atomic, the resulting load must be atomic as well.<br class="">
<br class="">
Artur <br class="">
<blockquote type="cite" class=""><br class="">
-- Sanjoy<br class="">
</blockquote>
<br class="">
</div>
</div>
</blockquote>
</div>
<br class="">
</body>
</html>