1. Си / Говнокод #28309

    +1

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    61. 61
    62. 62
    63. 63
    64. 64
    65. 65
    66. 66
    67. 67
    68. 68
    69. 69
    70. 70
    71. 71
    72. 72
    73. 73
    74. 74
    75. 75
    76. 76
    77. 77
    78. 78
    79. 79
    80. 80
    81. 81
    82. 82
    83. 83
    84. 84
    85. 85
    86. 86
    87. 87
    88. 88
    89. 89
    90. 90
    91. 91
    92. 92
    93. 93
    94. 94
    95. 95
    #include <stdio.h>
    #include <string.h>
    #include <inttypes.h>
    
    void swap(uint8_t *x, uint8_t *y)
    {
        uint8_t tmp;
        tmp = *x;
        *x = *y;
        *y = tmp;
    }
    
    // эту хуйню тоже можно нагенерировать
    uint64_t cmp_bits(uint8_t a[restrict 9])
    {
      return 
      ((uint64_t)(a[0] < a[1]) << 0) |
      ((uint64_t)(a[0] < a[2]) << 1) |
      ((uint64_t)(a[0] < a[3]) << 2) |
      ((uint64_t)(a[0] < a[4]) << 3) |
      ((uint64_t)(a[0] < a[5]) << 4) |
      ((uint64_t)(a[0] < a[6]) << 5) |
      ((uint64_t)(a[0] < a[7]) << 6) |
      ((uint64_t)(a[0] < a[8]) << 7) |
    
      ((uint64_t)(a[1] < a[2]) << 8)  |
      ((uint64_t)(a[1] < a[3]) << 9)  |
      ((uint64_t)(a[1] < a[4]) << 10) |
      ((uint64_t)(a[1] < a[5]) << 11) |
      ((uint64_t)(a[1] < a[6]) << 12) |
      ((uint64_t)(a[1] < a[7]) << 13) |
      ((uint64_t)(a[1] < a[8]) << 14) |
    
      ((uint64_t)(a[2] < a[3]) << 15) |
      ((uint64_t)(a[2] < a[4]) << 16) |
      ((uint64_t)(a[2] < a[5]) << 17) |
      ((uint64_t)(a[2] < a[6]) << 18) |
      ((uint64_t)(a[2] < a[7]) << 19) |
      ((uint64_t)(a[2] < a[8]) << 20) |
    
      ((uint64_t)(a[3] < a[4]) << 21) |
      ((uint64_t)(a[3] < a[5]) << 22) |
      ((uint64_t)(a[3] < a[6]) << 23) |
      ((uint64_t)(a[3] < a[7]) << 24) |
      ((uint64_t)(a[3] < a[8]) << 25) |
    
      ((uint64_t)(a[4] < a[5]) << 26) |
      ((uint64_t)(a[4] < a[6]) << 27) |
      ((uint64_t)(a[4] < a[7]) << 28) |
      ((uint64_t)(a[4] < a[8]) << 29) |
    
      ((uint64_t)(a[5] < a[6]) << 30) |
      ((uint64_t)(a[5] < a[7]) << 31) |
      ((uint64_t)(a[5] < a[8]) << 32) |
    
      ((uint64_t)(a[6] < a[7]) << 33) |
      ((uint64_t)(a[6] < a[8]) << 34) |
    
      ((uint64_t)(a[7] < a[8]) << 35);
    }
    
    void printshit(uint8_t a[restrict 9])
    {
      size_t i = 0;
      while(*a != 4)
      {
        a++;
        i++;
      }
      printf("arr[%" PRIu64 "] = %zu\n", cmp_bits(a), i);
    }
    
    void permute(char *a, size_t l, size_t r)
    {
      size_t i;
      if (l == r)
        printshit(a);
      else
      {
        for (i = l; i <= r; i++)
        {
          swap((a+l), (a+i));
          permute(a, l+1, r);
          swap((a+l), (a+i));
        }
      }
    }
    
    int main()
    {
        uint8_t a[] = {0,1,2,3,4,5,6,7,8};
        size_t n = 9;
        permute(a, 0, n-1);
        return 0;
    }

    https://govnokod.ru/24496#comment782476

    Построение таблицы поиска для быстрого нахождения медианы. Там эту хуйню конечно можно улучшить, например запаковывать число от 0 до 8 в хуйни по 4 бита

    Запостил: j123123, 31 Июля 2022

    Комментарии (55) RSS

    • хотя это хуйня конечно, если для 9 элементов. Вот для 7 это рациональнее будет.
      Ну и еще такое говно можно как-нибудь аппаратно реализовать
      Ответить
      • 8 тоже в 32 бита влезет...
        Ответить
      • > uint8_t a[restrict 9]
        Какая универсальность )))
        Ответить
      • > Ну и еще такое говно можно как-нибудь аппаратно реализовать

        Борманд в прошлом треде уже показал pshufb.
        В принципе если компилятор достаточно умён он шаффлы
        typedef union
        {
            int64_t v;
            struct
            {
                int b0:8; int b1:8; int b2:8; int b3:8; int b4:8; int b5:8; int b6:8; int b7:8;
        
            };
        } MMX;

        Превратит в MMX/SSE инструкции.
        Ответить
        • > Превратит в SSE инструкции.

          Но обычно они сливают этот шанс если что-то посложнее тупого копирования (((
          Ответить
          • Обычно да. Но шланг меня приятно удивил.
            https://godbolt.org/z/EasbMjffP

            Надо будет попробовать расширить тот говнопример на произвольные размеры и шаффлы.
            Ответить
            • Да шланг тоже часто срывался в какую-то дичь если арифметику начать делать...

              Походу интринсиками ебашить -- пока единственный способ.
              Ответить
              • > Походу интринсиками ебашить -- пока единственный способ
                Почему же?

                Интринсиками непортабельно.
                А вот препроцессором имитировать PSHUFB чтобы мракос развернулся в мувы int8_t внутри структуры, тогда код будет портабельный.
                На умном компиляторе быстрый, на глупом — медленный, со сдвигами и битовыми масками.
                Ответить
                • > На умном компиляторе быстрый

                  Это если он не охуеет от количества операций... Должен же быть какой-то порог в пределах которого он мёржит операции в одну.
                  Ответить
                  • А много и не надо.
                    8 — MMX
                    16 — SSE
                    32 — AVX-2

                    В примере выше, он легко понимает что копирования 16 элементов это сдвиг.
                    Как будет вдохновение попробую сделать тасующий регистр на препроцесоре.
                    Ответить
                  • > Это если он не охуеет от количества операций...

                    Ну вот, всё работает:
                    https://godbolt.org/z/KsPq5soo9
                    #pragma pack(push,1)
                    
                    typedef union
                    {
                        int64_t v;
                        struct
                        {
                            int b0:8; int b1:8; int b2:8; int b3:8; int b4:8; int b5:8; int b6:8; int b7:8;
                        };
                    } Num;
                    
                    Num diff(Num n0, Num n1)
                    {
                        n0.b0 = -(n0.b0 > n1.b0); n0.b1 = -(n0.b1 > n1.b1); n0.b2 = -(n0.b2 > n1.b2); n0.b3 = -(n0.b3 > n1.b3); n0.b4 = -(n0.b4 > n1.b4); n0.b5 = -(n0.b5 > n1.b5); n0.b6 = -(n0.b6 > n1.b6); n0.b7 = -(n0.b7 > n1.b7);
                    
                        return n0;
                    }
                    
                    
                    diff:
                            movq    xmm0, rdi
                            movq    xmm1, rsi
                            pcmpgtb xmm0, xmm1
                            movq    rax, xmm0
                            ret

                    Осталось шуффлы напилить.
                    Ответить
              • > шланг тоже часто срывался в какую-то дичь если арифметику начать делать.
                Да, на массивах и векторах-структурах шланг городит дичь.
                А вот недавняя версия gcc 12.1 структуры векторизует хорошо, а массивы просто отлично.

                >Походу интринсиками ебашить -- пока единственный способ.
                Я по заветам Царя переделал на массивы: выхлоп стал ГОРАЗДО чище.
                https://godbolt.org/z/478cY9jP7
                GCC 11.3 и младше конечно так хорошо не умели, так что налицо прогресс.
                sort:
                        movq    xmm1, rdi
                        pshuflw xmm0, xmm1, 177
                        movdqa  xmm2, xmm0
                        pminsw  xmm0, xmm1
                        pmaxsw  xmm2, xmm1
                        movdqa  xmm3, xmm0
                        movdqa  xmm1, xmm2
                        pblendw xmm0, xmm2, 6
                        pshufb  xmm3, XMMWORD PTR .LC1[rip]
                        pshufb  xmm1, XMMWORD PTR .LC0[rip]
                        movdqa  xmm2, xmm0
                        por     xmm1, xmm3
                        pmaxsw  xmm2, xmm1
                        pminsw  xmm0, xmm1
                        movdqa  xmm1, xmm0
                        movdqa  xmm3, xmm2
                        pblendw xmm0, xmm2, 12
                        pshufb  xmm1, XMMWORD PTR .LC2[rip]
                        movdqa  xmm2, xmm0
                        pshufb  xmm3, XMMWORD PTR .LC3[rip]
                        por     xmm1, xmm3
                        pminsw  xmm2, xmm1
                        pmaxsw  xmm0, xmm1
                        pblendw xmm2, xmm0, 10
                        movq    rax, xmm2
                        ret
                .LC4:

                Правда первое перемешивание он догадался через pshuflw
                А последующие почему-то через джва pshufb.
                Ответить
                • >недавняя версия gcc 12.1 структуры векторизует хорошо, а массивы просто отлично.

                  https://gcc.gnu.org/gcc-12/changes.html

                  Vectorization is enabled at -O2 which is now equivalent to the original -O2 -ftree-vectorize -fvect-cost-model=very-cheap. Note that default vectorizer cost model has been changed which used to behave as -fvect-cost-model=cheap were specified.

                  Интересно что даже с этими флагами прошлые версии GCC не могут нормально векторизовать код.
                  Ответить
              • > Походу интринсиками ебашить -- пока единственный способ.
                Интринсики — непортабельное, трудночитаемое говно.
                А через массивы, у меня и на арме хороший векторный выхлоп получился
                sort:
                        fmov    d1, x0
                        adrp    x1, .LC0
                        adrp    x0, .LC1
                        rev32   v0.4h, v1.4h
                        ldr     d6, [x1, #:lo12:.LC0]
                        ldr     d5, [x0, #:lo12:.LC1]
                        adrp    x0, .LC2
                        ldr     d4, [x0, #:lo12:.LC2]
                        adrp    x0, .LC3
                        smax    v2.4h, v0.4h, v1.4h
                        smin    v0.4h, v0.4h, v1.4h
                        ldr     d3, [x0, #:lo12:.LC3]
                        mov     v1.8b, v2.8b
                        ins     v1.d[1], v0.d[0]
                        ins     v0.d[1], v2.d[0]
                        tbl     v1.8b, {v1.16b}, v6.8b
                        tbl     v0.8b, {v0.16b}, v5.8b
                        smax    v2.4h, v0.4h, v1.4h
                        smin    v0.4h, v0.4h, v1.4h
                        mov     v1.8b, v0.8b
                        ins     v0.s[1], v2.s[1]
                        ins     v1.d[1], v2.d[0]
                        tbl     v1.8b, {v1.16b}, v4.8b
                        smin    v2.4h, v0.4h, v1.4h
                        smax    v0.4h, v0.4h, v1.4h
                        mov     v1.8b, v2.8b
                        ins     v1.d[1], v0.d[0]
                        tbl     v0.8b, {v1.16b}, v3.8b
                        umov    x0, v0.d[0]
                        ret
                Ответить
                • .4h и .8b это количество и размер элемента?
                  Ответить
                  • Не совсем. Я не очень понимаю зачем он вообще взял 8b.

                    Видимо оно внутри решает что шаффлить батами лучше. Что мы видим и по SSE выхлопу: гцц и тут юзает pshufb

                    #define BATS   4  //кол-во бат
                    #define BAT    16 //размер бата
                    typedef struct
                    {
                        int16_t b[4];
                    } Num;
                    Ответить
                    • А может на арме и нету других шаффлов помимо побайтового? В общем-то он все задачи решает, просто маска больше получается.
                      Ответить
    • Кстати тут баг, пофиксил:
      void printshit(uint8_t a[restrict 9])
      {
        size_t i = 0;
        uint64_t cmp = cmp_bits(a);
        while(*a != 4)
        {
          a++;
          i++;
        }
        printf("arr[%" PRIu64 "] = %zu\n", cmp, i);
      }
      Ответить
    • #bormand_govno
      Ответить
    • Честно я не понял какая задача решается.

      Вдохной массив отсортирован или нет?

      Но говнище редкостное.
      Ответить
      • Я думаю нет, иначе смысл сравнивать что-то? Понятно что всё единичками будет.
        Ответить
        • Какая-то рекурсия permute ещё и в цикле. Похоже на школьный пузырёк за O(N*N) сравнений.

          Не проще ли будет за O(N*log N) его отсортировать и просто взять средний элемент?
          Ответить
          • Причём битовая маска, построенная выше не юзается. Вот меня это смущает. А не, юзается.
            Ответить
            • Кстати, пока не няпокакнул.

              Зацени сдвиговый регистр: https://govnokod.ru/28289
              Ответить
          • Это перебор всех перестановок хуйни.
            Находим индексы медианы для всех возможных перестановок хуйни, чтоб сделать таблицу соответствия, и потом можно сделать 36 сравнений, по результатам этих сравнений через эту таблицу можно найти, по какому индексу тут медиана
            Ответить
            • > потом можно сделать 36 сравнений
              36 сравнений это (N*N-N)/2=(9*9-9)/2.

              То есть O(N²)
              > для быстрого нахождения медианы

              Это так же "быстро", как осортировать массив наиболее тупым способом: питузком.
              Ответить
              • Для сортировки пузырьком нужно еще менять элементы массива местами, тут же прямолинейное сравнение кучи элементов, которое можно идеально распараллелить на какой-нибудь FPGA и за счет этого сделать всё очень быстро (по времени равно одному такому сравнению).
                А асимптотические оценки имеют смысл только на очень больших размерах
                Ответить
                • > FPGA

                  Тратить O(n^2) по площади кристалла на компараторы тоже не айс.

                  Хотя, возможно, в какой-то обработке сигналов может пригодиться такая сортировка по 4-8 элементов на каждый такт. Что-нибудь в духе поиска медианы в небольшом окне.
                  Ответить
                  • > FPGA

                    Привет. Посоветуйте актуальный FPGA для начала. Например по книжке вирта Проект Оберон пройти.
                    Ответить
                    • Хрен знает, что-нибудь от альтеры (интела) или зайлинкса из того что сейчас удастся найти?

                      У меня была de0 nano. Камень там неплохой, но вот по периферии она совсем голая. Можно ещё у марсохода посмотреть, вроде неплохие платы делали если ещё живы.

                      Ну и морально готовься к ёбле с жуткой, уёбищной проприетарщиной. С опенсурсом в этой области всё совсем плохо, хотя есть прогресс в том же Yosys.
                      Ответить
                      • Ты имеешь ввиду что софт для работы с платой проприетарный? А что там вообще за стек. Там что-то кроме Верилога бывает?
                        Ответить
                        • Там мало того, что синтез схемы сам по себе нетривиальная задача и требует кучи таблиц и знаний о кишках чипа, так ещё и формат битстрима, который в чип заливается везде закрытый... Поэтому с тулчейном для синтеза полная жопа. Для латтисов и старых зайлинков что-то опенсурсное уже запинали. Для альтеры нет.

                          Плюс многие IP Core (модули) закрытые и\или платные. Но с этим ситуация гораздо лучше, опенсурсных модулей и проектов куча.

                          Кроме верилога ещё обычно бывает VHDL. Ну и схемы в гуйне можно порисовать если хочется по-старинке.
                          Ответить
                          • > Для латтисов и старых зайлинков что-то опенсурсное уже запинали. Для альтеры нет.

                            Бля, я думал это область, в которой вообще по дефолту всё опенсурсное. Пиздец...

                            А нахуя это всё тогда? Чисто экспериментировать с архитектурой? Делать медленный процессор, для которого js буде ассемблером? Я хочу fpga чтобы гарантировать, что у меня в стеке нет аппаратных закладок, и для этого желаю контролировать всё начиная от кристалла. И получаю в итоге проприетарный программатор. Мда...
                            Ответить
                            • > А нахуя это всё тогда?

                              Сделать быструю аппаратную реализацию какого-то алгоритма.
                              Возможность не меняя железо перепрограммировать его в другой алгоритм.
                              Ответить
                            • > А нахуя это всё тогда?

                              ASIC'и на чём-то надо прототипировать. Ну и какие-нибудь реалтаймовые задачки, с которыми проц тупо не справится.

                              З.Ы. Если хочешь опенсурса -- кроме i386/amd64 вообще сложно какое-то актуальное железо найти. Это будут или какие-нибудь слабые микроконтроллеры или говно мамонта, на которое вендору уже насрать.
                              Ответить
                            • > проприетарный программатор

                              Опенсурсный программатор, к слову несложно найти или даже написать. Там достаточно высрать битстрим из файла в какой-нибудь jtag-over-usb.

                              Проприетарщина таится именно в синтезе этого битстрима из твоих исходников. Ну и причина довольно прозаичная -- чем больше кишков кристалла вендор опубликует, тем быстрее его идею склонируют другие. А без знаний о кишках чипа синтез невозможен, увы. Разве что для низкочастотных схем.
                              Ответить
                        • А стаканить зачем? )
                          Ответить
                      • > от альтеры (интела) или зайлинкса (амд)
                        fixed
                        Ответить
                        • Встроенные команды биоса всё равно не вскрыть.
                          Ответить
                      • не надо стаканить.
                        Ответить
              • А стаканить зачем? )
                Ответить
      • Охулион итераций на одну команду. Ресурсоемненько.
        Ответить
    • Для 9ти элементов 8*9/2 = 36 сравнений.

      Не проще взять qsort?
      Ответить
      • Это генерация таблицы поиска, каким образом тут qsort поможет?
        Ответить
        • Походу интринсиками ебашить -- пока единственный способ.
          Ответить
    • Эхехехех. Я упоролся и портировал алгоритм Борманда на Царские мувы

      https://godbolt.org/z/8frGY1GG1

      Выхлоп после препроцессора:
      #pragma pack(push,1)
      
      typedef union
      {
          __int128_t v;
          struct
          {
      
              int b0:32; int b1:32; int b2:32; int b3:32;
      
          };
      } Num;
      
      int min(int a, int b)
      {
          return a < b ? a : b;
      }
      
      int max(int a, int b)
      {
          return a > b ? a : b;
      }
      Num nmin(Num n0, Num n1) { n0.b0 = min(n0.b0, n1.b0); n0.b1 = min(n0.b1, n1.b1); n0.b2 = min(n0.b2, n1.b2); n0.b3 = min(n0.b3, n1.b3); return n0; };
      
      Num nmax(Num n0, Num n1) { n0.b0 = max(n0.b0, n1.b0); n0.b1 = max(n0.b1, n1.b1); n0.b2 = max(n0.b2, n1.b2); n0.b3 = max(n0.b3, n1.b3); return n0; };
      
      Num nGT(Num n0, Num n1) { n0.b0 = -(n0.b0>n1.b0); n0.b1 = -(n0.b1>n1.b1); n0.b2 = -(n0.b2>n1.b2); n0.b3 = -(n0.b3>n1.b3); return n0; };
      
      Num nLT(Num n0, Num n1) { n0.b0 = -(n0.b0>n1.b0); n0.b1 = -(n0.b1>n1.b1); n0.b2 = -(n0.b2>n1.b2); n0.b3 = -(n0.b3>n1.b3); return n0; };
      Num n1001(Num n0, Num n1) { n0.b0 = n1.b0; n0.b3 = n1.b3; return n0; }
      
      
      Num n0011(Num n0, Num n1) { n0.b0 = n1.b0; n0.b1 = n1.b1; return n0; }
      
      
      Num n0101(Num n0, Num n1) { n0.b0 = n1.b0; n0.b2 = n1.b2; return n0; }
      Num shfl0(Num n0) { Num r={}; r.b0 = n0.b1; r.b1 = n0.b0; r.b2 = n0.b3; r.b3 = n0.b2; return r; }
      
      Num shfl1(Num n0) { Num r={}; r.b0 = n0.b2; r.b1 = n0.b3; r.b2 = n0.b0; r.b3 = n0.b1; return r; }
      
      
      inline Num shr0(Num n)
      {
          return shr(n,0);
      }
      
      inline Num slr0(Num n)
      {
          return shl(n,0);
      }
      
      Num sort(Num a){
      
          Num s1 = shfl0(a);
          Num x1 = nmax(a, s1);
          Num y1 = nmin(a, s1);
          a = n1001(x1, y1);
      
          Num s2 = shfl1(a);
          Num x2 = nmax(a, s2);
          Num y2 = nmin(a, s2);
          a = n0011(x2, y2);
      
          Num s3 = shfl0(a);
          Num x3 = nmax(a, s3);
          Num y3 = nmin(a, s3);
          a = n0101(x3, y3);
          return a;
      }
      
      int main()
      {
      
          Num x={.b0=42,15,60,3};
          x=sort(x);
          printf("%d %d %d %d\n",x.b0,x.b1,x.b2,x.b3);
      
          return 0;
      }
      
      Program returned: 0
      3 15 42 60
      Ответить
      • Выхлоп почему-то на cmovах (12 штук)
        sort:
                mov     rdx, rdi
                mov     rcx, rsi
                mov     eax, edi
                mov     r8d, esi
                sar     rdx, 32
                sar     rcx, 32
                cmp     edx, edi
                cmovge  eax, edx
                cmp     ecx, esi
                cmovge  r8d, ecx
                cmp     edx, edi
                cmovg   edx, edi
                cmp     ecx, esi
                mov     edi, eax
                cmovg   ecx, esi
                mov     esi, r8d
                cmp     edx, r8d
                cmovge  esi, edx
                cmp     ecx, eax
                cmovge  edi, ecx
                cmp     edx, r8d
                cmovg   edx, r8d
                cmp     ecx, eax
                cmovg   ecx, eax
                cmp     edx, ecx
                mov     eax, ecx
                cmovle  eax, edx
                cmovl   edx, ecx
                mov     eax, eax
                sal     rdx, 32
                or      rax, rdx
                cmp     esi, edi
                mov     edx, edi
                cmovle  edx, esi
                cmovl   esi, edi
                mov     edx, edx
                sal     rsi, 32
                or      rdx, rsi
        Ответить
      • Если поставить BAT (размер бата) равным 16ти, то ГЦЦ начинает юзать SSE
        sort:
                mov     eax, edi
                mov     rdx, rdi
                mov     rcx, rsi
                sar     eax, 16
                sal     rdx, 16
                movd    xmm1, eax
                movsx   eax, di
                sar     rdi, 48
                movd    xmm3, eax
                movd    xmm0, edi
                sar     rdx, 48
                movdqa  xmm7, xmm1
                movd    xmm2, edx
                pmaxsd  xmm7, xmm3
                pminsd  xmm1, xmm3
                movdqa  xmm4, xmm0
                movdqa  xmm5, xmm7
                pminsd  xmm0, xmm2
                pmaxsd  xmm4, xmm2
                movdqa  xmm7, xmm1
                pmaxsd  xmm7, xmm4
                movdqa  xmm6, xmm4
                movdqa  xmm4, xmm0
                pmaxsd  xmm4, xmm5
                pminsd  xmm1, xmm6
                movdqa  xmm6, xmm7
                pmaxsd  xmm6, xmm4
                pminsd  xmm0, xmm5
                movdqa  xmm5, xmm1
                movd    esi, xmm6
                pmaxsd  xmm5, xmm0
                movdqa  xmm2, xmm7
                movzx   esi, si
                movd    edx, xmm5
                pminsd  xmm1, xmm0
                mov     rax, rsi
                movzx   edx, dx
                pminsd  xmm2, xmm4
                sal     rax, 16
                or      rax, rsi
                movabs  rsi, -281470681743361
                sal     rax, 16
                or      rax, rdx
                sal     rax, 16
                or      rax, rdx
                movd    edx, xmm1
                mov     ax, dx
                movd    edx, xmm2
                movzx   edx, dx
                and     rax, rsi
                sal     rdx, 32
                or      rax, rdx
                mov     rdx, rcx
                ret
        Ответить
    • Как видим выхлоп хуже оригинала
      https://godbolt.org/z/EaEfGxe5M
      
      bormand_sort:
              movdqu  xmm2, XMMWORD PTR [rdi]
              pshufd  xmm0, xmm2, 177
              movdqa  xmm1, xmm0
              pminsd  xmm0, xmm2
              pmaxsd  xmm1, xmm2
              blendps xmm1, xmm0, 9
              pshufd  xmm2, xmm1, 78
              movdqa  xmm0, xmm2
              pminsd  xmm2, xmm1
              pmaxsd  xmm0, xmm1
              blendps xmm0, xmm2, 3
              pshufd  xmm1, xmm0, 177
              movdqa  xmm2, xmm1
              pminsd  xmm1, xmm0
              pmaxsd  xmm2, xmm0
              movaps  xmm0, xmm2
              blendps xmm0, xmm1, 5
              movaps  XMMWORD PTR [rdi], xmm0
              ret


      Нет blendps и shuffle.
      Хотя шаффлы вынесенные в отдельные функции нормально превращаются в SSE-инструкции.
      shfl0:
              movq    xmm1, rdi
              xor     edx, edx
              pshuflw xmm0, xmm1, 177
              movq    rax, xmm0
              ret
      shfl1:
              movq    xmm1, rdi
              xor     edx, edx
              pshuflw xmm0, xmm1, 78
              movq    rax, xmm0
              ret
      Ответить
      • Проблема тут, как мне видится, в том что blendps для плавающих 32 битных питухов.

        И компилятор не догадывается что его равноценно можно использовать для целых.

        В оригинале https://govnokod.ru/24496#comment452141 чтобы обойти это дерьмо кастят в флоаты: _mm_castsi128_ps, а потом обратно в целый __m128i.

        Наверное blend нетрудно реализовать через битовые маски чтобы сгенерить семейство инструкции pand.
        Ответить
        • Да, там даже с интринсиками приходится "кастовать" типы чтобы конпелятор успокоился. Хотя казалось бы какая разница для битовых и байтовых операций, которые никакой арифметики не делают.

          А бленд вручную лепить из and и or -- это же медленнее будет...

          З.Ы. А если версию SSE поднять, там не завезли для интов аналог?
          Ответить
          • > А бленд вручную лепить из and и or -- это же медленнее будет...
            Да. Плюс оно даже через and/or не понимает.

            > З.Ы. А если версию SSE поднять, там не завезли для интов аналог?

            Я вчера перепробовал все вореции с этим struct union.
            SSE4 — максимальная. От 4.2 пользы нет. А дальше AVX и VEX префиксы.
            Практически тоже самое, только с трехоперандными командами (меньше мувов).

            Меня спасла царская структура данных массив.
            С ней векторизуется хорошо. Но только на последнем гцц.

            https://govnokod.ru/28309#comment782800
            https://godbolt.org/z/478cY9jP7
            Ответить
      • Любишь ли ты перед сном посортировать пузырьком, 3.14159265?
        Ответить
        • А что такого? Кто-то считает слонов, а кто-то пузырки.
          Ответить

    Добавить комментарий