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

    0

    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
    // https://godbolt.org/z/f4s13WEWM
    
    #include <inttypes.h>
    
    int test(uint32_t a, uint32_t b)
    {
      if (a > b)
        return a+b;
      return a*b;
    }
    
    int test2(uint32_t a, uint32_t b)
    {
      return (a+b)*(a > b) | (a*b)*!(a > b);
    }
    
    int test3(uint32_t a, uint32_t b)
    {
      return
        ((a+b) & (uint32_t)(!(a > b) - 1)) |
        ((a*b) & (uint32_t)((a > b) - 1));
    }
    
    int test4(uint32_t a, uint32_t b)
    {
      const uint32_t arr[2] = {a+b, a*b};
      return arr[!(a > b)];
    }
    
    /* ASM output
    test:
            bltu    a1, a0, .LBB0_2
            mul     a0, a1, a0
            ret
    .LBB0_2:
            add     a0, a0, a1
            ret
    
    test2:
            bltu    a1, a0, .LBB1_2
            mul     a0, a1, a0
            ret
    .LBB1_2:
            add     a0, a0, a1
            ret
    
    test3:
            bltu    a1, a0, .LBB2_2
            mul     a0, a1, a0
            ret
    .LBB2_2:
            add     a0, a0, a1
            ret
    
    test4:
            addi    sp, sp, -16
            add     a2, a1, a0
            mul     a3, a1, a0
            sltu    a0, a1, a0
            sw      a2, 8(sp)
            sw      a3, 12(sp)
            xori    a0, a0, 1
            slli    a0, a0, 2
            addi    a1, sp, 8
            add     a0, a0, a1
            lw      a0, 0(a0)
            addi    sp, sp, 16
            ret
    */

    Наглядная демонстрация того, что компилятор может насрать на ваши попытки заставить его сгенерить branchless машинный код. Получилось это только в "test4"

    Запостил: j123123, 07 Марта 2025

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

    • Именно поэтому я за ассемблер.

      А то вот советуют иногда https://johnfarrier.com/c-performance-checklist-for-low-latency-systems/

      > Use branchless arithmetic tricks (e.g., masks, bit shifts) to remove predictable conditionals.

      Хуй там.
      Ответить
    • bltu это такое кондишнл джамп? В моем дестве только CMP да JNE были просто.

      test4 раскатало нехило, это точно лучше, чем один условный прыг? Точнее так: всегда-ли прыг это настолько плохо? Есть же спекулятивное выполнение. Или оно нужно только чтобы мельдоний делать?
      Ответить
      • > bltu это такое кондишнл джамп? В моем дестве только CMP да JNE были просто.

        Это RISC-V. "bltu" расшифровывается как "branch if less than unsigned"

        >test4 раскатало нехило, это точно лучше, чем один условный прыг?

        ХЗ. Зависит от процессора наверное. Если эту же срань скомпилировать через GCC 14.2 x86-64 то получается такое:
        test:
                cmp     esi, edi
                jb      .L5
                mov     eax, edi
                imul    eax, esi
                ret
        .L5:
                lea     eax, [rdi+rsi]
                ret
        test2:
                mov     edx, edi
                lea     eax, [rdi+rsi]
                imul    edx, esi
                cmp     esi, edi
                cmovnb  eax, edx
                ret
        test3:
                cmp     esi, edi
                jnb     .L8
                lea     eax, [rdi+rsi]
                ret
        .L8:
                mov     eax, edi
                imul    eax, esi
                ret
        test4:
                lea     eax, [rdi+rsi]
                mov     DWORD PTR [rsp-8], eax
                mov     eax, edi
                imul    eax, esi
                mov     DWORD PTR [rsp-4], eax
                xor     eax, eax
                cmp     esi, edi
                setnb   al
                mov     eax, DWORD PTR [rsp-8+rax*4]
                ret


        Т.е. качественный branchless с инструкцией cmovnb оно сделало в варианте test2 только. В test4 тоже branchless, но он говно.
        Ответить
        • Расскажи как ARM и RISC-V в одном процессоре уживаются (вопрос про SBC). Какие у них есть опции по взаимодействию? Какие ограничения из-за того, что ядро RISC-V обозначено как realtime? У него реально там ограничения на фиксированную частоту и отсутствие сна, или что-то другое? Оно реально realtime, или это на маркетинговой брошюре написано? Там на этом realtime может быть линукс?
          Ответить
          • Это надо читать даташит конкретной хуйни с "ARM и RISC-V в одном процессоре" чтоб на этот вопрос отвечать. Может по разному уживаться. Например, там могут быть общее адресное пространство, и через него может идти взаимодействие, или это может работать через какие-то порты
            Ответить
          • Нагуглил Sophgo SG2000, в который помимо RISC-V и ARM запихнули ещё 8051. Надо изучать:

            https://wiki.sipeed.com/hardware/en/lichee/RV_Nano/1_intro.html

            https://milkv.io/chips/sg2000
            Ответить
            • это как раз та ебедень с алиэкспресса из соседней ветки
              Ответить
              • А 8051 там чисто как контроллер для периферии?
                Ответить
            • The make_all for the LicheeRV-Nano fails with u-boot. I fixed by adding #include "cpu_func.h" in jdi.c,jdi_osal.c and jpurun.c
              It still fails at the end with these messages. I tried on both Arch Linux and ubuntu 22.04 in Virtual Box. I also tried with Debian 12
              Ответить
        • lea eax, [rdi+rsi]

          оптимизация так и прёт.
          Ответить
      • насколько понимаю, bltu = cmovl в 86
        Ответить
        • Нет, неправильно ты понимаешь. bltu это "сравни и прыгни по адресу если сравнение вернуло true". cmovl это "запиши такую-то хуйню туда-то, если выставлен такой-то EFLAGS", а чтоб выставить EFLAGS нужно еще что-то сделать
          Ответить
      • > Точнее так: всегда-ли прыг это настолько плохо? Есть же спекулятивное выполнение.

        Нет, не всегда. Зависит от микроархитектуры и от вероятности срабатывания условного перехода. Вот например в https://en.algorithmica.org/hpc/pipelining/branchless/#when-predication-is-beneficial пишут:

        > Using predication eliminates a control hazard but introduces a data hazard. There is still a pipeline stall, but it is a cheaper one: you only need to wait for cmov to be resolved and not flush the entire pipeline in case of a mispredict.

        > However, there are many situations when it is more efficient to leave branchy code as it is. This is the case when the cost of computing both branches instead of just one outweighs the penalty for the potential branch mispredictions.

        Компилятору можно через какие-то говнодирективы сказать вероятность срабатывания условия, но нет такой директивы, которая бы приказывала генерить branchless код
        Ответить
      • А в ARM ещё бывают предикаты. Означают: проигнорировать инструкцию, если условие не выполняется. Это не отдельная инструкция, а надстройка над имеющимися, всего несколько битов от опкода.
        Ответить
    • https://stackoverflow.com/questions/72340698/riscv-branchless-coding - вот кстати по поводу branchless под RISC-V
      Ответить
    • Белорус на спор залпом выпил литр водки. Победил. Но впал в алкогольную кому и умер
      Ответить
    • А если в первом случае сделать

      sum = a + b
      mult = a - b

      return a &lt; b ? sum : mult

      то компилятор из такого не вытаскивает понимание твоих намерений?

      upd. а, ты хочешь вообще от bltu отказаться. Но тем не менее, он выплюнет джамп или bltu?
      Ответить
    • Хм, интересно... А вот такой вариант:
      int test(uint32_t a, uint32_t b)
      {
        int cond = a > b;
        return (a + b) * cond + a * b * cond;
      }
      компилится бранчлесс
      test:
              sltu    a2, a1, a0
              add     a3, a1, a0
              mul     a0, a1, a0
              add     a0, a0, a3
              neg     a1, a2
              and     a0, a0, a1
              ret
      Ответить
    • 2-й вореант работает с volatilie, но тогда он просто так какает в стек
      int test(uint32_t a, uint32_t b)
      {
        volatile uint32_t gt = (a <= b) - 1;
        uint32_t le = ~gt;
        return ((a + b) & gt) | ((a * b) & le);
      }
      
      test:
              addi    sp, sp, -16
              sltu    a2, a1, a0
              neg     a2, a2
              sw      a2, 12(sp)
              lw      a2, 12(sp)
              lw      a3, 12(sp)
              add     a4, a1, a0
              not     a2, a2
              and     a3, a3, a4
              mul     a0, a1, a0
              and     a0, a0, a2
              or      a0, a0, a3
              addi    sp, sp, 16
              ret
      Ответить
      • Не нужены эти закорючк... Почему нет русскоязычных процессоров?
        Ответить
    • свежачок
      https://pbs.twimg.com/media/GiSJz5zXkAA4PTj?format=jpg&name=large
      Ответить
      • Geode... А на SiS, VIA, UMC или Cyrix у вас ничего не завалялось?
        Ответить
      • 4.51PG — это 1997-й плюс-минус пару лет.

        А жёсткий на 160 гигов — это уже вторая половина нулевых. Возможно, оригинальный винт сдох, и где-то примерно в 2010-м его поменяли.

        Но есть две проблемы:
        1. Award BIOS 4.51PG не поддерживает LBA48, поэтому винт будет работать в режиме совместимости с LBA28, т. е. видно будет первые 128 гигов. Это не беда.

        2. У 4.51PG есть ошибка в коде вывода объёма жёсткого на экран, из-за которой он виснет, если объём больше 8 гигов. Я накатывал патч с rom.by, чтобы он не вис.

        Значит, в этой железке пропатченный BIOS?
        Ответить
        • >4.51PG — это 1997-й плюс-минус пару лет.

          ну там копирайт 99, видишь?

          >винт будет работать в режиме совместимости с LBA28

          От BIOSа требуется только добраться до первого сектора загрузочного раздела, а дальше уже операционка сама разберется. Она может иметь свой драйвер, и работать с IDE напрямую (если конечно там не DOS: он может и соснуть)

          > из-за которой он виснет, если объём больше 8 гигов
          какой багор)) Этого я не знал. Но может быть пропатченный, да.

          Я просто как увидел настоящий BIOS и Energy Star Ally так вспомнил детсво, и заплака и принёс сюда
          Ответить
          • > От BIOSа требуется только добраться до первого сектора загрузочного раздела

            Согласен, да, если у операционки есть свой драйвер, она доберётся до всех секторов.

            > какой багор

            Представляешь, как лоханулись создатели Award BIOS? Сам БИОС поддерживает LBA28, но в коде POST при выводе на экран диагностического сообщения переменная переполняется, и на POST он виснет, если объём приближается к 8 гигам или превосходит их. На момент создания не было больших винтов, поэтому у разработчиков всё работало.

            Авторы патча к килобайтам и мегабайтам добавили гигабайты и терабайты, чтобы всё выглядело красиво. Места на патч хватило.

            Кстати, знаешь, чем отличается 4.51PG от 4.5G? Более старый просто отображался на память и работал, а в более новом всё зожали в зип-файл, а перед ним поместили розжималку в ОЗУ, что позволило БИОС запихать в маленькую флешку (прошивку на 128К запихали на флешку на 64К). Зачем? Зачем? В те годы флешки на 128К были дорогими?

            *****

            Был ещё вариант: поставить внешний по отношению к материнке контроллер ATA, например, аппаратный RAID со своим БИОСом. Тогда весь объём будет доступен даже голому ДОСу. Но как это будет отображаться в POST, я не знаю.
            Ответить
    • В Микашевичах мужчина психанул из-за проигрыша в компьютерной игре — и выбросил из окна 3 этажа системник, монитор, утюг, обогреватель, дуршлаг и тазики.
      Ответить
      • Утюг, обогреватель, дуршлаг и тазики в чём провинились?
        Ответить
      • Единственный волевой парень, а вы тут все - тюфяки, не можете слезть с игрулек.
        Ответить
    • В Витебске участковый случайно застрелил коллегу, когда чистил пистолет, а потом застрелился сам
      Ответить
      • Правильно говорить: пристрелял оружие на коллеге а испытал его стрелковые характеристики на себе.
        Ответить
    • Биш-Кек
      Ответить
    • — «Вы думаете: „Дурак, дурак этот Петух, зазвал обедать, а обеда до сих пор нет“. Будет готов, почтеннейший, не успеет стриженая девка косы заплесть, как он поспеет…»«
      Ответить

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