рд╣рд╛рд╕реНрдХреЗрд▓ рдФрд░ рд╕реА ++ рдХреА рддреБрд▓рдирд╛ рдХреА рдЧрдИ, рдФрд░ рдХреВрдж рдФрд░ рд╕реЗрдореАреЛрд╡ рдХреА рддреБрд▓рдирд╛ рдХреА рдЧрдИ

рдордЬрд╝реЗрджрд╛рд░ рдмрд╛рдд рдпрд╣ рд╣реИ - <br> рдореИрдВрдиреЗ LLVM рдмреИрдХрдПрдВрдб рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╣рд╛рд╕реНрдХреЗрд▓ рдХреЛрдб рдПрдХрддреНрд░ рдХрд┐рдпрд╛, <br> рд▓реЗрдХрд┐рди рдЙрд╕реА рд╕рдордп рдореИрдВрдиреЗ ICC рдХреЗ рд╕рд╛рде рддреБрд▓рдирд╛ рдХреА


рд▓реЗрдЦ [рд▓рд┐рдВрдХ] рдиреЗ рдХрд╣рд╛ рдХрд┐ рд╣рд╛рд╕реНрдХреЗрд▓ рдХреЛрдб рдХрд╛ рдкреНрд░рджрд░реНрд╢рди C ++ рдХреЛрдб рд╕реЗ рдмреЗрд╣рддрд░ рдерд╛ред рдХреНрдпрд╛ рддреБрд░рдВрдд рд░реБрдЪрд┐ рдЬрдЧреА, рдЬреИрд╕рд╛ рдХрд┐ рджреЛрдиреЛрдВ рдХрдВрдкрд╛рдЗрд▓рд░ рджреНрд╡рд╛рд░рд╛ LLVM рджреНрд╡рд╛рд░рд╛ рдЙрддреНрдкрдиреНрди рдХрд┐рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рдпрд╛ рддреЛ рдПрд╕реНрд╕реЗрд▓ рдХрдВрдкрд╛рдЗрд▓рд░ рдХреЛ рдЕрдзрд┐рдХ рд╕рдВрдХреЗрдд рджреЗ рд╕рдХрддрд╛ рд╣реИ, рдпрд╛ C ++ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд╕рд╛рде рдХреБрдЫ рдЧрд▓рдд рд╣реИред рдЗрд╕рдХреЗ рдмрд╛рдж, рд╣рдо рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░реЗрдВрдЧреЗ рдХрд┐ рд▓реЗрдЦрдХ рдХреЗ рдХрд╛рд░реНрдпреЛрдВ рдореЗрдВ рджреБрд░реНрдШрдЯрдирд╛рдУрдВ рдХреА рдПрдХ рд╢реНрд░реГрдВрдЦрд▓рд╛ рдиреЗ рдЧрд▓рдд рдирд┐рд╖реНрдХрд░реНрд╖ рдХреИрд╕реЗ рдирд┐рдХрд╛рд▓реЗ, рдЬреЛ рдиреАрдЪреЗ рджреА рдЧрдИ рддрд╛рд▓рд┐рдХрд╛ (рдХрдЯ рдХреЗ рддрд╣рдд) рдореЗрдВ рд╡рд░реНрдгрд┐рдд рд╣реИрдВред


рдкреНрд░рд╕реНрддрд╛рд╡рдирд╛


