On Fri, 5 Jun 2026, Richard Biener wrote:
> On Fri, 5 Jun 2026, Robin Dapp wrote:
>
> > >>> Please give an overview of what APEX is and why LTO currently
> > >>> cannot handle it.
> > >>>
> > >>> Richard.
> > >
> > >> Luis, is the problem just that we need consistent builtin numbering
> > >> (which
> > >> requires special care with dynamically enabled builtins but should still
> > >> be
> > >> possible) or is there more to it?
> > >
> > >> --
> > >> Regards
> > >> Robin
> > >
> > > Hi Richard, Robin,
> > >
> > > APEX (ARC Processor EXtension) is a mechanism for integrating custom
> > > instructions into GCC without requiring users to have detailed knowledge
> > > of
> > > compiler internals. It allows users to define custom instructions via C
> > > pragmas
> > > and assembler directives.
> > >
> > > A function prototype is used to represent a custom instruction, and a
> > > pragma
> > > binds it to instruction metadata (e.g., mnemonic, opcode), effectively
> > > making it
> > > behave like a builtin:
> > >
> > > ```c
> > > int foo_func (int, int);
> > > #pragma intrinsic (foo_func, "foo", 7, XD)
> > >
> > > int main (void)
> > > {
> > > return foo_func (1, 2);
> > > }
> > > ```
> > >
> > > which generate:
> > > ```asm
> > > .extInstruction foo,7,XD
> > > main:
> > > li a5,2
> > > li a0,1
> > > foo a0,a0,a5 # APEX instruction
> > > ret
> > > ```
> > >
> > > The issue with LTO is that APEX intrinsics are registered dynamically
> > > during
> > > front-end processing via pragmas. This registration state is not preserved
> > > through LTO.
> > >
> > > By the time LTO reads the serialized GIMPLE back in, the original pragma
> > > processing phase has already completed, so the backend no longer has any
> > > record
> > > of the intrinsic definition (mnemonic, opcode, operand constraints). As a
> > > result, the call cannot be resolved against any known intrinsic entry,
> > > leading
> > > to an ICE during validation.
> > >
> > > In response to Robin’s question: it is a bit more than just builtin
> > > numbering.
> > >
> > > It is not only about having a stable identifier across LTO, but also about
> > > preserving and restoring the intrinsic registration itself. Even with
> > > consistent
> > > numbering, the backend still lacks the metadata required to reconstruct
> > > the
> > > intrinsic after LTO.
> >
> > But we do know all possible intrinsics, statically?
>
> I don't read it this way.
>
> > Can't we (dummy) "initialize" them so there are placeholders to fall back
> > to?
> >
> > I haven't looked in detail (sorry) and just saw the "trick GCC into" which
> > might already indicate something like that?
>
> The GCC canonical way of doing what APEX does would be
>
> extern inline __attribute__((gnu_inline))
> int foo_func (int a, int b)
> {
> int res;
> __asm__ (".byte 7, XD" : "=r" (res) : "r" (a), "r" (b));
> return res;
> }
>
> and I'd implement "fancy" (producing the appropriate register operand
> mnemonic piece) via output templates and assembler extensions.
That said, the extension is probably driven from the LLVM side
where there's an internal assembler available. So even w/o that
couldn't the target, upon parsing
#pragma intrinsic (foo_func, "foo", 7, XD)
generate the above inline function? Not sure if
.extInstruction foo,7,XD
is already the assembler extension required, if so then the
asm template can just have "foo %0, %1, %2", no?
> No need for #pragma or anything, it's just GCC extended asm and
> function-as-a-macro extension. This should all work with LTO
> already.
>
> Richard.
--
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)