September 11
On 9/11/2024 3:23 PM, Manu wrote:
> Even if you can manage to convince a compiler to write the output you're alleging,

Alleging? I cut and pasted what dmd did and what gcc did. My gcc may behave differently than yours, as there are many versions of it.

> I would never imagine for a second that's a reliable strategy. The optimiser could do all kinds of things... even though in all my experiments, it does exactly what I predicted it would.

Did you use -O?

dmd does what I predicted it would, as it is designed to operate that way. If gcc doesn't do what you want, there's nothing I can do about it.
September 12

On Wednesday, 11 September 2024 at 18:54:21 UTC, Walter Bright wrote:

>

On 9/11/2024 4:18 AM, Manu wrote:

>

Obfuscating the contorting code is not the goal or a reasonable solution; we just want a mechanism in the language to take advantage of this general category of support in whatever architecture.

I tend to agree, but when micro-optimizing one's code, one accepts that its elegance is going to decline.

There are at least 3 ways to organize the code to get what you want. I won't claim they're beautiful, but they work.

FWIW, I agree with Walter that it is not worth to add a new special feature to the language for the problem at hand.

It is rare that you'd want to explicitly tell whether a branch is likely or not, and for that case the tool already exist (llvm_expect for LDC). It think it would hurt D as a whole to have special stuff for such a rare thing.

I do agree that it'd be good to have a common interface for all compilers, which can be achieved by e.g. introducing a core.micro_optimization module.
That module could collect more of such micro optimization things, like telling the compiler about likely function pointers or class types (devirtualization). [1]

Cheers,
Johan

[1]

auto is_likely(alias Likely, Fptr, Args...)(Fptr fptr, Args args) {
    return (fptr == &Likely) ? Likely(args) : fptr(args);
}
// ...
void function() fptr = get_function_ptr();
fptr.is_likely!likely_function();

See https://johanengelen.github.io/ldc/2016/04/13/PGO-in-LDC-virtual-calls.html

September 12
On Thu, 12 Sept 2024 at 04:26, Walter Bright via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On 9/11/2024 3:23 PM, Manu wrote:
> > Even if you can manage to convince a compiler to write the output you're alleging,
>
> Alleging? I cut and pasted what dmd did and what gcc did. My gcc may
> behave
> differently than yours, as there are many versions of it.
>

This is literally my point...

> I would never imagine for a second that's a reliable strategy. The
> > optimiser could do all kinds of things... even though in all my
> experiments, it
> > does exactly what I predicted it would.
>
> Did you use -O?
>

I used -O2... I don't imagine that would have made a difference though? I don't think I've ever seen anyone use -O before.

dmd does what I predicted it would, as it is designed to operate that way.
> If
> gcc doesn't do what you want, there's nothing I can do about it.
>

You're not meant to do anything about it; just accept that your suggestion
to rely on contorting the code and a prayer that the compiler emits the
code you'd like to see (it doesn't) is not a reasonable suggestion.
This needs a proper solution.


September 12
On Thu, 12 Sept 2024 at 18:21, Johan via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On Wednesday, 11 September 2024 at 18:54:21 UTC, Walter Bright wrote:
> > On 9/11/2024 4:18 AM, Manu wrote:
> >> Obfuscating the contorting code is not the goal or a reasonable solution; we just want a mechanism in the language to take advantage of this general category of support in whatever architecture.
> >
> > I tend to agree, but when micro-optimizing one's code, one accepts that its elegance is going to decline.
> >
> > There are at least 3 ways to organize the code to get what you want. I won't claim they're beautiful, but they work.
>
> FWIW, I agree with Walter that it is not worth to add a new special feature to the language for the problem at hand.
>
> It is rare that you'd want to explicitly tell whether a branch is likely or not, and for that case the tool already exist (`llvm_expect` for LDC).


expect() statements are not a good time.
And something portable needs to be added anyway; so I'd seriously suggest
not using expect as an API for this.

It think it would hurt D as a whole to
> have special stuff for such a rare thing.
>

How?
And it's not 'rare'; it's 'niche'. For a microcontroller with no branch
prediction, it's common and essential.
It's literally unworkable to write code for the platform without this tool;
you can't have branches constantly mispredicting.