рд╣рд╛рд▓ рд╣реА рдореЗрдВ, рдПрдХ рдФрд░ рд▓реЗрдЦ рд╕реЗ0xd34df00dрд╣рд╛рд╕реНрдХреЗрд▓ рдХреЛрдб рдЕрдиреБрдХреВрд▓рдиред рдЗрд╕рдХреА рддреБрд▓рдирд╛ рдРрд╕реЗ рдорд╛рдорд▓реЛрдВ рдореЗрдВ рд╕реНрд╡рд╛рднрд╛рд╡рд┐рдХ рд░реВрдк рд╕реЗ рдкреНрд░рджрд░реНрд╢рди рдореЗрдВ рдирд┐рд░реНрд╡рд┐рд╡рд╛рдж рдиреЗрддрд╛ рдХреЗ рд╕рд╛рде рдХреА рдЬрд╛рддреА рд╣реИ - C / C ++ред рдлрд┐рд░ рдЗрд╕ рд▓реЗрдЦ рд╕реЗ рдПрдХ рдкрд░рд╕рд┐рдВрдЧ рдЖрдИyleoрдХреНрдпрд╛ asm рдХреЛрдб рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдмреЗрд╣рддрд░ рд╣реИ, рдФрд░ рд╡рд┐рднрд┐рдиреНрди рднрд╛рд╖рд╛рдУрдВ рдкрд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рдмреАрдЪ рдЕрдВрддрд░ рдХреНрдпрд╛ рд╣реИ (рдореИрдВ рдкрдврд╝рдиреЗ рдХреА рд╕рд▓рд╛рд╣ рджреЗрддрд╛ рд╣реВрдВ)ред рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рднреА (рд▓рдЧрднрдЧ рдбреЗрдврд╝ рдорд╣реАрдиреЗ рдкрд╣рд▓реЗ), рд╣рд╛рд╕реНрдХреЗрд▓ рдмрдирд╛рдо рд╕реА / рд╕реА ++ рд╕реАрд░реАрдЬрд╝ рдХрд╛ рдкрд┐рдЫрд▓рд╛ рд▓реЗрдЦ рдкреНрд░рдХрд╛рд╢рд┐рдд рд╣реБрдЖ рдерд╛, рдФрд░ рдореИрдВрдиреЗ рднреА рдЗрд╕реА рддрд░рд╣ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд┐рдпрд╛ рдерд╛, рд▓реЗрдХрд┐рди рдЗрд╕реЗ рд╣рд╛рдмрд░рд╛ - рдЕрд▓рд╛рд╕ рдХреЛ рдкреНрд░рдХрд╛рд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп, рдореИрдВрдиреЗ рдЗрд╕реЗ рдмреИрдХ рдмреЙрдХреНрд╕ рдореЗрдВ рдбрд╛рд▓ рджрд┐рдпрд╛ред рдЗрд╕ рд╕рдкреНрддрд╛рд╣ рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдореЗрдВ рдЧрд░реНрдо рдЪрд░реНрдЪрд╛рдУрдВ рдиреЗ рдореБрдЭреЗ рдкрд┐рдЫрд▓реЗ рд╡рд┐рд╖рдп рдкрд░ рд▓реМрдЯрдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░реЗрд░рд┐рдд рдХрд┐рдпрд╛ред рдЖрдЬ рдореБрдЭреЗ рдЕрдВрдд рдореЗрдВ рджрд░рд╛рдЬ рдХреЗ рдмрд╛рд╣рд░ рдЙрд╕ рдорд╛рд░реНрдХрдбрд╛рдЙрди рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рдорд┐рд▓рд╛, рдЬреЛ рдзреВрд▓ рд╕реЗ рд╕рдирд╛ рд╣реБрдЖ рдерд╛,рдЦрд╝рддреНрдо рд╣реЛрдирд╛, рдФрд░ рдЗрд╕реЗ рдЕрдкрдиреА рд╕рдореАрдХреНрд╖рд╛ рдХреЗ рд▓рд┐рдП рдкреНрд░рджрд╛рди рдХрд░реЗрдВред


рдкрд░рд┐рдЪрдп


, [], :



.
clang 9103%
gcc 9.2125%
C++ gcc 9.2163%
C++ clang 9323%

/++, .. , , " , ". "", . , , , 10- .



-, , ++ , , , . , zero-cost, , , , - ++, . , clang 3 (!) , +, , .. lang llvm тАФ .



, : gcc clang. , . ( ), gcc . , , , , , .




std::min({...})


, , std::min.


C++.
, std::min({delCost, insCost, substCost})
std::min(substCost, std::min(delCost, insCost)),
clang тАФ 0.840
, .
( тАФ 0xd34df00d)

:


A.unsafeWrite v1 (j + 1) $ min (substCost + substCostBase) $ 1 + min delCost insCost

, min ! (, ). , , C++ , , llvm llvm. , . , , "skell " . , " ++; , PHP" , , . :


(1)
haskell/llvm910ms-
gcc 9.21211ms1211ms
clang 91915ms852ms

stdlib gcc - std::min , ++. std::min_element. , , , :


