Standard way to supply hints to branches
Quirin Schroll
qs.il.paperinik at gmail.com
Fri Sep 13 10:57:56 UTC 2024
On Friday, 13 September 2024 at 10:26:48 UTC, Richard (Rikki)
Andrew Cattermole wrote:
>
> On 13/09/2024 10:20 PM, Quirin Schroll wrote:
>> On Friday, 13 September 2024 at 10:02:25 UTC, Richard (Rikki)
>> Andrew Cattermole wrote:
>>> On 13/09/2024 9:54 PM, Quirin Schroll wrote:
>>>> The best thing about |pragma| is that it allows for
>>>> additional arguments. For example, a |bool| to enable or
>>>> disable it: |pragma(unlikely, false)| could be as if it’s
>>>> not there. Great for meta-programming. For |pragma(likely)|,
>>>> a numerical probability makes sense, too: |pragma(likely,
>>>> 0)| is equivalent to |pragma(unlikely)| and a single
>>>> |pragma(likely, value)| (with |value| > 0) is
>>>> |pragma(likely)|.
>>>
>>> We can do this with a UDA.
>>>
>>> ```d
>>> struct unlikely {
>>> bool activate=true;
>>> }
>>>
>>> if (...) @unlikely(false) {
>>>
>>> }
>>> ```
>>
>> Compiler-recognized UDAs are actually a bad choice in this
>> case. We’d need to change the grammar to allow them at this
>> place in a very special and weird way and they’re harder to
>> ignore.
>>
>> Again, the advantage of a pragma is that it’s implementation
>> defined and may end up not have any semantics at all, and this
>> is already specified out. A compiler-recognized UDA is just
>> the wrong tool for the job. The [spec about
>> pragmas](https://dlang.org/spec/pragma) is pretty clear about
>> that and as a related feature, `inline` is a pragma as well
>> for this exact reason.
>>
>> I just don’t understand why some people are adamant that those
>> annotations should be attributes. To me, it makes not the
>> least bit of sense.
>
> All the arguments you are making for a pragma equally apply to
> a UDA.
I don’t see why. Compilers aren’t free to ignore `@safe` and not
issue an error if you violate its conditions, but every pragma is
specified to be ignorable.
> Except they have the benefit that you can override them, and
> redefine them if they are not supported.
>
> You cannot do that with a pragma.
>
> So there is a transition path for both old and new code with
> new compiler versions with the UDA's that are not present with
> pragmas and that is a major advantage for code maintenance and
> portability between compilers.
I fail to see why this is the case or even desirable.
`pragma(likely)` isn’t really likely to be in code bases anyway.
>>>> Generally speaking, if there are more than two branches,
>>>> with two or more of them tagged |likely|, they can be given
>>>> weights, that may be derived from abstract reasoning or
>>>> profiling. That’s essentially what GCC has with
>>>> |__builtin_expect_with_probability|, except that it’s with
>>>> weights and not probabilities.
>>>
>>> The way it works in D is if-else not if-elseif-else.
>>
>> There is also `switch`.
>
> Walter has stated this elsewhere, that the order of declaration
> determines likelihood for cases.
>
> https://forum.dlang.org/post/vbspbo$2845$1@digitalmars.com
Another case of relying on the choice of specific compilers.
AFAICT, the whole point of likelihood annotations is that you can
layout the code as you think it’s best to read, but sprinkle in
some annotations that don’t hurt reading so that the compiler
emits a better binary.
>>> So for something like this, you are swapping the assumption
>>> from one path to another.
>>>
>>> I don't think we need probability support, just because of
>>> how the IR will be laid out to the backend.
>>
>> GCC supports them, so I thought at least GDC could make use of
>> them, LDC probably, too. DMD can just consider weights > 0 as
>> equal and likely.
>
> So does LLVM.
>
> What I am questioning is the need to offer this in the
> language, as I don't think we can drive it. To drive it you
> need if-elseif-else, rather than if-else.
Well, we’re in circles here. I already mentioned `switch`, and
again, the reason for the annotation is that code can be laid out
to be readable and idiomatic. Let’s say you have a big switch in
a hot loop. You profiled and now the data tells you how likely
each branch was. What would you prefer? Reordering the branches
by likelihood, leading to a diff that’s basically impossible to
understand or even vet that it’s just a reordering, or the pure
addition of likelihood annotations, for which in the diff it’s
absolutely clear nothing else changes. And if there’s a
fallthrough, you have to jump to the right case now.
You’re arguing as if the compiler couldn’t recognize `else if` as
a pattern.
The reason a compiler optimizes the non-branch or switch cases by
ordering (except if it has another clear indication of what’s a
cold path, e.g. a thrown exception) is because absent any
information, it has to do something and be deterministic. For
most cases, it’s fine. Optimization hints are an expert tool.
More information about the Digitalmars-d
mailing list