The response states that Open Watcom compiles such code

bool f(bool var1) { bool var2 = !var1; return var2; } bool g(bool var1) { bool var2; if (var1) var2 = 0; else var2 = 1; return var2; } 

in the following way

 bool near f( bool ): L$1: test al,al sete al ret bool near g( bool ): jmp L$1 

That is, from the function g , jmp is made to the beginning of the function f.

It turns out that the function g has an extra jmp compared to f .

  • Why is this needed and why it was impossible to simply combine the function g itself with f ?

     bool near f( bool ): bool near g( bool ): test al,al sete al ret 
  • What does the standard say on this subject? For example, is there a clause that pointers to two different functions must be different? If so, what does he give?

  • What are the advantages of such an implementation?

2 answers 2

Based on the discussion here :

No, addresses should not be equal

Standard, 5.10 / 2.2-3 , reads as follows:

- Otherwise, if the pointers are both null, both are the same address ([basic.compound]), they compare equal.

- Otherwise, the pointers compare unequal.

The compiler has the right , however, to make them equal in the as-if rule, that is, if it does not affect the visible result of the program. Therefore, even if a particular compiler has combined functions in the absence of obtaining and comparing their addresses, this is not a violation of the standard. (The compiler generally has the right to throw out all functions if no one notices.)


About the possible practical use of this rule. Suppose we have a container of functions (function pointers) std::unordered_set example, std::unordered_set — with a condition of uniqueness. If two independent parts of the code add a locally defined function that is invisible to other parts of the code, they can be sure that the function has a unique address and will be actually added. Otherwise, adding a locally defined function might not work if in another place another code added a local function with the same code.

Another example of when non-gluing functions is useful from the discussion mentioned: SIG_IGN and SIG_DFL must be different addresses. The implementation of the standard library may well use the empty functions void ign(int) { } and void dfl(int) { } . Sticking these functions will break the code.

  • "both point to the same function" - and this is not a catch? That is, if different functions are required to have different addresses, then this piece of the phrase can simply be thrown out and the meaning will not change. But here they are for some reason mentioned. Is there anything interesting in the understanding of the "same function"? - Qwertiy
  • @Qwertiy: Well, this seems to be the piece that claims that different functions should have different addresses. - VladD
  • Different in place in the source, or different in content? - Qwertiy
  • Yes, but where are the lines here? Equality of strings is definitely not guaranteed. Perhaps the function is somewhere nearby. - Qwertiy
  • @Qwertiy: In the standard, there is no equality anywhere on the same code. For example, in ODR, functions with different names are considered different regardless of whether they have the same implementation. - VladD

It does this with the default optimization. You rushed to the question - I compiled the same code with maximum optimization, and it successfully merged the functions into one (added to the original answer):

 Module: G:\Tmp\test.c GROUP: 'DGROUP' CONST,CONST2,_DATA Segment: _TEXT PARA USE32 00000009 bytes 0000 f_: 0000 g_: 0000 85 C0 test eax,eax 0002 0F 94 C0 sete al 0005 0F B6 C0 movzx eax,al 0008 C3 ret Routine Size: 9 bytes, Routine Base: _TEXT + 0000 

The suspicion that full optimization is multi-pass, and by default, there is only one pass. I can not prove :), but this hypothesis explains this behavior ...

  • Yet it is unclear whether such optimization is permitted by the standard. - VladD
  • @VladD, why not? - Grundy
  • @VladD Since both functions are in the same source file, I think, completely. Any change to either of these will require recompiling both. - Harry
  • @Grundy: Well, as if this is the question. - VladD
  • @VladD, what if I write if (f == g) ? And even better if (x == f) , and someone gives me an equal pointer, but to another function? Or is this another UB? Like with strings if (x == "abc") - Qwertiy