[IR] GlobalIFunc with declaration as resolver

Hi all,

We've had a lengthy discussion in [1] regarding GlobalIFunc whose
resolver is a declaration, and I wanted to get wider feedback for the
IR-level semantics.

The ELF object file semantics require the resolver to be defined in
the same TU as the ifunc [2] and Clang and GCC require the same when
using 'plain' attribute((ifunc("..."))), diagnosing that it must be a
defined function [3]. The same applies for aliases and their aliasees.
The LLVM Verifier requires that aliasees not be declarations [4], but
the same currently does not hold for GlobalIFunc (Verifier code for
GlobalIFunc was added in [1], defined-check was reverted due to
breaking CFE attribute cpu_specific).

The implementation of attributes cpu_dispatch and cpu_specific in CFE
currently depends on GlobalIFunc with a declaration for a resolver, in
the case when cpu_specific is specified in a TU and cpu_dispatch is
not. Trunk currently has broken codegen for references against such
ifuncs in the same TU [5], but there's reference to a downstream
(codegen-level?) patch which could fix it [6]. I don't know what
semantics the patch implements, but two options come to mind:
* Replace uses of GlobalIFunc with result of call to resolver; this
can work only in code, not in gvar initializers, and it nullifies
benefit of using an ifunc.
* 'downgrade' GlobalIFunc to a function declaration, dropping
'connection' to resolver (valid only when it has odr linkage? didn't
think this through). This creates a small representational redundancy
(ifunc with undefined resolver ~== func decl).

A different approach is to declare GlobalIFunc with undefined resolver
to be invalid IR, and thus bring it in line with the very similar
construct of GlobalAlias. This would necessitate a change to the
implementation of cpu_specific/cpu_dispatch to avoid breaking support
for defining them in separate TUs. A problem with that is that it
creates an issue similar to [7], where CFE would sometimes need to
emit a function declaration and later 'upgrade' it to a GlobalIFunc
upon encountering cpu_dispatch. CFE devs wish to avoid introducing
additional RAUW module mutations in this way. My understanding is that
this is because it harms incremental compilation scenarios, but I
don't know the full technical aspects of this.

~ Itay

[1] ⚙ D112349 [Verifier] Add verification logic for GlobalIFuncs
[2] GNU_IFUNC - glibc wiki
[3] llvm-project/CodeGenModule.cpp at 99d5cbbd7e33b620f5f4725ffa04ce15d2794a14 · llvm/llvm-project · GitHub
[4] llvm-project/Verifier.cpp at 99d5cbbd7e33b620f5f4725ffa04ce15d2794a14 · llvm/llvm-project · GitHub
[5] ⚙ D112349 [Verifier] Add verification logic for GlobalIFuncs
[6] ⚙ D112349 [Verifier] Add verification logic for GlobalIFuncs
[7] llvm-project/CodeGenModule.cpp at 05f34ffa216975f132fa1bd4cbf8424053a19147 · llvm/llvm-project · GitHub