0

I have a string

const signed char From[] = {
    0b00000000, 0b00000001, 0b00000010, 0b00000011,
    0b00000100, 0b00000101, 0b00000110, 0b00000111,
    0b00001000, 0b00001001, 0b00001010, 0b00001011,
    0b00001100, 0b00001101, 0b00001110, 0b00001111,
};

i need to place chars from this string into a __m128i vector and than store bytes from this vector into a std::uint32_t Schedule[4] array

Doing this:

const __m128i Chars = _mm_set_epi8 (
    From[0],
    From[1],
    From[2],
    From[3],
    From[4],
    From[5],
    From[6],
    From[7],
    From[8],
    From[9],
    From[10],
    From[11],
    From[12],
    From[13],
    From[14],
    From[15]
);

And now store this vector into Schedule:

_mm_store_si128((__m128i*)&Schedule[Kter], SettedLines4);

And we have incorrect Byte order in Schedule(also i think this is not an incorrect byte order. I think bits were mixed)

template<typename Type>
[[ nodiscard ]] std::string to_binary(Type Data) noexcept
{
    std::string Result = "";

    std::uint64_t CurrentBit = 8 * sizeof Data;
    while(CurrentBit--)
        Result += ((Data >> CurrentBit) & 1) == 0 ? "0" : "1";

    return Result;
}

std::cout << to_binary(Schedule[0]) << std::endl;
std::cout << to_binary(Schedule[1]) << std::endl;
std::cout << to_binary(Schedule[2]) << std::endl;
std::cout << to_binary(Schedule[3]) << std::endl;

Full code:

# include <x86intrin.h>
# include <iostream>
# include <cstdint>

template<typename Type>
[[ nodiscard ]] std::string to_binary(Type Data) noexcept
{
    std::string Result = "";

    std::uint64_t CurrentBit = 8 * sizeof Data;
    while(CurrentBit--)
        Result += ((Data >> CurrentBit) & 1) == 0 ? "0" : "1";

    return Result;
}

int main(void)
{
    std::uint32_t Schedule[4];
    const signed char From[] = {
        0b00000000, 0b00000001, 0b00000010, 0b00000011,
        0b00000100, 0b00000101, 0b00000110, 0b00000111,
        0b00001000, 0b00001001, 0b00001010, 0b00001011,
        0b00001100, 0b00001101, 0b00001110, 0b00001111,
    };

    const __m128i v = _mm_set_epi8 (
        From[0],
        From[1],
        From[2],
        From[3],
        From[4],
        From[5],
        From[6],
        From[7],
        From[8],
        From[9],
        From[10],
        From[11],
        From[12],
        From[13],
        From[14],
        From[15]
    );

    _mm_store_si128((__m128i*)&Schedule[0], v);
    std::cout << to_binary(Schedule[0]) << std::endl;
    std::cout << to_binary(Schedule[1]) << std::endl;
    std::cout << to_binary(Schedule[2]) << std::endl;
    std::cout << to_binary(Schedule[0]) << std::endl;
}

How can i fix it? I need to get the same byte order as expected

faust403
  • 3
  • 2
  • What is the output of your code? What do you expect it to be? – Alan Birtles Aug 11 '23 at 14:24
  • The output is: ```00001100000011010000111000001111 00001000000010010000101000001011 00000100000001010000011000000111 00001100000011010000111000001111``` I want it to be: ```00000000000000010000001000000011 00000100000001010000011000000111 00001000000010010000101000001011 00001100000011010000111000001111``` The awaited output is in order as in From (im sorry, i dont how to place endlines here) – faust403 Aug 11 '23 at 14:35
  • I have an idea that it was happened because invalid casting (__m128i*)&Schedule[0] in _mm_store_si128 arg but i still have no idea how to fix it – faust403 Aug 11 '23 at 14:39
  • @faust403, the casting is ok. Although it appears to violate Strict Aliasing Rule, for load/store intrinsics it is ok to do such casts, because these intrinsics are designed for such usage. Just be sure to align the destination variable properly, or use unaligned store. – Alex Guteniev Aug 11 '23 at 14:51
  • Please [edit] clarifications into the question rather than adding them in the comments – Alan Birtles Aug 11 '23 at 16:17

1 Answers1

1

Your issue is that _mm_set_epi8 takes parameters starting from most significant. You need _mm_setr_epi8 or reverse parameters order

Also you have a typo:

    std::cout << to_binary(Schedule[0]) << std::endl;
    std::cout << to_binary(Schedule[1]) << std::endl;
    std::cout << to_binary(Schedule[2]) << std::endl;
    std::cout << to_binary(Schedule[0]) << std::endl;

The last is 0.

Also it is an error to use _mm_store_si128 for not properly aligned destination. This may or may not crash. Use _mm_storeu_si128 or align your destination by 16.

Alex Guteniev
  • 12,039
  • 2
  • 34
  • 79
  • Yeah, but the last(or first, idk) line is still invalid – faust403 Aug 11 '23 at 14:41
  • i added spaces for the best view. ```00000011 00000010 00000001 00000000 00000111 00000110 00000101 00000100 00001011 00001010 00001001 00001000 00000011 00000010 00000001 00000000``` As you can see, last line repeats first(or vice versa) – faust403 Aug 11 '23 at 14:42
  • @faust403, this is because you repeat the last index. Your indices are `0`, `1`, `2`, `0`. – Alex Guteniev Aug 11 '23 at 14:47
  • Ah, yeah, you are right, Sorry for my mistake Also the right order is From[12], From[13], From[14], From[15], From[8], From[9], From[10], From[11], From[4], From[5], From[6], From[7], From[0], From[1], From[2], From[3] – faust403 Aug 11 '23 at 15:11
  • @faust403: So you're reversing bytes within each dword, like endian conversion? You can do that with a constant for `_mm_shuffle_epi8`. Your source *might* be getting optimized to a `pshufb` instruction, but a clearer way to write it would be with vector loads/stores like `_mm_loadu_si128( (const __m128i*)From)` and `_mm_storeu_si128( (__m128i*)schedule, v)`, where `v` comes from a shuffle. Or if you're reversing dwords in groups of 4 but keeping bytes in the same order within 4-byte groups, use `_mm_shuffle_epi32(v, _MM_SHUFFLE(0,1,2,3))` – Peter Cordes Aug 11 '23 at 18:29