inline functions should be emit to the calling CU.
they should be assigned an appropriate link flag such that linker appropriately handles duplicate symbols:
inline = 'linkonce' (like `inline` in C)
private inline = 'internal' (like `static inline` in C)
ie; LLVM enumerates the linker flags: https://llvm.org/docs/LangRef.html#linkage-types
Specifically, this should work:
---------------------
lib.d
-----
module lib;
pragma(inline, true)
void inl() {}
test.d
------
import lib;
int main()
{
inl();
return 0;
}
---------------------
Expect:
> dmd test.d
No link error!
Currently:
> error LNK2019: unresolved external symbol "void lib.inl()" (__D3lib3inlFZv) referenced in function __Dmain
IMO, `pragma(inline, true)` should clearly keep on being a strong hint for the optimizer to inline a function into callers, everything else would be a bad misnomer following C++.
I do deem the request for linkonce_odr emission into each referencing CU as valid, but it should use another syntax.
As to `internal` linkage for `private pragma(inline, true)` IIUC - what's the justification for the private special case and a reason *not* to fold any remainining multiple definitions to a single one when linking?
Comment #3 by turkeyman — 2020-06-13T02:37:37Z
It's not clear that it does... it doesn't look like it emits the function to the calling CU at all. Is the inline a front-end trick in DMD such that it just doesn't need to emit the function at all?
What happens if you take the address of the function instead of calling it? Will the link error return?
Comment #4 by turkeyman — 2020-06-13T02:44:48Z
> I do deem the request for linkonce_odr emission into each referencing CU as valid, but it should use another syntax.
Which is why I proposed allowing more fidelity in the argument to the pragma.
Perhaps something like:
pragma(inline, true) - linkonce
pragma(inline, always) - strong hint that inlining should occur if possible
pragma(inline, force) - compile error if inline fails
These map to the 3 distinct use cases I referred to in my forum OP.
What alternative proposal would you suggest for `linkonce`? That's what 'inline' actually means to most native programmers... deviating from that precedent would likely be _more_ confusing rather than less.
Comment #5 by kinke — 2020-06-13T03:00:09Z
(In reply to Manu from comment #4)
> Which is why I proposed allowing more fidelity in the argument to the pragma.
> Perhaps something like:
> pragma(inline, true) - linkonce
> pragma(inline, always) - strong hint that inlining should occur if possible
> pragma(inline, force) - compile error if inline fails
>
> These map to the 3 distinct use cases I referred to in my forum OP.
> What alternative proposal would you suggest for `linkonce`? That's what
> 'inline' actually means to most native programmers... deviating from that
> precedent would likely be _more_ confusing rather than less.
That's wild speculation on your part. ;) I don't find anything with `inline` acceptable; I'm a C++ guy too, but I also try to keep in mind future generations of D devs.
pragma(inline, <true|false>) are already reserved and make sense. Making `pragma(inline, true)` mean linkonce_odr emission into each referencing CU (and absolutely having to do nothing with actual inlining into callers), and `pragma(inline, false)` mean never-inline-into-any-callers-and-only-emit-into-owning-CU just isn't sound.
I don't have a thought-through alternative proposal because this isn't of high enough interest to me. From the LDC side, we could simply add a UDA and allow the user to specify the LLVM linkage directly if desired - à la `@linkonce`.
Comment #6 by kinke — 2020-06-13T03:07:13Z
(In reply to kinke from comment #5)
> Making `pragma(inline, true)` mean linkonce_odr emission into each referencing
> CU (and absolutely having to do nothing with actual inlining into callers)
That's wrong on my part; emitting the function into each referencing CU does enable 'normal' inlining (excl. DMD with its AST-based inlining) in non-owning CUs. It's basically a way to selectively enable potential cross-module/CU inlining for a function, without extra inlining hints.
Comment #7 by turkeyman — 2020-06-13T03:29:43Z
> and `pragma(inline, false)` mean never-inline-into-any-callers-and-only-emit-into-owning-CU just isn't sound.
Fair. This is where the forum thread should have gone.
Alternative suggestions welcome... but it still needs to work.
To be fair though; `pragma(inline, false)` isn't really clear from any perspective. What should it mean normally? Is it supposed to mean something useful? I don't think it's likely anyone would ever want that.
Comment #8 by kinke — 2020-06-13T03:41:28Z
(In reply to Manu from comment #7)
> To be fair though; `pragma(inline, false)` isn't really clear from any
> perspective. What should it mean normally? Is it supposed to mean something
> useful? I don't think it's likely anyone would ever want that.
I doubt there are many cases for it outside of testcases, but there are some, e.g., inline asm with stack alignment assumptions here: https://github.com/ldc-developers/druntime/blob/f5e154743d844c5ec1ea3b086abb6daca6e1713b/src/core/thread/fiber.d#L250-L252
Comment #9 by turkeyman — 2020-06-13T04:20:32Z
You're proposing that `pragma(inline, false)` is essentially a request for force-not-inline though?
That's not the clear meaning.
Not-force-inline, or not logically the same as force-not-inline; not-force-inline sounds like it may still be subject to the compilers discretion.
So if,
pragma(inline, true) == absolutely-force-inline
pragma(inline, false) == force-not-inline
... what is the default un-opinionated state? How do we specify the 'hint' request for a strong preference but not a hard error?
I just don't think the bool is the proper argument here; it should draw from an enum of possibilities.
Perhaps the complete set is: (default, never, always, preferred [for the strong hint])
Comment #10 by kinke — 2020-06-13T12:35:16Z
(In reply to Manu from comment #9)
> You're proposing that `pragma(inline, false)` is essentially a request for
> force-not-inline though?
I'm not proposing, never-inline (in LLVM lingo: `noinline`) is what it stands for today. There are 38 occurrences in (LDC) druntime.
> So if,
> pragma(inline, true) == absolutely-force-inline
> pragma(inline, false) == force-not-inline
> ... what is the default un-opinionated state? How do we specify the 'hint'
> request for a strong preference but not a hard error?
There's no such thing as absolutely-force-inline in LLVM. I also don't think we need that.
`pragma(inline, true)` for LDC is `alwaysinline` + emission into each referencing CU (currently as available_externally in non-owning CUs though, which is weaker than linkonce_odr). I don't know when LLVM does NOT inline, I haven't seen that case yet.
Comment #11 by robert.schadek — 2024-12-13T19:09:14Z