f(int, int, int):
        cmp     esi, edi
        mov     eax, edx
        cmovg   esi, edi
        cmp     esi, edx
        cmovle  eax, esi
        ret

: cmov* = conditional move (: g тАФ greater, le тАФ less equal, ..).


, , , , clang, gcc, - ( rsp ):


fptr(int*, int*, int*):
        mov     eax, dword ptr [rdi]
        mov     dword ptr [rsp - 12], eax
        mov     ecx, dword ptr [rsi]
        mov     dword ptr [rsp - 8], ecx
        cmp     ecx, eax
        cmovle  eax, ecx
        mov     ecx, dword ptr [rdx]
        cmp     ecx, eax
        cmovle  eax, ecx
        ret

, clang . initializer_list asm -O1, (-O2), asm . , std::min(std::initializer_list) -, -, , .


s1[i]


, тАФ , ++.


s1[i] ! ()

, , , - , , . , s1[i] ,


  let s1char = s1 `BS.index` i
  let go j | j == n = pure ()
    --  

++, , clang. .. + llvm - , -march=native. , , std::min , , ! , - , " " , .


(2)(3)
haskell/llvm910ms--
gcc 9.21211ms1195ms1195ms
clang 91915ms742ms831ms


C++ .
,
C main', .
( )

, , , - , :


  size_t lev_dist(const std::string &s1, const std::string &s2) {
    const auto m = s1.size();
    const auto n = s2.size();

    std::vector<int> v0;
    v0.resize(n + 1);
    std::iota(v0.begin(), v0.end(), 0);
    auto v1 = v0;

    for (size_t i = 0; i < m; ++i) {
      v1[0] = i + 1;
      char c1 = s1[i];
      for (size_t j = 0; j < n; ++j) {
        auto substCost = c1 == s2[j] ? v0[j] : (v0[j] + 1);
        v1[j + 1] = std::min(substCost, std::min(v0[j + 1], v1[j]) + 1);
      }
      std::swap(v0, v1);
    }
    return v0[n];
  }

32- int тАФ , ( ).


(3b)
haskell/llvm910ms-
gcc 9.21210ms831ms
clang 91915ms741ms

, GCC . j , GCC. clang .



LLVM == LLVM


-, , ++ Haskell , clang-9. , Skylake C++ . , , , Haswell, .


, , , GCC LLVM.


, , llvm, ffi, .


GCC vs CLANG


-, , gcc . , clang- .


