Are modern C++ compilers able to avoid calling a const function twice under some conditions?

早过忘川 提交于 2019-12-03 10:29:58

问题


For instance, if I have this code:

class SomeDataProcessor
{
public:
    bool calc(const SomeData & d1, const SomeData & d2) const;
private:
    //Some non-mutable, non-static member variables
}

SomeDataProcessor sdp;
SomeData data1;
SomeData data2;

someObscureFunction(sdp.calc(data1, data2),
                    sdp.calc(data1, data2));

Let's consider the potentially equivalent code:

bool b = sdp.calc(data1, data2);
someObscureFunction(b,b);

For this to be valid, the calc() function should meet some requirements, and for the example I call the property _pure_const_formula_

A _pure_const_formula_ would:

  • Not change any member, static or global variable state
  • Call only _pure_const_formula_ functions
  • Maybe some other conditions that I don't have in mind

For instance, calling a random number generator would not fit these requirements.

Is the compiler allowed to replace the first code with the second one, even if it needs to dig recursively into called functions? Are modern compilers able to do this?


回答1:


GCC has the pure attribute (used as __attribute__((pure))) for functions which tells the compiler that redundant calls can be eliminated. It's used e.g. on strlen.

I'm not aware of any compiler doing this automatically, especially considering the fact that the functions to be called may not be available in source form, and the object file formats contain no metadata about whether a function is pure or not.




回答2:


Yes, absolutely.

Compilers do this all the time, and more.

For example, if all your function did were return true, and its definition were visible to the compiler at the callsite, the entire function call would probably be elided, resulting in just:

someObscureFunction(true, true);

A program for which the compiler has sufficient information may be "optimised" from a quite complex chain of tasks down to perhaps one or two instructions. Now, actually operating on member variables is pushing the optimiser to its limit to some degree, but if the variables are private, are given a known initial value, and are not mutated by any other member function, I don't see why a compiler couldn't just inline its known value if it wanted to. Compilers are very, very smart.

People think that a compiled program is a one-to-one mapping of lines in your source code, but this is almost never true. The entire purpose of C++ is that it is an abstraction of what your computer's actually going to be doing when it runs your program.




回答3:


No, given the shown code, the compiler cannot guarantee that the proposed optimization will have no observable differences, and no modern compiler will be able to optimize away the second function call.

A very simple example: this class method might use a random number generator, and save the result in some private buffer, that some other part of the code reads later on. Obviously, eliminating a function call now results in fewer randomly-generated values being placed in that buffer.

In other words, just because a class method is const does not mean that it has no observable side effects when it's called.




回答4:


No, the compiler is not allowed to do that in this case. The const only means you do not change the state of the object the method belongs to. However, invoking this method multiple times with the same input parameters might give different results. For example, think of a method that produces a random result.




回答5:


Yes, modern C compilers can elide redundant function calls if and only if they can prove that such an optimization behaves as-if the original program semantics were followed. For example, that means means they could eliminate multiple calls to the same function with the same arguments, if the function has no side-effects and if its return value depends only on the arguments.

Now, you asked specifically about const - this is mostly useful to the developer, and not the coder. A const function is a hints that the method doesn't modify the object it is called on, and const arguments are hints that the arguments are not modified. However, the function may (legally1) cast away the const-ness of the this pointer or of its arguments. So the compiler can't rely on it.

Furthermore, even if const objects passed to a function really were never modified within that function, and const functions never modified the receiver object, the method could easily rely on mutable global data (and could mutate such data). Consider, for example, a function that returns the current time, or which increments a global counter.

So the const declarations help the programmer, not the compiler2.

However, the compiler might be able to use other tricks to prove the calls are redundant:

  • The function may be in the same compilation unit as the caller, allowing the compiler to inspect it and determine exactly what it relies on. The ultimate form of this is inlining: the function body may be moved into the caller at which point the optimizer can remove redundant code from later calls (up to an including all the code from those calls entirely and perhaps all or port of the original call too).
  • The toolchain may use some type of link-time-optimization, which effectively allows the type of analysis described in the point above even for functions and callers in different compilation units. This could allow this optimization for any code present when the final executable is being generated.
  • The compiler may allow the user to annotate a function with an attribute that informs the compiler that it may treat the function as not having side-effects. For example, gcc provides the pure and const function attributes which inform gcc that the functions has no side effects, and depend only on their parameters (and on global variables, in the case of pure).

1 Usually, as long as the object wasn't originally defined as const.

2 There is at one sense in which const definitions do help the compiler: they can put global objects defined as const into a read-only section of the executable (if such a feature exists) and also combine such objects when they are equal (e.g., identical string constants).



来源:https://stackoverflow.com/questions/42227535/are-modern-c-compilers-able-to-avoid-calling-a-const-function-twice-under-some

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!