2

Full code available here: https://godbolt.org/z/7sbxeM3WP

I was curious if it would be possible for a compiler to optimize

constexpr auto lambda = [](){return 5;};
constexpr auto lambda_same_definition = [](){return 5;};

such that there would only be one generated functor. I am aware of how lambda expressions work under the hood, creating anonymous functors for each expression. But at least here it looks pretty obvious since the expressions are literally the same, char for char, plus they're stored as constexpr, that it doesn't seem out of the question that the compiler could fold the two functors into one. Of course I doubt this type of reasoning is doable in the general case, determining if two functions are the same sounds would probably be undecidable in the general case I'm guessing.

Unfortunately, it doesn't look like that's the case from my Godbolt snippet, it seems to have info for both under the type names*NL6lambdaMUlvE_E1 and NL22lambda_same_definitionMUlvE_E.

So my question is, is this a quality of implementation issue? Or is there something in the Standard that forbids this optimization?

k huang
  • 409
  • 3
  • 10

1 Answers1

4

Each lambda is a unique anonymous class. This is going to be the starting point.

The C++ standard allows a compiler to implement any optimization that has no observable effects. If the compiler can prove that using a single instance of the anonymous class will have no observable effects than the compiler is allowed to implement it.

So if someone is wondering "if it would be possible" to do that, the answer is: yes, it's possible.

Whether or not your compiler successfully implements this optimization can only be determined by inspecting the actual code produced by your compiler.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • 1
    Modern compilers do identical-code-folding for named functions, e.g. making one just a `jmp` to the other instead of emitting the same big chunk of asm for both. I assume GCC wants different functions to have different addresses, otherwise it could just put two labels on the same block to avoid a `jmp`. For GCC, the option is `-fipa-icf` which stands for InterProcedural Analysis: Identical Code Folding. So I'd certainly expect this for the code of anonymous lambdas. – Peter Cordes May 25 '23 at 03:22
  • 1
    But IPA-ICF only takes care of the actual code, which is trivial in this case; the OP's Godbolt link shows there's metadata with type-name information, and a vtable? With `-fno-rtti`, https://godbolt.org/z/v33je4nGK it gets a lot more compact, just `.LC0: .quad _ZNSt17_Function_handlerIFivENL6lambdaMUlvE_EE9_M_invokeERKSt9_Any_data` and `.LC1:` with the `lambda_same_definition`. So as Richard Critten suggested, maybe it does come down to COMDAT folding. Oh, also Godbolt was filtering "library functions" and omitting the `mov eax, 5` / `ret` code for the actual lambdas. That's duplicated :/ – Peter Cordes May 25 '23 at 03:25
  • 1
    @PeterCordes `std::function` requires type information. The callee could use the `std::function::target_type` member function to identity the actual lambda (which always has a distinct type). On the other hand it is impossible to take addresses of non-static member functions or otherwise compare their identity for unrelated classes. So the compiler wouldn't need to worry about identical code folding violating address requirements of the two `operator()` member functions of the lambdas. But I don't know whether compilers special case non-static member functions. – user17732522 May 26 '23 at 19:47