Does Const-Correctness Give the Compiler More Room For Optimization

Does const-correctness give the compiler more room for optimization?

[Edit: OK so this question is more subtle than I thought at first.]

Declaring a pointer-to-const or reference-of-const never helps any compiler to optimize anything. (Although see the Update at the bottom of this answer.)

The const declaration only indicates how an identifier will be used within the scope of its declaration; it does not say that the underlying object can not change.

Example:

int foo(const int *p) {
int x = *p;
bar(x);
x = *p;
return x;
}

The compiler cannot assume that *p is not modified by the call to bar(), because p could be (e.g.) a pointer to a global int and bar() might modify it.

If the compiler knows enough about the caller of foo() and the contents of bar() that it can prove bar() does not modify *p, then it can also perform that proof without the const declaration.

But this is true in general. Because const only has an effect within the scope of the declaration, the compiler can already see how you are treating the pointer or reference within that scope; it already knows that you are not modifying the underlying object.

So in short, all const does in this context is prevent you from making mistakes. It does not tell the compiler anything it does not already know, and therefore it is irrelevant for optimization.

What about functions that call foo()? Like:

int x = 37;
foo(&x);
printf("%d\n", x);

Can the compiler prove that this prints 37, since foo() takes a const int *?

No. Even though foo() takes a pointer-to-const, it might cast the const-ness away and modify the int. (This is not undefined behavior.) Here again, the compiler cannot make any assumptions in general; and if it knows enough about foo() to make such an optimization, it will know that even without the const.

The only time const might allow optimizations is cases like this:

const int x = 37;
foo(&x);
printf("%d\n", x);

Here, to modify x through any mechanism whatsoever (e.g., by taking a pointer to it and casting away the const) is to invoke Undefined Behavior. So the compiler is free to assume you do not do that, and it can propagate the constant 37 into the printf(). This sort of optimization is legal for any object you declare const. (In practice, a local variable to which you never take a reference will not benefit, because the compiler can already see whether you modify it within its scope.)

To answer your "side note" question, (a) a const pointer is a pointer; and (b) a const pointer can equal NULL. You are correct that the internal representation (i.e. an address) is most likely the same.

[update]

As Christoph points out in the comments, my answer is incomplete because it does not mention restrict.

Section 6.7.3.1 (4) of the C99 standard says:

During each execution of B, let L be any lvalue that has &L based on P. If L is used to
access the value of the object X that it designates, and X is also modified (by any means),
then the following requirements apply: T shall not be const-qualified. ...

(Here B is a basic block over which P, a restrict-pointer-to-T, is in scope.)

So if a C function foo() is declared like this:

foo(const int * restrict p)

...then the compiler may assume that no modifications to *p occur during the lifetime of p -- i.e., during the execution of foo() -- because otherwise the Behavior would be Undefined.

So in principle, combining restrict with a pointer-to-const could enable both of the optimizations that are dismissed above. Do any compilers actually implement such an optimization, I wonder? (GCC 4.5.2, at least, does not.)

Note that restrict only exists in C, not C++ (not even C++0x), except as a compiler-specific extension.

do const declarations help the compiler (GCC) produce faster code?

In general const modifier on method, references and pointers can't be used to optimize code for a couple of reasons. The primary one is that const modifier, in those contexts, doesn't make any guarantees about the underlying data not changing, it just makes it harder to modify it. Here is a classic example

void M(const C& p1, C& p2) { 
cout << p1.field << endl;
p2.Mutate();
cout << p1.field<< endl;
}

In this case it's very possible that p1.field is modified in this code. The most obvious case is that p1 and p2 refer to the same value.

C local;
M(local, local);

Hence there is no real optimization the compiler can do here. The const parameter is equally as dangerous as the non-const one.

The other reason why it can't really optimize is that anyone can cheat in C++ with const_cast.

class C { 
public:
int field;

int GetField() const {
C* pEvil = const_cast<C*>(this);
pEvil->field++;
return field;
}
};

So even if you are dealing with a single const reference the values are still free to change under the hood.

What kind of optimization does const offer in C/C++?

Source

Case 1:

When you declare a const in your program,

int const x = 2;

Compiler can optimize away this const by not providing storage for this variable; instead it can be added to the symbol table. So a subsequent read just needs indirection into the symbol table rather than instructions to fetch value from memory.

Note: If you do something like:

const int x = 1;
const int* y = &x;

Then this would force compiler to allocate space for x. So, that degree of optimization is not possible for this case.

In terms of function parameters const means that parameter is not modified in the function. As far as I know, there's no substantial performance gain for using const; rather it's a means to ensure correctness.



Case 2:

"Does declaring the parameter and/or the return value as const help the compiler to generate more optimal code?"

const Y& f( const X& x )
{
// ... do something with x and find a Y object ...
return someY;
}

