Почему этот код ветвления быстрее, чем этот код не ветвления? Тем более, что это использует случайные данные - PullRequest
0 голосов
/ 28 апреля 2020

У меня была идея, как оптимизировать лексер, и я попробовал экспериментальный код. Код без ветвей как-то медленнее, чем версия с ветвлением. Я озадачен Версия без отрубей не вводила условных ходов. Я не могу себе представить, почему это медленнее, тем более что я использовал rand () для генерации входных данных. Я не могу представить, чтобы предсказания ветвлений были хорошими со случайными данными. Кто-нибудь знает, почему версия ветвления работает быстрее?

-Edit- Согласно perf stat у кода без ответвлений много бэкэндов (51,65%). Я понял, что забыл увеличить pdata_out в версии ветки, но это не сильно сократило разрыв. Ветвление имеет 18,82% киосков.

Оба были скомпилированы с clang++-10 -O2 -mssse3 и не должны быть эквивалентными

Источник ветвления Неотраслевой источник

код ветвления, который я переписал в не ветвящийся (не приложил особых усилий)

    {
        auto prevToken = token;
        token &= temp_array[n];
        if (token)
            continue;

        auto len = pinput+n-data_left;
        if (prevToken & LexClass::DecimalValue)
        {
            *pdata_out = Token::TokDecimal;
            *ptoken_len=len;
            ptoken_len++;
        }
        else if (prevToken & LexClass::Var)
        {
            auto push_token = Token::variable;
            *pdata_out = push_token;
            *ptoken_len=len;
            ptoken_len++;
        }
        else if (prevToken & LexClass::NewLine)
        {
            line_start[line_start_index++] = pinput+n-data;
            *pdata_out = Token::TokNewLine;
        }
        else if (prevToken & LexClass::WhiteSpace)
        {
            //NOOP
        }
        else {
        }
        token = temp_array[n];
        data_left = pinput+n;
        if(token == 0)
            token = LexClass::WhiteSpace;
    }

версия без ветвлений (не эквивалентно, и я не старался)

    {
        const auto input128 = _mm_loadu_si128((__m128i*)pinput);
        const auto lowNibble = _mm_and_si128(input128, MaskLowNibble);
        const auto highNibble = _mm_and_si128(_mm_srli_epi32(input128, 4), MaskLowNibble);
        const auto lo_val = _mm_shuffle_epi8(LowTable, lowNibble);
        const auto hi_val = _mm_shuffle_epi8(HighTable, highNibble);
        const auto lookup_result = _mm_and_si128(lo_val, hi_val);

        _mm_store_si128((__m128i*)temp_array, lookup_result);
        for(int n=0; n<16; n++)
        {
            auto prevToken = token;
            token &= temp_array[n];
            if (token)
                continue;

            auto len = pinput+n-data_left;
            auto lz = 64 - __builtin_clzll(prevToken);

            auto tbl_value = tbl[lz];
            auto tokenValue = 256 + (tbl_value & 0x3F);
            *pdata_out = tokenValue;
            pdata_out += tbl_value>>7;
            *ptoken_len = len;
            ptoken_len+=(tbl_value>>6) & 1;
            line_start[line_start_index] = pinput+n-data;
            line_start_index+=(prevToken & LexClass::NewLine) != 0 ? 1 : 0;

            token = temp_array[n];
            data_left = pinput+n;
            token = token!=0?token:LexClass::WhiteSpace;
        }
    }

Различный файл S

--- branching.s 2020-04-28 01:42:57.578939280 -0400
+++ nonbranching.s  2020-04-28 01:42:53.938780661 -0400
@@ -1,5 +1,5 @@
    .text
-   .file   "branching.cpp"
+   .file   "nonbranching.cpp"
    .globl  _Z8GenTablev            # -- Begin function _Z8GenTablev
    .p2align    4, 0x90
    .type   _Z8GenTablev,@function
@@ -199,10 +199,14 @@
    .cfi_def_cfa_register %rbp
    pushq   %r15
    pushq   %r14
+   pushq   %r13
+   pushq   %r12
    pushq   %rbx
    andq    $-64, %rsp
    subq    $128, %rsp
