<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="">Hi Tim,<div class=""><br class=""></div><div class="">I tracked down the issue to a LLVM omission or bug, or that’s what I think. The issue can be easily reproduced for targets that do not support misaligned memory accessed and do not implement allowsMisalignedMemoryAccesses. Let me try to explain what happens:</div><div class=""><br class=""></div><div class="">In getMemcpyLoadsAndStores, the function FindOptimalMemOpLowering is called to obtain the list of Store operations that should be generated. If the memcpy destination is the non-fixed section of the stack, a value of Zero is passed as the destination alignment (DstAlign) to signal that it can be “changed”.</div><div class=""><br class=""></div><div class="">The FindOptimalMemOpLowering starts by calling the target getOptimalMemOpType. Most targets implement the later by returning the largest possible EVT that shall be used to create the load/store pairs. This is generally ok for targets that can handle non-aligned load/stores. If this function is not implemented, then the FindOptimalMemOpLowering does that by finding the largest legal integer type. Again, this is ok if the target would support misaligned accesses. Upon return, the FindOptimalMemOpLowering has found the minimal list of memory operations required to complete the memcpy.</div><div class=""><br class=""></div><div class="">Next, the getMemcpyLoadsAndStores continues by generating the required load/store pairs, which will result into too large loads/stores for targets that do not support misaligned accesses.</div><div class=""><br class=""></div><div class="">Later on, during the legalizeDAG phase, the function LegalizeLoadOps is invoked which eventually calls allowsMemoryAccess function, which only now calls allowsMisalignedMemoryAccesses to determine that it must replace the too long loads by the odd Shifts and OR aggregates of smaller loads, the latter happens inside expandUnalignedLoad</div><div class=""><br class=""></div><div class="">I would have expected, that for targets not supporting misaligned accesses, the list of load/stores generated around the getMemcpyLoadsAndStores function, would have respected such target limitation and would have not produced misaligned load/stores to begin with. Instead, the default implementation defers that for later and ends replacing such incorrect load/stores by odd expanded aggregates.</div><div class=""><br class=""></div><div class="">The workaround that I found was implementing getOptimalMemOpType in a way that rather than finding the highest possible EVT to minimise the number of load/stores, it would provide one that will never get greater than the SrcAlign. So this is what I have now:</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class=""><span style="color: #4f8187" class="">EVT</span> <span style="color: #4f8187" class="">CPU74TargetLowering</span>::getOptimalMemOpType(<span style="color: #703daa" class="">uint64_t</span> Size,</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="">unsigned</span> DstAlign, <span style="color: #ba2da2" class="">unsigned</span> SrcAlign, <span style="color: #ba2da2" class="">bool</span> IsMemset, <span style="color: #ba2da2" class="">bool</span> ZeroMemset,</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="">bool</span> MemcpyStrSrc, <span style="color: #4f8187" class="">MachineFunction</span> &MF) <span style="color: #ba2da2" class="">const</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="">    <span style="color: #ba2da2" class="">if</span> ( DstAlign == <span style="color: #272ad8" class="">0</span> && !IsMemset )</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>// Return the EVT of the source</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">        DstAlign = SrcAlign;</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">        <span style="color: #4f8187" class="">EVT</span> VT = <span style="color: #4f8187" class="">MVT</span>::<span style="color: #31595d" class="">i64</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="">while</span> (DstAlign && DstAlign < VT.<span style="color: #31595d" class="">getSizeInBits</span>() / <span style="color: #272ad8" class="">8</span>)</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">          VT = (<span style="color: #4f8187" class="">MVT</span>::<span style="color: #4f8187" class="">SimpleValueType</span>)(VT.<span style="color: #31595d" class="">getSimpleVT</span>().<span style="color: #4f8187" class="">SimpleTy</span> - <span style="color: #272ad8" class="">1</span>);</div><p style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255); min-height: 15px;" class="">    <br class="webkit-block-placeholder"></p><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> VT;</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">    }</div><p style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255); min-height: 15px;" class="">  <br class="webkit-block-placeholder"></p><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="">MVT</span>::<span style="color: #31595d" class="">Other</span>;</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Monaco; background-color: rgb(255, 255, 255);" class="">}</div></div><div class=""><br class=""></div><div class="">Maybe, this is what we are expected to do after all, but it still looks somewhat weird to me that the default LLVM implementation would not take care of misaligned memory access targets in a more appropriate way. Solving this issue is just a matter of including the code above in FindOptimalMemOpLowering for such targets. The current implementation does just the opposite, and will even use MVT::i64 as the destination align even if the source align is only MVT::i8, which I regard as totally wrong.</div><div class=""><br class=""></div><div class="">This problem is also shared by the MSP430 target, and it’s very easy to reproduce by just compiling the code that I posted before.</div><div class=""><br class=""></div><div class="">Thanks</div><div class=""><br class=""><div class=""><div class="">
<div style="color: rgb(0, 0, 0); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div style="color: rgb(0, 0, 0); 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;">John Lluch</div><div style="color: rgb(0, 0, 0); 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;"><br class=""></div><div style="color: rgb(0, 0, 0); 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;"><br class=""></div><div style="color: rgb(0, 0, 0); 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;"><br class=""></div></div></div></div><div><blockquote type="cite" class=""><div class="">On 13 May 2019, at 20:09, Tim Northover <<a href="mailto:t.p.northover@gmail.com" class="">t.p.northover@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="">Hi Joan,<br class=""><br class="">On Mon, 13 May 2019 at 18:01, Joan Lluch <<a href="mailto:joan.lluch@icloud.com" class="">joan.lluch@icloud.com</a>> wrote:<br class=""><blockquote type="cite" class="">After looking at it a bit further, I think this is a Clang thing.  Clang issues “align 2” if the struct has at least one int (2 bytes), but also if the entire struct size is multiple of 2. For example a struct with 4 char members. In these cases the LLVM backend correctly creates word sized load/stores (2 bytes).<br class=""></blockquote><br class="">I'm slightly surprised that it happens based purely on size, but<br class="">either way LLVM should be able to cope.<br class=""><br class=""><blockquote type="cite" class="">The LLVM backend just follows what’s dictated by Clang regarding alignment and thus it creates 2 byte or 1 byte load/stores instructions accordingly. I have not found a way to override this in LLVM. Any suggestions are appreciated.<br class=""></blockquote><br class="">That sounds right, but I don't think it explains the shifts you<br class="">described before. It should work out a lot better than what you're<br class="">seeing. Specifically, a 3 byte struct (for example) ought to either<br class="">lower to:<br class=""><br class="">    load i16, load i8 + stores if your target can do misaligned i16 operations.<br class=""><br class="">or<br class=""><br class="">    load i8, load i8, load i8 + stores if not.<br class=""><br class="">Neither of those involve shifting operations. I'd suggest breaking<br class="">just after getMemcpyLoadsAndStores and using SelectionDAG::dump to see<br class="">exactly what it's created. Then try to work out where that gets<br class="">pessimized to shifts, because it's not normal.<br class=""><br class="">Cheers.<br class=""><br class="">Tim.<br class=""></div></div></blockquote></div><br class=""></div></div></body></html>