, , , , (#if !defined(__GNUC__) || defined(__llvm__)), ++ , , ++ .


clang ( ) . ( )

, GCC LLVM. , asm. gcc - : , cmov* min ( , ). (3), , , ++ :


      for (size_t j = 0; j < n; ++j) {
        auto delCost = v0[j + 1] + 1;
        auto insCost = v1[j] + 1;
        auto substCost = c1 == s2[j] ? v0[j] : (v0[j] + 1);
        v1[j + 1] = std::min(substCost, std::min(delCost, insCost));
      }

, , :


.L42:
        inc     rcx  // j++
        mov     rdi, QWORD PTR [r12+rcx*8]  //  v0[j+1]
        xor     edx, edx  //  %edx
        cmp     r10b, BYTE PTR [r11-1+rcx]  // c1 == s2[j]
        setne   dl  //     %rdx
        lea     r9, [rdi+1]  //  v0[j+1] + 1
        add     rdx, QWORD PTR [r12-8+rcx*8]  //  v0[j]
        lea     rsi, [rax+1]  // %rax  v1[j]
        cmp     rdi, rax  //  v0[j+1]  v1[j]  += 1
        mov     rax, r9
        cmovg   rax, rsi  //       += 1
        cmp     rax, rdx  //  %rax, %rdx
        cmovg   rax, rdx
        mov     QWORD PTR [r8+rcx*8], rax  // v1[j+1] = ...
        cmp     rbx, rcx  // loop
        jne     .L42

, тАФ v1[j] %rax.


LLVM, - , . , , :


.LBB1_40:                               #   in Loop: Header=BB1_36 Depth=2
        mov     qword ptr [r14 + 8*rsi + 8], rax
        mov     rdx, qword ptr [rbx + 8*rsi + 16]
        inc     rdx
        inc     rax
        xor     ebp, ebp
        cmp     cl, byte ptr [r13 + rsi + 1]
        setne   bpl
        add     rbp, qword ptr [rbx + 8*rsi + 8]
        cmp     rax, rdx
        jg      .LBB1_41
        lea     rdi, [rsi + 2]
        cmp     rax, rbp
        jle     .LBB1_44
        jmp     .LBB1_43

: jmp, j* = jump (: jg тАФ greater, jle тАФ less equal, ..).


v0[j+1], v0[j], cmp s1[i], cmp + jump . , , ( , ) , , . тАФ .


str a тАФ str a, str a тАФ str brandom-random x2
gcc 9.21190 ms1190 ms
clang 9837 ms1662 ms

, GCC , LLVM 2 (!) , .


, . : (jump), тАФ (cmov).
, тАФ .


, , . , , PGO (, JIT ). , GCC PGO clang. тАФ , . , , // , , , .



  • , тАФ
  • , LLVM
  • , GCC LLVM ,
  • ffi. , .. , , ,

, , .



: , , "" , , . Rust (, ).


P.S.


тАФ , -
( )

, тАФ , .. , , , s1 s2. . -, O(n*m) ( for). , . , k. , . , .


LinearLeopard .




  • : -O3 -march=native -std=gnu++17.
  • рдкреНрд░реЛрд╕реЗрд╕рд░: рдЗрдВрдЯреЗрд▓ i5-8250U (рд╣рд╛рдБ, рд▓реИрдкрдЯреЙрдк)
  • OS: рдЙрдмрдВрдЯреВ 19.04 / рд▓рд┐рдирдХреНрд╕ 5.0.0
  • рдЯрд░реНрдмреЛ рдмреВрд╕реНрдЯ рдореЗрдВ рддреЗрдЬреА рд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╣рд▓рд╛ рд░рди, рдлрд┐рд░ рдПрдХ рдкрдВрдХреНрддрд┐ рдореЗрдВ рдиреНрдпреВрдирддрдо рдкрд╛рдВрдЪред 1-2% рдХреЗ рднреАрддрд░ рд╡рд┐рдЪрд▓рдиред
  • рд╡рд┐рднрд┐рдиреНрди 1s рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд▓реЙрдиреНрдЪ рдХреЗ рдмреАрдЪ, рд╣рдо рд╢рд╛рдВрдд рд╣реЛ рдЬрд╛рдПрдВрдЧреЗ (рд╣рд╛рдБ, рд▓реИрдкрдЯреЙрдк)

рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛: рдЖрд▓рд╕реА рдХреЗ рд▓рд┐рдП рд╕реНрдХреНрд░рд┐рдкреНрдЯ


рдЖрдк рдЕрдкрдиреЗ рд╣рд╛рд░реНрдбрд╡реЗрдпрд░ рдкрд░ рдПрдХ рд╣реА рдЪреАрдЬрд╝ рдЪрд▓рд╛ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЬрдирддрд╛ рдХреЛ рдЗрд╕рдХрд╛ рдкрд░рд┐рдгрд╛рдо рдмрддрд╛ рд╕рдХрддреЗ рд╣реИрдВ: рдЧреАрдердм рдХрд╛ рд▓рд┐рдВрдХ ред


рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛: -march = рджреЗрд╢реА рдХреЗ рдмрд┐рдирд╛ рдкрд░рд┐рдгрд╛рдо


рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдореЗрдВ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рдЕрдиреБрд╕рд╛рд░, рдореИрдВрдиреЗ рдЗрд╕ рдзреНрд╡рдЬ рдХреЗ рдкреНрд░рднрд╛рд╡ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ред


рдЭрдВрдбреЗ-рдУ рей -рдорд░рдЪ = рджреЗрд╢реА-рдУ рей -рдорд░рдЪ = рджреЗрд╢реА-O3-O3
рд╕рдВрдХрд▓рдХрдореВрд▓рдбреЙрдкреНрдб (3 рдмреА)рдореВрд▓рдбреЙрдкреНрдб (3 рдмреА)
haskell / llvm--910ms-
gcc 9.21210ms831ms1191ms791ms
рджрдмрдВрдЧ 91915ms741ms1924ms807ms

All Articles