-   .cfi_offset %rbx, -40
+   .cfi_offset %rbx, -56
+   .cfi_offset %r12, -48
+   .cfi_offset %r13, -40
    .cfi_offset %r14, -32
    .cfi_offset %r15, -24
    callq   _Z8GenTablev
@@ -253,16 +257,17 @@
    movaps  %xmm0, %fs:data@TPOFF+32
    movups  _ZL10test_input+41(%rip), %xmm0
    movups  %xmm0, %fs:data@TPOFF+41
-   movq    %fs:0, %rcx
-   leaq    data@TPOFF(%rcx), %rax
-   leaq    token_len@TPOFF(%rcx), %r15
-   movl    $1, %r10d
+   movq    %fs:0, %rax
+   leaq    data@TPOFF(%rax), %rsi
+   leaq    token_len@TPOFF(%rax), %r14
+   leaq    data_out@TPOFF(%rax), %r13
+   movl    $1, %r9d
    movdqa  .LCPI1_0(%rip), %xmm1   # xmm1 = [3616804123480109617,3329059735766188339]
    movdqa  .LCPI1_1(%rip), %xmm0   # xmm0 = [15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15]
-   movq    $data@TPOFF, %r9
+   movq    $data@TPOFF, %r10
    movl    $104857600, %r8d        # imm = 0x6400000
-   movl    $1, %ecx
-   movq    %rax, %r11
+   movl    $1, %eax
+   movq    %rsi, %r11
    .p2align    4, 0x90
.LBB1_6:                                # =>This Loop Header: Depth=1
                                        #     Child Loop BB1_7 Depth 2
@@ -281,56 +286,54 @@
    .p2align    4, 0x90
.LBB1_7:                                #   Parent Loop BB1_6 Depth=1
                                        # =>  This Inner Loop Header: Depth=2
-   movq    %rax, %rdi
-   movzbl  %bl, %eax
-   andl    %ecx, %eax
+   movzbl  %bl, %edi
+   andl    %eax, %edi
    je  .LBB1_11
# %bb.8:                                #   in Loop: Header=BB1_7 Depth=2
-   movl    %eax, %ecx
-   movq    %rdi, %rax
+   movl    %edi, %eax
    cmpq    $15, %rdx
-   jne .LBB1_20
+   jne .LBB1_13
    jmp .LBB1_9
    .p2align    4, 0x90
.LBB1_11:                               #   in Loop: Header=BB1_7 Depth=2
-   leaq    (%r11,%rdx), %rax
-   movq    %rax, %rsi
-   subq    %rdi, %rsi
-   testb   $8, %cl
-   jne .LBB1_12
-# %bb.14:                               #   in Loop: Header=BB1_7 Depth=2
-   testb   $4, %cl
-   jne .LBB1_15
-# %bb.16:                               #   in Loop: Header=BB1_7 Depth=2
-   testb   $2, %cl
-   je  .LBB1_18
-# %bb.17:                               #   in Loop: Header=BB1_7 Depth=2
+   leaq    (%r11,%rdx), %rdi
+   movl    %edi, %ebx
+   subl    %esi, %ebx
+   cltq
+   bsrq    %rax, %rsi
+   xorq    $63, %rsi
+   movl    $_ZZ4mainE3tbl, %ecx
+   subq    %rsi, %rcx
+   movzbl  64(%rcx), %ecx
+   movl    %ecx, %esi
+   andl    $63, %esi
+   orl $256, %esi              # imm = 0x100
+   movw    %si, (%r13)
+   shrl    $6, %ecx
+   movl    %ecx, %esi
+   andl    $-2, %esi
+   addq    %rsi, %r13
+   movb    %bl, (%r14)
+   andl    $1, %ecx
+   addq    %rcx, %r14
    movq    %fs:0, %rcx
-   addl    %r9d, %ecx
-   movl    %eax, %esi
-   subl    %ecx, %esi
+   addl    %r10d, %ecx
+   movq    %rdi, %rsi
+                                        # kill: def $edi killed $edi killed $rdi
+   subl    %ecx, %edi
    movslq  %fs:line_start_index@TPOFF, %rcx
