2

A signed& cannot be initialized from an unsigned& (and vice versa), but strict aliasing rules allow to read/write a signed object through an unsigned& (and vice versa), see C++20 standard [basic.lval]#11.2. This theoretically could be used in compiler optimizations, if the as-if rule is not violated.

Example 1. If I am correct, f could be implemented by just a jump to foo:

void foo(const unsigned& u);

void f(const signed& par)
{
    foo(par);
}

But all compilers load par to a register, store the register on the stack, and pass the stack location to foo. Live demo.

Example 2. Similarly I think g1 and g2 could point to the same memory location:

const signed&   g1 = 1;
const unsigned& g2 = g1;

But compilers tend to allocate two different locations. Live demo.

Question. Why is that? Isn't it a missed opportunity for optimization?

Dr. Gut
  • 2,053
  • 7
  • 26

1 Answers1

3
const signed&   g1 = 1;
const unsigned& g2 = g1;

But compilers tend to allocate two different locations.

Here, what is happening is that g1 is converted to a temporary unsigned int and g2 binds to this temporary. And C++ guarantees that different objects have different addresses, thus g1 and g2 need to be stored separately.

Same with your function example. The key point is that having different addresses is an observable behavior. These functions could rely on the fact that their arguments have different addresses because they are references to different objects. If your compiler merged different objects into the same memory space, this observable behavior would change, thus it is not covered under the as-if rule.

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
  • Your argument makes sense for the global vars, but not the functions. You're saying that two instances of the same function call running simultaneously (e.g. in different threads) have to be able to compare the addresses of their function args and find them different because they're references of different types, since the source doesn't do any type-punning so a copy has to get made? Or you mean comparing `&par` against `&g2` or something and being guaranteed to find that it's different? – Peter Cordes Nov 10 '22 at 15:32
  • 1
    @PeterCordes Consider [this](https://gcc.godbolt.org/z/rahKbevb3). Line 6 **must not** fail, since these are different objects. If the function argument were "optimized" to be the same memory, it would fail. – Aykhan Hagverdili Nov 10 '22 at 15:46
  • 1
    @AyxanHaqverdili: So [\[basic.lval\]#11.2](https://timsong-cpp.github.io/cppwp/n4861/basic.lval#11.2) _could_ be used in optimization, _if_ the as-if rule were not violated. But in both examples my proposed optimization would make an _observable_ change, therefore it cannot be optimized this way. Is that correct? – Dr. Gut Nov 10 '22 at 16:56
  • @Dr.Gut That is exactly right. I expanded the answer with more information from the comments. – Aykhan Hagverdili Nov 10 '22 at 17:23
  • Fair enough. It seems like not a very important distinction that it's hard to imagine could break a real program, but the same semantics apply to non-const references (I assume), that it still has to make a temporary copy and pass a reference to that. So modification won't update the original. Unlike if you'd taken the address yourself and passed a pointer. (Which would require a cast of the pointer type.) – Peter Cordes Nov 10 '22 at 17:57
  • And as you demonstrate, it's possible to construct a program that observes the difference required by that language rule, so compilers can't ignore it except when inlining. Or with whole-program optimization. – Peter Cordes Nov 10 '22 at 17:59
  • @PeterCordes yeah, that whole "All addresses are unique" thing is not very useful in my experience in general. – Aykhan Hagverdili Nov 10 '22 at 19:39
  • @AyxanHaqverdili: Historically, the Standard has been excessively loath to recognize sitautions where a useful optimizing transforms might change the behavior of some action into some *observably differnet, but just as useful* behavior. Allowing trivial or const objects to share addresses would cause far less practical problems than many other "optimizations" that compiler writers insist that programmers should jump through hoops to accommodate. – supercat Nov 14 '22 at 21:46