I do agree that it'd be good to have a common interface for all
> compilers, which can be achieved by e.g. introducing a
> `core.micro_optimization` module.
> That module could collect more of such micro optimization things,
> like telling the compiler about likely function pointers or class
> types (devirtualization). [1]
>
> Cheers,
>    Johan
>
>
> [1]
> ```
> auto is_likely(alias Likely, Fptr, Args...)(Fptr fptr, Args args)
> {
>      return (fptr == &Likely) ? Likely(args) : fptr(args);
> }
> // ...
> void function() fptr = get_function_ptr();
> fptr.is_likely!likely_function();
> ```
> See
> https://johanengelen.github.io/ldc/2016/04/13/PGO-in-LDC-virtual-calls.html
>

We virtually always end up with weird or butchered solutions to almost
everything for no good reason. Why can't we just do the normal and
reasonable thing for once?
Adding an attribute to a control statement is virtually zero impact; it's
such an obvious and elegant solution. This also isn't mutually exclusive
with expect(), or your suggestion above.


September 13
On 9/12/2024 3:49 PM, Manu wrote:
> You're not meant to do anything about it; just accept that your suggestion to rely on contorting the code and a prayer that the compiler emits the code you'd like to see (it doesn't) is not a reasonable suggestion.
> This needs a proper solution.

dmd does emit the expected code.

I used -O on gcc, not -O2, and it produced the expected result. -O2 does not, as you discovered.

There's also the do-while solution:

```
void bar();
int gax(int i)
{
    do
    {
        if (i) break;
        bar();
        return 1;
    } while (0);
    return 0;
}
```
which produces the same result with gcc -O:
```
gax:
    mov       EAX,0
    test      EDI,EDI
    jne       L55
    sub       RSP,8
    call      bar@PC32
    mov       EAX,1
    add       RSP,8
L55:    rep
    ret
```

I do not know why -O2 behaves differently. I don't know why gcc does not respect the code order given by the programmer.

Expecting these kinds of micro-optimizations to work reliably have a long history of becoming pessimizations. Given the complexity of modern optimizers and code generators, trying to control the sausage that comes out is going to be frustrating. Since they are "hints", there is no guarantee whatsoever any particular compiler will take the hints.

One thing you can try is to ask Iain and Martin to automatically add [[likely]]/[[unlikely]] hints to if statements so that code generation order mimics dmd's, which does put the code in the order presented.
September 13
On 9/11/2024 12:46 PM, Timon Gehr wrote:
> On 9/11/24 20:55, Walter Bright wrote:
>>
>>> My proposal is to allow a hint attached strictly to control statements. (ideally as a suffix)
>>> It is easy to read, also easy to ignore (this is important), and extremely low-impact when marking up existing code: no new lines, no rearranging of code, purely additive; strictly appends to the end of existing control statements... these are very nice properties for casually marking up some code where it proves to be profitable, without interfering with readability, or even interfering with historic diff's in any meaningful way that might make it annoying to review.
>>
>> How is that materially different from [[likely]] annotations?
> 
> It's associated with the branch and not with the program path.

I have no idea what the difference is, as the branch determines the program path.

September 13
On 9/11/2024 3:44 PM, Manu wrote:
> The article given above shows why arbitrary hints given as stand-alone statements in a flow causes nonsense when conflicting annotations appear within a flow.

It reminds me of the wretched

__declspec
__attribute__
__pragma
_Pragma
#pragma

additions to C that don't fit in the grammar in any sane manner.

September 13

On Wednesday, 11 September 2024 at 11:05:03 UTC, Dom DiSc wrote:

>

On Wednesday, 11 September 2024 at 08:53:30 UTC, ShadoLight wrote:

>

Just tongue-in-cheek along these lines ;-)

iffy(...) ...;
else ...;

At least it is shorter!

In german it would be easy: "wenn" is the likely path, "falls" is the unlikely path.

There’s also when in English. Being German myself, I found wenn and falls are way more interchangeable than English if and when. What teachers tell you isn’t that clear cut true. Haskell has a when function for monads.

Maybe we could add unless which is a negated if, but unless(cond) is different from if (!cond) in how it’s seen my the optimizer. CoffeScript has unless. However, I still think any optimization hints should be in a form that allows a conforming compiler to ignore it, i.e. a pragma is ideal:

if (x is null) pragma(unlikely) return 0;
// use *x

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).

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.

September 13
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) {

}
```

> 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.

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.

September 13

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.

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 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.

> >

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.

>

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.