-   leal    1(%rcx), %edi
-   movl    %edi, %fs:line_start_index@TPOFF
-   movl    %esi, %fs:line_start@TPOFF(,%rcx,4)
-   movw    $259, %fs:data_out@TPOFF # imm = 0x103
-   jmp .LBB1_18
-.LBB1_12:                               #   in Loop: Header=BB1_7 Depth=2
-   movw    $257, %fs:data_out@TPOFF # imm = 0x101
-   jmp .LBB1_13
-.LBB1_15:                               #   in Loop: Header=BB1_7 Depth=2
-   movw    $262, %fs:data_out@TPOFF # imm = 0x106
-.LBB1_13:                               #   in Loop: Header=BB1_7 Depth=2
-   movb    %sil, (%r15)
-   addq    $1, %r15
-.LBB1_18:                               #   in Loop: Header=BB1_7 Depth=2
-   movzbl  (%rsp,%rdx), %ecx
-   testb   %cl, %cl
-   cmovel  %r10d, %ecx
-   movzbl  %cl, %ecx
+   movl    %edi, %fs:line_start@TPOFF(,%rcx,4)
+   shrl    %eax
+   andl    $1, %eax
+   addl    %ecx, %eax
+   movl    %eax, %fs:line_start_index@TPOFF
+   movzbl  (%rsp,%rdx), %eax
+   testb   %al, %al
+   cmovel  %r9d, %eax
+   movzbl  %al, %eax
    cmpq    $15, %rdx
    je  .LBB1_9
-.LBB1_20:                               #   in Loop: Header=BB1_7 Depth=2
+.LBB1_13:                               #   in Loop: Header=BB1_7 Depth=2
    movzbl  1(%rsp,%rdx), %ebx
    addq    $1, %rdx
    jmp .LBB1_7
@@ -341,14 +344,15 @@
    addq    %r8, %rdx
    addq    $data@TPOFF, %rdx
    cmpq    %rdx, %r11
-   jae .LBB1_21
+   jae .LBB1_14
# %bb.10:                               #   in Loop: Header=BB1_6 Depth=1
    movdqu  (%r11), %xmm1
    jmp .LBB1_6
-.LBB1_21:
-   movzwl  %fs:data_out@TPOFF, %esi
+.LBB1_14:
    movq    %fs:0, %rax
-   leaq    token_len@TPOFF(%rax), %r14
+   leaq    data_out@TPOFF(%rax), %r12
+   movzwl  %fs:data_out@TPOFF, %esi
+   leaq    token_len@TPOFF(%rax), %r15
    movzbl  %fs:token_len@TPOFF, %edx
    movl    $.L.str.3, %edi
    xorl    %eax, %eax
@@ -428,17 +432,21 @@
    movl    $.L.str.3, %edi
    xorl    %eax, %eax
    callq   printf
+   subq    %r12, %r13
+   sarq    %r13
    movl    %fs:line_start_index@TPOFF, %edx
-   subq    %r14, %r15
+   subq    %r15, %r14
    movl    $.L.str.4, %edi
-   xorl    %esi, %esi
-   movq    %r15, %rcx
+   movq    %r13, %rsi
+   movq    %r14, %rcx
    xorl    %r8d, %r8d
    xorl    %eax, %eax
    callq   printf
    xorl    %eax, %eax
-   leaq    -24(%rbp), %rsp
+   leaq    -40(%rbp), %rsp
    popq    %rbx
+   popq    %r12
+   popq    %r13
    popq    %r14
    popq    %r15
    popq    %rbp
@@ -626,6 +634,12 @@
    .asciz  "123\n0x123Af\n123.45\n0x12F3a1\nvar\nif\nifword\ni\na+b*c!\n_Word"
    .size   _ZL10test_input, 57

+   .type   _ZZ4mainE3tbl,@object   # @_ZZ4mainE3tbl
+   .section    .rodata.cst8,"aM",@progbits,8
+_ZZ4mainE3tbl:
+   .asciz  "\000\000\000\000\301\306\203"
+   .size   _ZZ4mainE3tbl, 8
+
    .type   .L.str.3,@object        # @.str.3
    .section    .rodata.str1.1,"aMS",@progbits,1
.L.str.3:
...