Thread overview
core.simd ubyte16 initialization weirdness.
May 07, 2023
realhet
May 08, 2023
realhet
May 08, 2023
realhet
May 07, 2023

Hello,

import std, core.simd;

void main()
{
    enum ubyte16
        good1 = mixin([1, 2, 3, 4]),
    	bad = [1, 2, 3, 4];

    static immutable ubyte16
        good2 = mixin([1, 2, 3, 4]),
    	crash = [1, 2, 3, 4];

    pragma(msg, good1);
    pragma(msg, bad);
    pragma(msg, good2);
    pragma(msg, crash);
}

In the above example I tried 4 ways to initialize ubyte16 constants.
I only specify the first 4 values, the remaining is automatically zero.
2 of them are good 2 of them are bad.
Egy enum version compiles, but after trying SSE pshufb instruction with them, it seems like the [1, 2, 3, 4, 12 times 0] is distorted to this: [1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4]
I discovered the mixin() trick when I wanted to give them some calculated series.

Is it a bad way to initialize these constants? Is there a better way?

cast(immutable(__vector(ubyte[16])))[cast(ubyte)1u, cast(ubyte)2u, cast(ubyte)3u, cast(ubyte)4u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u]
This is how the compiler dumps it. But it's not so compact, so I rather use the mixin() version, I just don't understand why the int array fails -> [1, 2, 3....] It would look so nice.

May 08, 2023
On 08/05/2023 9:07 AM, realhet wrote:
> I just don't understand why the int array fails -> [1, 2, 3....] It would look so nice.

It doesn't.

```d
import std, core.simd;

void main()
{
     enum ubyte16
         good1 = mixin([1, 2, 3, 4]),
         bad = [1, 2, 3, 4];

     static immutable ubyte16
         good2 = mixin([1, 2, 3, 4]),
         crash = [1, 2, 3, 4];

    writeln(good1);
    writeln(bad);
    writeln(good2);
    writeln(crash);
}
```

```
[1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
```

Its a bug with ``pragma(msg)`` by the looks.
May 08, 2023
On Monday, 8 May 2023 at 08:05:13 UTC, Richard (Rikki) Andrew Cattermole wrote:

Yes, there is a pragma msg bug, but there is also a functionality 'bug'.

I collected some more info:

```
import std, core.simd, ldc.llvmasm;

T pshufb(T, U)(T a, in U b) { return __asm!ubyte16("pshufb $2, $1", "=x,0,x", a, b); }

void main()
{
    enum ubyte16
        input = mixin(iota(100, 116).array),
        good = mixin([1, 2, 3, 4, 5, 6, 7]),
    	bad1 = [1, 2, 3, 4, 5, 6, 7];
    static immutable
    	bad2 = [1, 2, 3, 4, 5, 6, 7];

    //pragma(msg, somewhat_good); <-crash

	writeln(good);
    writeln(pshufb(input, good));
    writeln;
    writeln(bad1);
    writeln(pshufb(input, bad1));
    writeln;
    writeln(bad2);
    writeln(pshufb(input, bad2));
}

[1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[101, 102, 103, 104, 105, 106, 107, 100, 100, 100, 100, 100, 100, 100, 100, 100]

[1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100]

[1, 2, 3, 4, 5, 6, 7]
[107, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100]
```

In the declaration of pshufb I let anything pass through to the __asm statement.

Only the   enum ubyte16 = mixin(...);   variant calculates the correct results, and luckily that can accept iota... calculated inputs as well.

But at this point I have to memorize this and be aware when I'm having weird results.


After all, this is the best SSE assembler I ever used so far *big thumbs up*. I like that I don't even have to allocate registers manually.
May 08, 2023
Don't forget to type bad2 which gives the same result as the good one. Otherwise it only has 7 elements in it.

```d
static immutable ubyte16 bad2 = [1, 2, 3, 4, 5, 6, 7];
```

```
[1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[101, 102, 103, 104, 105, 106, 107, 100, 100, 100, 100, 100, 100, 100, 100, 100]
```
May 08, 2023
On Monday, 8 May 2023 at 11:43:33 UTC, Richard (Rikki) Andrew Cattermole wrote:
> Don't forget to type bad2 which gives the same result as the good one. Otherwise it only has 7 elements in it.

Thank You, now that's good too.


So here are the weird stuff:

Pure arrays produce errors:
enum ubyte16 x = [1, 2, 3]               ->  bad SSE calculation
static immutable ubyte16 x = [1, 2, 3]   ->  calculates good, but pragma msg crashes

And there ar 2 possible fixes:
* Send the constant array through mixin()
* Send the constant array through Phobos: For example .array or .dub will do.


I think I will prefer the static immutable ubyte16 way with the simples looking array. The pragma will crash on it, but I can live with that.


```
import std, core.simd, ldc.llvmasm;

T pshufb(T, U)(T a, in U b) { return __asm!ubyte16("pshufb $2, $1", "=x,0,x", a, b); }

void main()
{
    enum ubyte16             input                = mixin(iota(100, 116).array),

                             good                 = mixin([0, 1, 2, 3, 4, 5, 6, 7]),
    	                     bad1                 = [0, 1, 2, 3, 4, 5, 6, 7];
    static immutable ubyte16 good2                = iota(8).array,
    	                     goodButPragmaCrash   = [0, 1, 2, 3, 4, 5, 6, 7],
    	                     goodAndNoPragmaCrash = [0, 1, 2, 3, 4, 5, 6, 7].dup;

    //pragma(msg, goodButPragmaCrash);
    pragma(msg, goodAndNoPragmaCrash);

    void test(string s)(){
        mixin(q{
            writef!"%s\n%s\n%s\n\n"("$", $, pshufb(input, $));
        }.replace("$", s));
    }

    test!"good";
    test!"bad1";
    test!"good2";
    test!"goodButPragmaCrash";
    test!"goodAndNoPragmaCrash";
}
```