0

I'm mostly interested in C and C++, but I think this question can also apply to other languages.

My question is, if an unamed object or value is generated from the evaluation of an expression or function, can it be cached if that same expression or function is later called, and the compiler recognizes that the result is unchanged.

Demonstrated in the below examples

    x=(a+b)/c;
    y=(a+b)/c;
    a+=x;
    z=(a+b)/c;

and

int my_function()
{
    return (a+b)/c;
}

int main()
{
    x=my_function();
    y=my_function();
    a+=x;
    z=my_function();
}

The compiler will cache the result of the expression (a+b)/c, or the function my_function when assigning x, and change the assignments of y to a reference to the cached result, without the calculation or function having to be performed again. But since their is a visible change to that expression or function with a+=x, z is assigned by reevaluating (a+b)/c, or calling my_function a second time.
This question also applies to larger data types, like structs and classes, which I imagined could be assigned to the current stack frame like local variables, but unnamed and not directly accessible by the programmer.

While typing this, I saw another question asking the same thing about Python, referencing the C++ standard, which stated that a temporary object does not last after the statment it is created in.
https://stackoverflow.com/questions/9046606/are-temporary-references-automatically-cleared-in-python
So, my question is, even if that object no longer exists within the rules of the language, can it still be retained by the the compiler as a form of optimization, if it detects that within the rules of the language the same evaluation or function call will yield the same result.

I want to effectively treat a function call or expression like a stored variable in situations where I know it will return the same result, without it performing the evaluation or function call each time. Do I have to assign the result to a named variable to achieve this.

The compiler I am using is GCC.

17
  • 2
    You will have to examine the generated assembly. There are no guarantees, compilers can do anything they feel like so long as the code exhibits the correct behaviour. Feb 27, 2022 at 18:48
  • @PhilipKendall Thank you for your response. Even if I can't guarantee it, have compilers been known to do this? Is this something I can expect, or should I declare a named variable each time I want to reuse a result from a complex evaluation. Feb 27, 2022 at 19:04
  • 2
    You should worry about clarity first and only worry about performance once you have shown that this is actually on your hot path. Feb 27, 2022 at 19:15
  • 1
    Compilers are smart in some ways, dumb in others. It tends to be difficult for compilers to reason about temporal relationships. I wouldn't expect any compiler to do your optimization unless some code calls the target function multiple times, the compiler inlines the calls, and the compiler sees that the value cannot change. However, the compiler might not be able to prove that if pointers are involved due to “aliasing”. I would not expect the compiler to change a function so that it always caches the return value, you'd have to implement that manually. You could write a Clang plugin though.
    – amon
    Feb 28, 2022 at 0:43
  • 1
    C and C++ have the “as if” rule: The compiler can do anything it likes, any optimisation, if the code behaves as if the original code had been executed. As long as a standard conforming program cannot detect the difference. In your example, the caller can be compiled as y = x = my_function(). I can say that because I understand the code; a compiler may find it difficult to know that the change is valid.
    – gnasher729
    Mar 9, 2022 at 21:08

1 Answer 1

4

if the object no longer exists within the rules of the language, can it still be retained by the the compiler

Can it? Yes, so long as the language model doesn't forbid it. Does it? Check and see. You can say it should be optimized but I can call it a security risk. But we don't matter. What matters is what the model promised you, or didn't. If it didn't it's just an implementation detail of the compiler. It does whatever the implementer decides. The standards don't decide everything.

Can I effectively treat a function call like a variable in a situation like this, without it being called each time, or should I assign an evaluation or function call to a named variable, if I want to use that value more than once?

This is a different question. To cache or not to cache is one of the hardest questions in computer science. Knowing if the compiler does it for you already would be nice to know but understand, just because your particular compiler behaves one way doesn't mean some poor unsuspecting fool wont come along later and notice that they can compile your code on something else. Something else that behaves differently.

So if you’re going to bake in assumptions about how your compiler is going to behave that are outside what the language standard guarantees I beg you to document them where such fools can easily find them. Because I've been such a fool. I was not amused.

1
  • Thank you for your response. My question is specifically, are compilers generally known to do this, particularly GCC. Or if this is something that is impossible or impractical to implement, and no compiler does this. I understand that a a feature can not be guaranteed if they are not specified by the standard, but I wondered if the is still something that I could generally expect from most compilers. Mar 9, 2022 at 18:38

Not the answer you're looking for? Browse other questions tagged or ask your own question.