<div dir="ltr"><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">Hello LLVM Community (specifically anyone working with ARM Cortex-M),</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">While trying to compile the Newlib C library I found that Clang10 was generating slightly larger binaries than the libc from the prebuilt gcc-arm-none-eabi toolchain. I looked at a few specific functions (memcpy, strcpy, etc.) and noticed that LLVM does not tend to generate load/store instructions with a register offset (e.g. ldr Rd, [Rn, Rm] form) and instead prefers the immediate offset form.</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">When copying a contiguous sequence of bytes, this results in additional instructions to modify the base address. <a href="https://godbolt.org/z/T1xhae">https://godbolt.org/z/T1xhae</a></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><div style="color:rgb(0,0,0);background-color:rgb(255,255,254);font-family:"Consolas, ""><div><span style="color:rgb(0,0,255)">void</span>* memcpy_alt1(<span style="color:rgb(0,0,255)">void</span>* dst, <span style="color:rgb(0,0,255)">const</span> <span style="color:rgb(0,0,255)">void</span>* src, size_t len) {</div><div>    <span style="color:rgb(0,0,255)">char</span>* save = (<span style="color:rgb(0,0,255)">char</span>*)dst;</div><div>    <span style="color:rgb(0,0,255)">for</span> (size_t i = <span style="color:rgb(9,134,88)">0</span>; i < len; ++i)</div><div>        *((<span style="color:rgb(0,0,255)">char</span>*)(dst + i)) = *((<span style="color:rgb(0,0,255)">char</span>*)(src + i));</div><div>    <span style="color:rgb(0,0,255)">return</span> save;</div><div>}</div><div><br></div><div>clang --target=armv6m-none-eabi -Os -fomit-frame-pointer</div><div><div><div><span style="color:rgb(0,128,128)">memcpy_alt1:</span></div><div>        <span style="color:rgb(0,0,255)">push</span>    {<span style="color:rgb(72,100,170)">r4</span>, <span style="color:rgb(72,100,170)">lr</span>}</div><div>        <span style="color:rgb(0,0,255)">cmp</span>     <span style="color:rgb(72,100,170)">r2</span>, <span style="color:rgb(9,134,88)">#0</span></div><div>        <span style="color:rgb(0,0,255)">beq</span>     <span style="color:rgb(0,128,128)">.LBB0_3</span></div><div>        <span style="color:rgb(0,0,255)">mov</span>     <span style="color:rgb(72,100,170)">r3</span>, <span style="color:rgb(72,100,170)">r0</span></div><div><span style="color:rgb(0,128,128)">.LBB0_2:</span></div><div>        <span style="color:rgb(0,0,255)">ldrb</span>    <span style="color:rgb(72,100,170)">r4</span>, [<span style="color:rgb(72,100,170)">r1</span>]</div><div>        <span style="color:rgb(0,0,255)">strb</span>    <span style="color:rgb(72,100,170)">r4</span>, [<span style="color:rgb(72,100,170)">r3</span>]</div><div>        <span style="color:rgb(0,0,255)">adds</span>    <span style="color:rgb(72,100,170)">r1</span>, <span style="color:rgb(72,100,170)">r1</span>, <span style="color:rgb(9,134,88)">#1</span></div><div>        <span style="color:rgb(0,0,255)">adds</span>    <span style="color:rgb(72,100,170)">r3</span>, <span style="color:rgb(72,100,170)">r3</span>, <span style="color:rgb(9,134,88)">#1</span></div><div>        <span style="color:rgb(0,0,255)">subs</span>    <span style="color:rgb(72,100,170)">r2</span>, <span style="color:rgb(72,100,170)">r2</span>, <span style="color:rgb(9,134,88)">#1</span></div><div>        <span style="color:rgb(0,0,255)">bne</span>     <span style="color:rgb(0,128,128)">.LBB0_2</span></div><div><span style="color:rgb(0,128,128)">.LBB0_3:</span></div><div>        <span style="color:rgb(0,0,255)">pop</span>     {<span style="color:rgb(72,100,170)">r4</span>, <span style="color:rgb(0,128,128)">pc</span>}</div></div></div><div><br></div><div>arm-none-eabi-gcc -march=armv6-m -Os</div><div><div><div><span style="color:rgb(0,128,128)">memcpy_alt1:</span></div><div>        <span style="color:rgb(0,0,255)">movs</span>    <span style="color:rgb(72,100,170)">r3</span>, <span style="color:rgb(9,134,88)">#0</span></div><div>        <span style="color:rgb(0,0,255)">push</span>    {<span style="color:rgb(72,100,170)">r4</span>, <span style="color:rgb(72,100,170)">lr</span>}</div><div><span style="color:rgb(0,128,128)">.L2:</span></div><div>        <span style="color:rgb(0,0,255)">cmp</span>     <span style="color:rgb(72,100,170)">r3</span>, <span style="color:rgb(72,100,170)">r2</span></div><div>        <span style="color:rgb(0,0,255)">bne</span>     <span style="color:rgb(0,128,128)">.L3</span></div><div>        <span style="color:rgb(0,0,255)">pop</span>     {<span style="color:rgb(72,100,170)">r4</span>, <span style="color:rgb(0,128,128)">pc</span>}</div><div><span style="color:rgb(0,128,128)">.L3:</span></div><div>        <span style="color:rgb(0,0,255)">ldrb</span>    <span style="color:rgb(72,100,170)">r4</span>, [<span style="color:rgb(72,100,170)">r1</span>, <span style="color:rgb(72,100,170)">r3</span>]</div><div>        <span style="color:rgb(0,0,255)">strb</span>    <span style="color:rgb(72,100,170)">r4</span>, [<span style="color:rgb(72,100,170)">r0</span>, <span style="color:rgb(72,100,170)">r3</span>]</div><div>        <span style="color:rgb(0,0,255)">adds</span>    <span style="color:rgb(72,100,170)">r3</span>, <span style="color:rgb(72,100,170)">r3</span>, <span style="color:rgb(9,134,88)">#1</span></div><div>        <span style="color:rgb(0,0,255)">b</span>       <span style="color:rgb(0,128,128)">.L2</span></div></div></div></div></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">Because this code appears in a loop that could be copying hundreds of bytes, I want to add an optimization that will prioritize load/store instructions with register offsets when the offset is used multiple times. I have not worked on LLVM before, so I'd like advice about where to start.</div><div class="gmail_default" style=""><ul style="font-family:arial,helvetica,sans-serif"><li>The generated code is correct, just sub-optimal so is it appropriate to submit a bug report?</li><li>Is anyone already tackling this change or is there someone with more experience interested in collaborating?</li><li>Is this optimization better performed early during instruction selection or late using c++ (i.e. ARMLoadStoreOptimizer.cpp)</li><li>What is the potential to cause harm to other parts of the code gen, specifically for other arm targets. I'm working with armv6m, but armv7m offers base register updating in a single instruction. I don't want to break other useful optimizations.</li></ul><div style="font-family:arial,helvetica,sans-serif">So far, I am reading through the LLVM documentation to see where a change could be applied. I have also:</div><div style=""><ul style=""><li style="font-family:arial,helvetica,sans-serif">Compiled with -S -emit-llvm (see Godbolt link)<br>There is an identifiable pattern where a getelementptr function is followed by a load or store. When multiple getelementptr functions appear with the same virtual register offset, maybe this should match a tLDRr or tSTRr.</li><li style=""><font face="arial, helvetica, sans-serif">Ran LLC with  </font>--print-machineinstrs <br>It appears that tLDRBi and tSTRBi are selected very early and never replaced by the equivalent t<LDRB|STRB>r instructions.</li></ul><div>Thank you,</div></div></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br></div><div><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div>Daniel Way</div></div></div></div></div>