[cfe-dev] [cfe-users] Constexpr prevents optimization?
Steffen Hirschmann via cfe-dev
cfe-dev at lists.llvm.org
Sun May 27 05:48:01 PDT 2018
Thanks for the explanation and the link! This is very interesting.
Greetings,
Steffen
On 17:33 Mon 21 May , Richard Smith wrote:
> On 16 May 2018 at 00:38, Steffen Hirschmann via cfe-dev <cfe-dev at lists.llvm.org
> > wrote:
>
> Dear all,
>
> a while ago I posted odd (in the sense that I cannot explain it)
> constexpr behavior to the cfe-user mailing list and never received a
> reply. Since my observations are still valid for clang-6.0.0, I am
> reposting my original message to cfe-dev.
>
> tl;dr: It seems that the use of constexpr in this stupid example I ran
> across back in February prohibits a certain type of optimization that
> clang does. I cannot think of a reason for this behavior, therefore, I
> ask you.
>
> Greetings,
> Steffen
>
> P.S.: This also happens if one defines "fib" correctly (i <= 1). :)
>
>
> On 10:51 Fri 16 Feb , Steffen Hirschmann via cfe-users wrote:
> > Dear all,
> >
> > I was just playing around with a toy example when I noticed an oddity in
> > the code generated by clang-5.0.0 (and also in clang-5.0.1) regarding
> > constexpr.
> >
> > Given the code:
> > > int fib(int i) { if (i <= 0) return i; else return (fib(i - 1) + fib(i
> - 2)) % 100; }
> > > int main()
> > > {
> > > int ret = 0;
> > > for (int i = 0; i < 10; ++i)
> > > ret += fib(39);
> > > return ret;
> > > }
> >
> > Compile it with clang++ -O3 and what you get is (gdb disassembly of
> "main"):
> > > 7 {
> > > 8 int ret = 0;
> > > 9 for (int i = 0; i < 10; ++i)
> > > 10 ret += fib(39);
> > > 0x00000000004004e0 <+0>: push rax
> > > 0x00000000004004e1 <+1>: mov edi,0x27
> > > 0x00000000004004e6 <+6>: call 0x400490 <fib(int)>
> > >
> > > 9 for (int i = 0; i < 10; ++i)
> > > 0x00000000004004eb <+11>: add eax,eax
> > > 0x00000000004004ed <+13>: lea eax,[rax+rax*4]
> > >
> > > 11 return ret;
> > > 0x00000000004004f0 <+16>: pop rcx
> > > 0x00000000004004f1 <+17>: ret
> >
> > A call to fib(39) once followed by a multiplication with 10.
> >
> > Now, if you make "fib" constexpr, i.e.:
> > > constexpr int fib(int i) { if (i <= 0) return i; else return (fib(i -
> 1) + fib(i - 2)) % 100; }
> >
> > And, again, compile it with -O3 and disassemble "main":
> > > 7 {
> > > 8 int ret = 0;
> > > 9 for (int i = 0; i < 10; ++i)
> > > 10 ret += fib(39);
> > > 0x0000000000400490 <+0>: push rbp
> > > 0x0000000000400491 <+1>: push rbx
> > > 0x0000000000400492 <+2>: push rax
> > > 0x0000000000400493 <+3>: mov edi,0x27
> > > 0x0000000000400498 <+8>: call 0x400530 <fib(int)>
> > > 0x000000000040049d <+13>: mov ebx,eax
> > > 0x000000000040049f <+15>: mov edi,0x27
> > > 0x00000000004004a4 <+20>: call 0x400530 <fib(int)>
> > > 0x00000000004004a9 <+25>: mov ebp,eax
> > > 0x00000000004004ab <+27>: add ebp,ebx
> > > 0x00000000004004ad <+29>: mov edi,0x27
> > > 0x00000000004004b2 <+34>: call 0x400530 <fib(int)>
> > > 0x00000000004004b7 <+39>: mov ebx,eax
> > > 0x00000000004004b9 <+41>: add ebx,ebp
> > > 0x00000000004004bb <+43>: mov edi,0x27
> > > 0x00000000004004c0 <+48>: call 0x400530 <fib(int)>
> > > 0x00000000004004c5 <+53>: mov ebp,eax
> > > 0x00000000004004c7 <+55>: add ebp,ebx
> > > 0x00000000004004c9 <+57>: mov edi,0x27
> > > 0x00000000004004ce <+62>: call 0x400530 <fib(int)>
> > > 0x00000000004004d3 <+67>: mov ebx,eax
> > > 0x00000000004004d5 <+69>: add ebx,ebp
> > > 0x00000000004004d7 <+71>: mov edi,0x27
> > > 0x00000000004004dc <+76>: call 0x400530 <fib(int)>
> > > 0x00000000004004e1 <+81>: mov ebp,eax
> > > 0x00000000004004e3 <+83>: add ebp,ebx
> > > 0x00000000004004e5 <+85>: mov edi,0x27
> > > 0x00000000004004ea <+90>: call 0x400530 <fib(int)>
> > > 0x00000000004004ef <+95>: mov ebx,eax
> > > 0x00000000004004f1 <+97>: add ebx,ebp
> > > 0x00000000004004f3 <+99>: mov edi,0x27
> > > 0x00000000004004f8 <+104>: call 0x400530 <fib(int)>
> > > 0x00000000004004fd <+109>: mov ebp,eax
> > > 0x00000000004004ff <+111>: add ebp,ebx
> > > 0x0000000000400501 <+113>: mov edi,0x27
> > > 0x0000000000400506 <+118>: call 0x400530 <fib(int)>
> > > 0x000000000040050b <+123>: mov ebx,eax
> > > 0x000000000040050d <+125>: add ebx,ebp
> > > 0x000000000040050f <+127>: mov edi,0x27
> > > 0x0000000000400514 <+132>: call 0x400530 <fib(int)>
> > > 0x0000000000400519 <+137>: add eax,ebx
> > >
> > > 11 return ret;
> > > 0x000000000040051b <+139>: add rsp,0x8
> > > 0x000000000040051f <+143>: pop rbx
> > > 0x0000000000400520 <+144>: pop rbp
> > > 0x0000000000400521 <+145>: ret
> >
> > That's 10 calls to function "fib" (for which the assembly is essentially
> > the same as in the example above).
> >
> > Regardless of whether the function is evaluated at compile time or not,
> > it seems odd to me that using constexpr here prohibits clang from
> > emitting the very same code as in the non-constexpr example. Note
> > however, that if you declare "fib" to be "static constexpr" clang,
> > again, emits the multiplication code.
> >
> > Is there something keeping clang from producing the multiplication code
> > for a non-static constexpr example that I don't see? And why is the
> > optimization possible again if one makes "fib" static?
>
>
> The problem is not that constexpr prevents optimizations. The problem is that
> constexpr implies inline, and inline prevents optimizations. For details,
> please see
>
> https://www.playingwithpointers.com/blog/ipo-and-derefinement.html
>
> The problem here is that we cannot deduce that 'fib' is side-effect-free, and
> use that information to call it only once, if it's an inline function, because
> we don't know that it was "originally" side-effect-free, and it could be
> derefined to a version with side-effects in a way that makes the transformation
> to call it only once be somehow non-conforming. However, if 'fib' is not
> inline, or if it's file-static, then we can transfer that information from
> 'fib' to its caller, because we know the version of 'fib' we can see is the
> same one that's actually going to be used at runtime.
--
M.Sc. Steffen Hirschmann
Abt. Simulation Software Engineering
IPVS, Universität Stuttgart
Tel.: 0711/685 88223
More information about the cfe-dev
mailing list