I'm not a compiler expert, but my impression is it's sort of the other way around. First the compiler tries to optimize the code. If after optimization, the address of the variable is not needed, then it is a candidate to be put in a register (or perhaps optimized completely out of existence).
Of course if the & operator is never applied to the variable at all, then it is certainly a candidate. But even if &x does appear in the source code, the need for the address may go away after optimization.
As a trivial example, if we have
int x = 7;
foo(*&x);
the compiler can see that *&x is exactly equivalent to x, and so the code can be treated as if it were just foo(x). If the address of x is not taken anywhere else, then it no longer needs to have an address at all, and can go in a register.
Now you can imagine extending this sort of analysis to more complicated code.
int x = foo1(), y = foo2();
int *p;
p = cond ? &x : &y;
return *p;
Try it on godbolt
Conceptually, this can be successively rewritten as
return *(cond ? &x : &y);
return cond ? *&x : *&y;
return cond ? x : y;
and now x,y no longer need to have addresses, and p no longer needs to exist at all.
So in other words, the compiler doesn't try to "emulate" the & operator; rather, it tries to restructure the code so that it simply isn't needed.
The most common situation where this is not possible is if the address of the variable is passed to another function.
int x;
foo(&x);
Unless foo can be inlined or some other sort of interprocedural analysis is available, the compiler really does have to pass the address of something to foo, and so x has to exist in memory, at least for that moment. Of course, the compiler can choose to move it into a register immediately thereafter, and keep it there for the rest of the function if its address is not needed again; the question of whether a variable lives in memory or in a register need not be fixed for all time.