Call to address 0 gets removed

Dale Johannesen wrote:

Marius Wachtler wrote:
...
The call to address 0 gets removed.

define i32 @t(i32 %a) noreturn nounwind readnone {
entry:
    unreachable
}

How can I prevent that the call is removed, without making the
function addr volatile?
Does anyone know which optimization removes it?

Calling 0 is undefined behavior; the optimizer is within its rights to
remove this. Why do you want to call 0?

Although a C translation unit may arguably not assign a correspondingly
defined function as having a pointer value (address) comparing equal to
((void *) 0); it's not clear that the standard forbids the invocation of
such a function, nor does it seem like a good idea to silently strip any
such invocations especially if allowed to be specified; as to do so would
seemingly only mask potentially legitimate problems, and/or prevent that
intended from being performed although potentially relying on an undefined
behavior.

(As for example, it's not hard to imagine that it may be desirable to allow
a machine which may trap such calls to do, and/or to allow the invocation of
some otherwise specified behavior although considered undefined by standard
itself.)

Dale Johannesen wrote:

Marius Wachtler wrote:
...
The call to address 0 gets removed.

define i32 @t(i32 %a) noreturn nounwind readnone {
entry:
   unreachable
}

How can I prevent that the call is removed, without making the
function addr volatile?
Does anyone know which optimization removes it?

Calling 0 is undefined behavior; the optimizer is within its rights to
remove this. Why do you want to call 0?

Although a C translation unit may arguably not assign a correspondingly
defined function as having a pointer value (address) comparing equal to
((void *) 0);

Nothing arguable about it, see C99 6.3.2.3

it's not clear that the standard forbids the invocation of such a function

No such function can exist. I don't think the standard forbids you to call 0, but it makes calling 0 undefined behavior ("behavior, upon use of a nonportable or erroneous program construct or of erroneous data"), since there can't possibly be a valid function there.

nor does it seem like a good idea to silently strip any
such invocations especially if allowed to be specified; as to do so would
seemingly only mask potentially legitimate problems, and/or prevent that
intended from being performed although potentially relying on an undefined
behavior.

(As for example, it's not hard to imagine that it may be desirable to allow
a machine which may trap such calls to do, and/or to allow the invocation of
some otherwise specified behavior although considered undefined by standard
itself.)

In general, a C compiler is not the right tool to use for functionality outside the C language, so I'm not inclined to be sympathetic to this line of reasoning.

In C++, my understanding is that the null pointer --
static_cast<void*>(0) -- need not be the pointer whose representation
is all unset bits -- reinterpret_cast<void*>(0) -- and that only
loads/stores/calls/etc on the former are undefined behaviour, as there
may be architectures or programming levels on which referring to
memory address 0 is perfectly reasonable.

Does C99 have such a distinction as well?

~ Scott