15

I have a pointer int* p, and do some operations in a loop. I do not modify the memory, just read. If I add const to the pointer (both cases, const int* p, and int* const p), can it help a compiler to optimize the code?

I know other merits of const, like safety or self-documentation, I ask about this particular case. Rephrasing the question: can const give the compiler any useful (for optimization) information, ever?

jørgensen
  • 10,149
  • 2
  • 20
  • 27
Jakub M.
  • 32,471
  • 48
  • 110
  • 179
  • 3
    Do you really mean `int const* p`? Or `int* const p`? What loop? What are you iterating over? – Lightness Races in Orbit Jan 31 '12 at 10:46
  • 1
    You could just do it and compare the generated code :-? – cnicutar Jan 31 '12 at 10:47
  • 1
    The only way to determine this for a given CPU, compiler, OS, etc is to benchmark it, and the result will then only be valid for this particular configuration of course. It sounds like premature optimisation to me. – Paul R Jan 31 '12 at 10:49
  • have a look at [this](http://stackoverflow.com/questions/212237/constants-and-compiler-optimization-in-c) – StevieG Jan 31 '12 at 10:58
  • @cnicutar: of course I can and I did. For simple code I saw no difference, but I assumed that compiler can figure out that the memory is not modified, for a few small loops. What I don't know is if the compiler *always* knows everything. – Jakub M. Jan 31 '12 at 10:59
  • 2
    @JakubM. Then in the end do what's most natural. If the memory need not be changed, make it const and call it a day. – cnicutar Jan 31 '12 at 11:00
  • 1
    Instead of looking for optimizations in those calls and ruining the API and readability of your functions you might want to look for bottlenecks elsewhere. That said, I can imagine that a you might find a difference in speed if you do a huge number of calls to a function with / without const modifier, because the compiler needs to insert a cast at the callee. – Bort Jan 31 '12 at 11:11
  • I believe you are looking for the "restrict" keyword. ====== In a nutshell, the restrict keyword tells the compiler that the memory being pointed to is not aliased. The compiler can then make more aggressive optimizations (ex: out of order execution, etc) as compared to when it must assume that the memory being pointed to is aliased. – Trevor Boyd Smith Jan 31 '12 at 13:18

6 Answers6

6

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.

Mankarse
  • 39,818
  • 11
  • 97
  • 141
  • This is simply wrong; `int const*` is equivalent to `const int *` which does *not* point to writeable memory. (What you mean is probably `int * const`) – Jo So Dec 15 '13 at 02:37
  • 1
    @JoSo: No, this is correct. All that `int const *` indicates is that the `int` may not be modified through that particular pointer. If the `int` was originally non-const, then it can be modified by another part of the code, or can be modified by the same part of the code after a cast. – Mankarse Dec 15 '13 at 22:37
  • I got your answer wrong, and cannot retrace how this happened. Sorry for that. Worse, obviously it's not allowed to remove a (down)vote unless the answer is edited... :( – Jo So Dec 16 '13 at 00:02
3

No. Using const like that will not provide the compiler with any information that can be used for optimization.

Theoretically, for it to be a help to your compiler, the optimizer must be able to prove that nobody will ever use const_cast on your const pointer yet be unable to otherwise prove that the variable is never written to. Such a situation is highly unlikely.

Herb Sutter covers this is more depth in one of his Guru of the Week columns.

JoeG
  • 12,994
  • 1
  • 38
  • 63
  • If the compiler *is* able to prove all that additional information, it does not need the `const` qualification anymore. So even then the `const` will not help with optimisation. – Mankarse Jan 31 '12 at 11:21
  • @Mankarse: unless for some silly implementation-specific reason, e.g. a particular optimizer doesn't bother doing the analysis unless the pointer is const-qualified. But you're still correct in what you say, because by my argument *anything* can affect optimzation -- the number of vowels in your variable names, or whether you indent with tabs vs spaces. The only question is how plausible it is that the optimizer ignores certain potentially-useful information in some circumstances but not others. – Steve Jessop Jan 31 '12 at 12:32
2

It can help or it can make no difference or it can make it worse. The only way to know is to try both and inspect the emitted machine code.

Modern compilers are very smart so they can often deduce that memory is unchanged without any qualifiers (pr they can deduce many other optimizations are possible without code being written in manner easier to analyze) yet they are rather complex and so have a lot of deficiencies and often can't optimize every possible thing at every opportunity.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • Do you have any example when it can make it worse? – Jakub M. Jan 31 '12 at 11:00
  • @Jakub M.: Not for this specific case, but I've seen literally dozens of cases when a compiler failed to emit optimal code. – sharptooth Jan 31 '12 at 11:28
  • 2
    *it can make it worse* is rather an overstatement and too generalized statement unless substantiated with an example, `const` can make no difference or *some* difference, and the difference is negligible enough to not consider it's usage as a optimization criteria, it should only be used to write a more correct maintainable code. – Alok Save Jan 31 '12 at 11:38
1

I think the compiler can't do much in your scenario. The fact that your pointer declared as const int * const p doesn't guarantee that the memory can't be changed externally, e.g. by another thread. Therefore the compiler must generate code that reads the memory value on each iteration of your loop.

But if you are not going to write to the memory location and you know that no other piece of code will, then you can create a local variable and use it similar to this:

const int * p = ...
...
int val = *p;
/* use the value in a loop */
for (i = 0; i < BAZILLION; i++)
{
    use_value(val);
}

Not only you help potential readers of your code to see that the val is not changed in a loop, but you also give the compiler a possibility to optimize (load val in a register, for instance).

Igor Korkhov
  • 8,283
  • 1
  • 26
  • 31
  • 2
    Compilers usually don't consider other threads unless you specifically add volatile. Any function call would get in the way though. – Per Johansson Jan 31 '12 at 14:01
  • @PerJohansson: you are probably right. Anyway, another thread was just an example. Side effect of any function call is a good example, too. I just wanted to point out that any optimization performed by the compiler must (and does!) preserve original semantics of the code, while optimizing out memory reads inside a loop certainly doesn't, and therefore will not be performed. But since there's no legal way to change the `val` externally (outside of the function body), the compiler is free to optimize. – Igor Korkhov Jan 31 '12 at 14:16
1

Using const is, as everyone else has said, unlikely to help the compiler optimize your loop.

It may, however, help optimise code outside the loop, or at the site of a call to a const-qualified method, or to a function taking const arguments.

This is likely to depend on whether the compiler can prove it's allowed to eliminate redundant loads, move them around, or cache calculated values rather than re-calculating them.

The only way to prove this is still to profile and/or check the assembly, but that's where you should probably be looking.

Useless
  • 64,155
  • 6
  • 88
  • 132
1

You don't say which compiler you are using. But if you are both reading and writing to memory you could benefit from using "restrict" or similar. The compiler does not know if your pointers are aliasing the same memory so any store often forces loading other values again. "restrict" tells the compiler that no aliasing of the pointer is happening and can keep using values loaded before a subsequent write. Another way to avoid the aliasing issue is to load your values into local variables then the compiler is not forced to reload after a write.

Darren B
  • 122
  • 3