What could the compiler do better? Could it avoid a copy of the parameter or the return value?

No, as argument is already passed by reference.

Could it put a copy of x or someY into read-only memory?

No, as both x and someY live outside its scope and come from and/or are given to the outside world. Even if someY is dynamically allocated on the fly within f() itself, it and its ownership are given up to the caller.

What about possible optimizations of code that appears inside the body of f()? Because of the const, could the compiler somehow improve the code it generates for the body of f()?

Even when you call a const member function, the compiler can't assume that the bits of object x or object someY won't be changed. Further, there are additional problems (unless the compiler performs global optimization): The compiler also may not know for sure that no other code might have a non-const reference that aliases the same object as x and/or someY, and whether any such non-const references to the same object might get used incidentally during the execution of f(); and the compiler may not even know whether the real objects, to which x and someY are merely references, were actually declared const in the first place.



Case 3:

void f( const Z z )
{
// ...
}

Will there be any optimization in this?

Yes because the compiler knows that z truly is a const object, it could perform some useful optimizations even without global analysis. For example, if the body of f() contains a call like g( &z ), the compiler can be sure that the non-mutable parts of z do not change during the call to g().

Constants and compiler optimization in C++

Let's disregard methods and look only at const objects; the compiler has much more opportunity for optimization here. If an object is declared const, then (ISO/IEC 14882:2003 7.1.5.1(4)):

Except that any class member declared
mutable (7.1.1) can be modified, any
attempt to modify a const object
during its lifetime (3.8) results in
undefined behavior.

Lets disregard objects that may have mutable members - the compiler is free to assume that the object will not be modified, therefore it can produce significant optimizations. These optimizations can include things like:

  • incorporating the object's value directly into the machines instruction opcodes
  • complete elimination of code that can never be reached because the const object is used in a conditional expression that is known at compile time
  • loop unrolling if the const object is controlling the number of iterations of a loop

Note that this stuff applies only if the actual object is const - it does not apply to objects that are accessed through const pointers or references because those access paths can lead to objects that are not const (it's even well-defined to change objects though const pointers/references as long as the actual object is non-const and you cast away the constness of the access path to the object).

In practice, I don't think there are compilers out there that perform any significant optimizations for all kinds of const objects. but for objects that are primitive types (ints, chars, etc.) I think that compilers can be quite aggressive in optimizing
the use of those items.

Can const-correctness improve performance?

const correctness can't improve performance because const_cast and mutable are in the language, and allow code to conformingly break the rules. This gets even worse in C++11, where your const data may e.g. be a pointer to a std::atomic, meaning the compiler has to respect changes made by other threads.

That said, it is trivial for the compiler to look at the code it generates and determine if it actually writes to a given variable, and apply optimizations accordingly.

That all said, const correctness is a good thing with respect to maintainability. Otherwise, clients of your class could break that class's internal members. For instance, consider the standard std::string::c_str() -- if it couldn't return a const value, you'd be able to screw around with the internal buffer of the string!

Don't use const for performance reasons. Use it for maintainability reasons.

Can adding 'const' to a pointer help the optimization?

While this is obviously specific to the implementation, it is hard to see how changing a pointer from int* to int const* could ever provide any additional information that the compiler would not otherwise have known.

In both cases, the value pointed to can change during the execution of the loop.

Therefore it probably will not help the compiler optimize the code.

How does const correctness help write better programs?

A whole section is devoted to Const Correctness in the FAQ. Enjoy!

C++ const-correctness and const members

check out about it at SO and also HERE

Should I use const for local variables for better code optimization?

Or am I wrong, and compilers can figure out by themselves that the local variable is never modified?

Most of the compilers are smart enough to figure this out themselves.

You should rather use const for ensuring const-correctness and not for micro-optimization.

const correctness lets compiler help you guard against making honest mistakes, so you should use const wherever possible but for maintainability reasons & preventing yourself from doing stupid mistakes.

It is good to understand the performance implications of code we write but excessive micro-optimization should be avoided. With regards to performance one should follow the,

80-20 Rule:

Identify the 20% of your code which uses 80% of your resources, through profiling on representative data sets and only then attempt to optimize those bottlenecks.

Are there any cases when marking objects as const results in a better optimized code (when compiled with optimizations)?

If you mark an object as const, the compiler can infer that it won't ever be modified (although it may have mutable members), and the value of the actual object can be inlined in a lot of places.

Knowing this, if you have something like an if statement or a loop condition which reads such an object, and the resulting boolean expression is always true or always false, the compiler can therefore eliminate any code branches it knows can't be reached.

Overall, though, the optimizations seem to be pretty negligible when stacked next to the real use case of the const keyword (code clarity / safety).

You might also want to take a look at this post, because he seems to summarize the possible optimizations in more detail :)



Related Topics



Leave a reply



Submit