<div dir="ltr"><div dir="ltr"><div dir="ltr">On Mon, Sep 21, 2020 at 7:02 AM Bart Samwel via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org">cfe-dev@lists.llvm.org</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">Hi there folks,<div><br></div><div>I wonder if anybody can shed some light on this. I'm looking at a function with a parameter pack argument and one without, that should do the exact same thing.</div><div><br></div><div><a href="https://godbolt.org/z/Keqzcj" target="_blank">https://godbolt.org/z/Keqzcj</a> <br clear="all"><div><br></div><div>However, the version with the parameter pack expands (at -O3 -march=broadwell, on clang 10.0.1, on godbolt) into a loop per 128 bytes, plus a loop per 64 bytes, plus nonvectorized instructions to process the remaining <=63 bytes. The manual version expands to just a loop per 128 bytes (256-bit vectors, unrolled 4x), and nonvectorized instructions to process the remaining <=127 bytes.</div></div></div></blockquote><div><br></div><div>It's about the fold expression.</div><div><a href="https://godbolt.org/z/EPETj9">https://godbolt.org/z/EPETj9</a><br></div><div><br></div><div>With C++17 fold-expressions, (args | ...) doesn't mean (arg1 | arg2 | arg3); it means (arg1 | (arg2 | arg3)).  So with the right-fold you wrote, you're telling the compiler to OR the values together "right-to-left", whereas the non-template version does it "left-to-right": ((arg1 | arg2) | arg3). And apparently this makes some huge difference to the codegen (which is still mysterious to me, but out of my depth).</div><div><br></div><div>Switch the right-fold to a left-fold and the codegen becomes identical, at least to my eyes. (In the above Godbolt, put -DVARIADIC in one compiler frame and nothing in the other.)</div><div><br></div><div>–Arthur</div></div></div></div>