LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)

Takeshi Yamamuro
Takeshi YamamuroR&D Engineer
LLVMで遊ぶ	
  
整数圧縮とか、x86向け自動ベクトル化とか	
                            2013/3/30	
  
             maropu@x86/64最適化勉強会5	
  	
  




                                            1
clang	
       LLVMで遊ぶ	
  
整数圧縮とか、x86向け自動ベクトル化とか	
                            2013/3/30	
  
             maropu@x86/64最適化勉強会5	
  	
  




                                            2
本日の概要	
•  なんでお前clang(LLVM)の話してんの?	
  
  –  RDBMS関連の話題で最近良く扱われるため勉強中	
  
  –  今書いている整数圧縮のコードをより高速化したい	
  

•  整数圧縮ライブラリ:	
  vpacker	
  
  –  hCps://github.com/maropu/vpacker	
  


•  clangのx86向け自動ベクトル化	
  
  –  SIMDを使用した命令列への自動変換	
  




                                            3
LLVMとの出会い・・・	




                 4
DB業界におけるLLVMの利活用	
•  SQLによる関係代数の処理をLLVM-­‐JITで改善	
  
  –  既存DBのSQL処理系*1は冗長的で非効率	
  
                              *1SQLコンパイラとSQL実行エンジンのこと




             Thomas Neumann, Efficiently Compiling Efficient Query Plans for
                                       Modern Hardware, Proc. of VLDB’11
                                                                               5
DB業界におけるLLVMの利活用	
•  Cloudera	
  ImpalaにおけるLLVMの利用	
  
  •  SQL対応の分散クエリエンジン	
  
  •  aggregaQon/join/scanの一部をJITで効率化	
  
  •  hCps://github.com/cloudera/impala	
  




  引用: http://www.theregister.co.uk/2012/10/24/cloudera_hadoop_impala_real_time_query/	
                                                                                6
整数圧縮ライブラリ: vpacker	



                       7
vpacker	
•  32/64-­‐bit整数列を圧縮するライブラリ(C/C++/Java)	
  
  –  hCps://github.com/maropu/vpacker	
  
  	
  
•  前提条件:	
  正の歪度をもつ整数列を効率的に圧縮	
  
  –  大半が小さい値で、稀に大きな値が発生	
  


•  ライブラリの特徴	
  
  –  少ないメモリ量で圧縮&展開	
  
  –  ILPを考慮した展開処理	
  -­‐	
  γ/δ符号と比べて速い	
  
  –  動的計画法による圧縮率の最適化	
  
  –  ヘッダファイルの読み込みのみで使用可能	
  

                                              8
vpacker	
  –	
  使い方 	




                         9
近年の整数圧縮手法	
     ~1990’s	
     ~2000’s	
                                 ~2013	


                                                   BP/SIMD-BP(2012)	


γ/δ/Variable-Byte符号	
                            Varint-G8IU(2011)	
                               Simple9(2005)	
                                          Simple16(2009)	


                                            Simple8b(2010)	


                                                   VSEncoding(2010)	
                               PForDelta(2006)	
                                      OPTPForDelta(2009)	
                                      SIMD-FastPFor/SimplePFor(2012)	
                                                                        10
近年の整数圧縮手法	
     ~1990’s	
     ~2000’s	
                                 ~2013	


                                                   BP/SIMD-BP(2012)	


γ/δ/Variable-Byte符号	
                            Varint-G8IU(2011)	
                               Simple9(2005)	
                                          Simple16(2009)	


                                        Simple8b(2010)	
     -  現在、最速の手法で秒間2000M個整数を展開
     -  vpackerは20130330現在の実装で秒間600〜700M程度	
                                              VSEncoding(2010)	
                            PForDelta(2006)	
                                      OPTPForDelta(2009)	
                                      SIMD-FastPFor/SimplePFor(2012)	
                                                                        11
vpacker	
  –	
  内部構造	
  
•  圧縮データのバイナリフォーマット	
  
   –  前半のディスクリプタ部と圧縮したデータ部で構成	
  

       ディスクリプタ部(desc)	
     圧縮データ部(in)	



      1-byteのディスクリプタの列     圧縮された整数データ	
       後半の圧縮したデータが
    どのように格納されているかを記録	




                                           12
vpacker	
  –	
  内部構造	
  
•  圧縮データのバイナリフォーマット	
  


       ディスクリプタ部(desc)	
                    圧縮データ部(in)	

      1-byteのデータに固定長1-bitで8個の整数が格納	

   void unpack1_8(const char *in, uint32_t *out) {
        *out++ = in[0] & 0x01;
        *out++ = (in[0] >> 1) & 0x01;
        *out++ = (in[0] >> 2) & 0x01;
          ...
        *out++ = (in[0] >> 7) & 0x01;
    }	


                                                          13
vpacker	
  –	
  内部構造	
•  圧縮データのバイナリフォーマット	
  
        2-byteのデータに固定長2-bitで8個の整数が格納	


       ディスクリプタ部(desc)	
                    圧縮データ部(in)	

      1-byteのデータに固定長1-bitで8個の整数が格納	

   void unpack2_8(const char *in, uint32_t *out) {
        *out++ = in[0] & 0x03;
        *out++ = (in[0] >> 2) & 0x03;
        *out++ = (in[0] >> 4) & 0x03;
          ...
        *out++ = (in[1] >> 6) & 0x03;
    }	


                                                          14
vpacker	
  –	
  内部構造	
•  復元処理の動作概要	
  
       2-byteのデータに固定長2-bitで8個の整数が格納	


      ディスクリプタ部(desc)	
            圧縮データ部(in)	

     1-byteのデータに固定長1-bitで8個の整数が格納	

   while (1) {
     switch (*desc++) {
       case 1-bitで8個の整数を展開: unpack1_8(in, out); break;
       case 2-bitで8個の整数を展開: unpack2_8(in, out); break;
        ...
     }
                  -  VMのインタプリタ的な処理の流れ
   }	
            -  descは1-byteのため最大256分岐(分岐数は設計による)	

                                                          15
vpacker	
  –	
  内部構造	
•  LLVM-­‐JITを用いてwhile-­‐switchを軽量化	
  
  –  共通する復元処理をまとめることでjmp命令を除去	
  

      ディスクリプタ部(desc)	
               圧縮データ部(in)	


                              「前提条件」より大半の復元処理は
                                  一部の関数に集中	
   while (1) {
     switch (*desc++) {
       case 1-bitで8個の整数を展開: unpack1_8(in, out); break;
       case 2-bitで8個の整数を展開: unpack2_8(in, out); break;
        ...
     }
   }	


                                                         16
vpacker	
  –	
  内部構造	
•  呼び出しが集中している関数を高速化	
  
  –  基本はSIMDを利用したデータ並列性の向上	
  

      ディスクリプタ部(desc)	
               圧縮データ部(in)	


                             呼び出しが集中している関数を高速化	
   while (1) {
     switch (*desc++) {
       case 1-bitで8個の整数を展開: unpack1_8(in, out); break;
       case 2-bitで8個の整数を展開: unpack2_8(in, out); break;
        ...
     }
   }	


                                                         17
gcc(v4.8)の自動ベクトル化	
•  この関数*1ってどんな機械語に変換されるの?	
  
   –  処理に依存関係が無く,ベクトル化しやすそうな印象	
  

   void unpack1(const char *in, uint32_t *out, int n) {
        for (int i = 0; i < n; i++) {
              *out++ = in[0] & 0x01;
              *out++ = (in[0] >> 1) & 0x01;
              *out++ = (in[0] >> 2) & 0x01;
                ...
              *out++ = (in[0] >> 7) & 0x01;
        }
   }	


*1 現実に即して,ループ回数(n)を指定できるように変更しました	
                                                          18
gcc(v4.8)の自動ベクトル化	
•  この関数ってどんな機械語に変換されるの?	
  
 –  処理に依存関係が無く,ベクトル化しやすそうな印象	
  

  void unpack1(const char *in, uint32_t *out, int n) {
       for (int i = 0; i < n; i++) {
             *out++ = in[0] & 0x01;
             *out++ = (in[0] >> 1) & 0x01;
             *out++ = (in[0] >> 2) & 0x01;
               ...
             *out++ = (in[0] >> 7) & 0x01;
       }
  }	
         重要) コンパイルする前に自動ベクトル化されやすいように前処理	


                                                         19
gcc(v4.8)の自動ベクトル化	
•  この関数ってどんな機械語に変換されるの?	
  
 –  処理に依存関係が無く,ベクトル化しやすそうな印象	
  

  void unpack1(const char *in, uint32_t *out, int n) {
       for (int i = 0; i < n; i++) {
             for (int j = 0; j < 8; j++)
                    *out++ = (*in >> j) & 0x01;
             in++;
       }
  }	
        gccの場合、SLP(Superword-Level Parallelism)による最適化より
              Loop Vectorizerに任せたほうが良いらしいです	




                                                          20
gcc(v4.8)の自動ベクトル化	
•  この関数ってどんな機械語に変換されるの?	
  
 –  処理に依存関係が無く,ベクトル化しやすそうな印象	
  

  void unpack1(const char * __restrict__ in,
                  uint32_t * __restrict__ out, int n) {
       for (int i = 0; i < n; i++) {
             for (int j = 0; j < 8; j++)
                    *out++ = (*in >> j) & 0x01;
             in++;
       }
  }	
          __restrict__を付与してin/outを呼び出し側で16Bにアライメント	




                                                          21
gcc(v4.8)の自動ベクトル化	
      •  一部だけ抜粋	
  &	
  並び替え(’gcc	
  -­‐O3’)	
  
      movdqu      (%r9), %xmm1   // in - %xmm1

         pxor        %xmm2, %xmm2
         pcmpgtb     %xmm1, %xmm2
         movdqa      %xmm1, %xmm3
         punpckhbw   %xmm2, %xmm1
      punpcklbw   %xmm2, %xmm3

      pxor      %xmm2, %xmm2
   movdqa    %xmm3, %xmm4
      pcmpgtw   %xmm3, %xmm2
      punpcklwd %xmm2, %xmm4

         movdqa      %xmm4, %xmm5
         pand        %xmm0, %xmm5   // %xmm1=[0x01, 0x01, 0x01, 0x01]
         ....	

                                                                        22
gcc(v4.8)の自動ベクトル化	
      •  一部だけ抜粋	
  	
  並び替え(’gcc	
  -­‐O3’)	
  
      movdqu      (%r9), %xmm1   // in - %xmm1

         pxor        %xmm2, %xmm2
         pcmpgtb     %xmm1, %xmm2
         movdqa      %xmm1, %xmm3
         punpckhbw   %xmm2, %xmm1
      punpcklbw   %xmm2, %xmm3 バイトからワードに符号拡張	

      pxor      %xmm2, %xmm2
   movdqa    %xmm3, %xmm4
      pcmpgtw   %xmm3, %xmm2
      punpcklwd %xmm2, %xmm4 ワードからダブルワードに符号拡張	

         movdqa      %xmm4, %xmm5
         pand        %xmm0, %xmm5   // %xmm1=[0x01, 0x01, 0x01, 0x01]
         ....	
                  0x01でマスクして展開処理完了	
                                                                        23
gcc(v4.8)の自動ベクトル化	
      •  一部だけ抜粋	
  	
  並び替え(’gcc	
  -­‐O3’)	
  
      movdqu      (%r9), %xmm1    // in - %xmm1

         pxor        %xmm2, %xmm2
         pcmpgtb     %xmm1, %xmm2
         movdqa      %xmm1, %xmm3
         punpckhbw   %xmm2, %xmm1
      punpcklbw   %xmm2, %xmm3 バイトからワードに符号拡張	

      pxor      %xmm2, %xmm2
   movdqa    %xmm3, %xmm4
      pcmpgtw   %xmm3, %xmm2
      punpcklwd %xmm2, %xmm4 ワードからダブルワードに符号拡張	
                ‘n  15’で分岐させてLoopを全てinline化するアグレッシブな最適化
         movdqa       %xmm4, %xmm5
                →’n = 15’はベクトル化されていないパスに分岐	
         pand         %xmm0, %xmm5 // %xmm1=[0x01, 0x01, 0x01, 0x01]
         ....	
                    0x01でマスクして展開処理完了	
                                                                       24
clangのx86向け自動ベクトル化	
  



                         25
clangと自動ベクトル化	
•  LLVM上に実装されたC/C++用フロントエンド	
  
    –  hCp://clang.llvm.org/index.html	
  
•  Auto-­‐VectorizaQon	
  in	
  LLVM	
  
    –  hCp://llvm.org/docs/Vectorizers.html	
  
•  Linpackを用いた性能評価	
  
    –  with	
  loop	
  vectorizaQon	
  at	
  -­‐O3	
  running	
  on	
  a	
  Sandybridge	
  




                                                            自動ベクトル化の有無で
                                                             性能差が3倍程度!	


                                                                                              26
clangにおける2種類のVectorizer	
•  Basic-­‐Block(BB)	
  Vectorizer	
  –	
  SLP	
  in	
  gcc	
  	
  
     –  v3.1で”	
  -­‐mllvm	
  –vectorize”として導入	
  
     –  最適化の対象が「Basic	
  Block」	
  
     –  歴史的に実装されたのはコチラが先	
  


•  Loop	
  Vectorizer	
  
     –  v3.2でようやく”	
  -­‐mllvm	
  –vectorize-­‐loops”として導入	
  
     –  「Unroll+BB	
  Vectorizer」にLoop間依存解析を加えたもの	
  
     –  自動ベクトル化の制約(v3.2のReleaseNotesより)	
  
          •  Loop枚のカウントは”1”のみ	
  
          •  InducQon変数は一番内側のLoopのみ使用可能	
  


                                                                      27
clangの自動ベクトル化パラメータ	
•  clang-­‐v3.2を利用(2013/3/30現在最新)	
  
    –  デフォルトで自動ベクトル化は全てOFF	
  
    –  v3.3からLoop	
  Vectorizerはデフォルトに	
  
    	
  
•  -­‐mllvm	
  –vectorize,	
  -­‐mllvm	
  –vectorize-­‐loops	
  
    –  -­‐O2/-­‐O3との併用が必要	
  
    –  -­‐Osはコード増加が発生しない場合に適用	
  
•  -­‐mllvm	
  –bb-­‐vectorize-­‐aligned-­‐only	
  
    –  アラインされたstore/loadのみを最適化に使用	
  
•  -­‐mllvm	
  –force-­‐vector-­‐width=X	
  
    –  最適化で使用するベクトル要素数をXで指定	
  

                                                                   28
その他の補助パラメータ	
•  -­‐mllvm	
  –unroll-­‐allow-­‐parQal	
  
       –  Loop内の部分的なUnrollを可能に	
  
•  -­‐mllvm	
  –unroll-­‐runQme	
  
       –  実行時にLoopを数えてUnroll可能に	
  
•  -­‐funsafe-­‐math-­‐opQmizaQons,	
  -­‐ffast-­‐math	
  
       –  浮動小数点演算にIEEE/ISO仕様外の最適化を適用	
  


•  他の関連するパラメータは以下の資料が詳しい	
  
       –  Auto-­‐vectorizaQon	
  with	
  LLVM	
  
       –  hCp://llvm.org/devmtg/2012-­‐04-­‐12/Slides/Hal_Finkel.pdf	
  
	
  
                                                                       29
WriQng	
  Vectorizer-­‐Friendly	
  Code	
  in	
  clang	
  	
  
•  example.1#	
  
       –  clang	
  -­‐O3	
  -­‐mllvm	
  -­‐vectorize-­‐loops	
  
	
  
                 void test1(float * __restrict__ a,
                                float * __restrict__ b, int n) {
                         for (int i = 0; i  n; i++)
                               a[i] += b[i];
                    }	




                                                                   30
WriQng	
  Vectorizer-­‐Friendly	
  Code	
  in	
  clang	
  	
  
•  example.1#	
  
       –  clang	
  -­‐O3	
  -­‐mllvm	
  -­‐vectorize-­‐loops	
  
	
                                      %rdiと%rsiは16Bに揃えてあるのに
                .LBB0_2:                 なぜかmovapsに変換されない?	
                    movups 16(%rdi,%rax,4), %xmm1
                    movups 16(%rsi,%rax,4), %xmm0
                    addps %xmm1, %xmm0
                    movups (%rdi,%rax,4), %xmm1
                    movups (%rsi,%rax,4), %xmm2
                    movups %xmm0, 16(%rdi,%rax,4)
                    addps %xmm1, %xmm2
                    movups %xmm2, (%rdi,%rax,4)
                    addq $8, %rax
                    cmpq %rax, %rcx
                    jne .LBB0_2	
                                  31
WriQng	
  Vectorizer-­‐Friendly	
  Code	
  in	
  clang	
  	
  
•  example.2#	
  
       –  clang	
  -­‐O3	
  -­‐mllvm	
  -­‐vectorize-­‐loops	
  
	
  
                 void test2(float * __restrict__ a,
                                float * __restrict__ b, int n) {
                         for (int i = 0; i  n; i += 2)
                               a[i] += b[i];
                    }	




                                                                   32
WriQng	
  Vectorizer-­‐Friendly	
  Code	
  in	
  clang	
  	
  
•  example.2#	
  
       –  clang	
  -­‐O3	
  -­‐mllvm	
  -­‐vectorize-­‐loops	
  
	
  
                .LBB0_2:
                    movss (%rsi,%rax,4), %xmm0
                    addss (%rdi,%rax,4), %xmm0
                    movss %xmm0, (%rdi,%rax,4)
                    addq $2, %rax
                    cmpl %edx, %eax
                    jl   .LBB0_2	




                                                                   33
WriQng	
  Vectorizer-­‐Friendly	
  Code	
  in	
  clang	
  	
  
•  example.3#	
  
       –  clang	
  -­‐O3	
  -­‐mllvm	
  -­‐vectorize-­‐loops	
  
	
  
                 void test3(float * __restrict__ a,
                                float * __restrict__ b, int n) {
                         for (int i = 0; i  n; i += 1) {
                               for (int j = 0; j  SIZE; j++)
                                      a[i * SIZE + j] += b[i * SIZE + j];
                         }
                    }	




                                                                            34
WriQng	
  Vectorizer-­‐Friendly	
  Code	
  in	
  clang	
  	
  
•  example.3#	
  
       –  clang	
  -­‐O3	
  -­‐mllvm	
  -­‐vectorize-­‐loops	
  
	
                   .LBB1_22: # = The Inner Loop
                         movups (%rbx), %xmm2
                         movups 16(%rbx), %xmm1
                         movups (%rax), %xmm0
                         movups 16(%rax), %xmm3
                         addps %xmm2, %xmm0
                         addps %xmm1, %xmm3
                         movups %xmm3, 16(%rbx)
                         movups %xmm0, (%rbx)
                         addq $32, %rbx
                         addq $32, %rax
                         addq $-8, %rdi
                         jne .LBB1_22	
                                                                   35
WriQng	
  Vectorizer-­‐Friendly	
  Code	
  in	
  clang	
  	
  
•  example.4#	
  
       –  clang	
  -­‐O3	
  -­‐mllvm	
  -­‐vectorize-­‐loops	
  
	
  
                 float test4(float * __restrict__ a, int n) {
                          float S = 0.0;
                          for (int i = 0; i  n; i += 1)
                                S += a[i];
                          return S;
                    }	




                                                                   36
WriQng	
  Vectorizer-­‐Friendly	
  Code	
  in	
  clang	
  	
  
•  example.4#	
  
       –  clang	
  -­‐O3	
  -­‐mllvm	
  -­‐vectorize-­‐loops	
  
	
  
                 .LBB0_1:
                        addss (%rdi), %xmm0
                        addq $4, %rdi
                        decl %esi
                        jne .LBB0_1	

                 浮動小数点演算は結合則が成り立たないため、こういう命令列に
                 →clangにも’-ffast-math’があるが、出力する命令は同じだった	




                                                                   37
WriQng	
  Vectorizer-­‐Friendly	
  Code	
  in	
  clang	
  	
  
•  example.4#	
  
       –  gcc	
  -­‐O3	
  -­‐ffast-­‐math	
  
	
                  .L33:
                            addps (%rax), %xmm0
                            addq $16, %rax
                            cmpq %rdx, %rax
                            jne .L33
                            movaps %xmm0, %xmm1
                            movhlps %xmm0, %xmm1
                            addps %xmm0, %xmm1
                            movaps %xmm1, %xmm0
                            shufps $85, %xmm1, %xmm0
                            addps %xmm1, %xmm0
                            unpcklps    %xmm0, %xmm0	
                                                                 38
WriQng	
  Vectorizer-­‐Friendly	
  Code	
  in	
  clang	
  	
  
•  example.4#	
  
       –  gcc	
  -­‐O3	
  -­‐ffast-­‐math	
     ベクトル加算して	
	
                  .L33:
                            addps (%rax), %xmm0
                            addq $16, %rax
                            cmpq %rdx, %rax
                            jne .L33              水平加算	
                            movaps %xmm0, %xmm1
                            movhlps %xmm0, %xmm1
                            addps %xmm0, %xmm1
                            movaps %xmm1, %xmm0
                            shufps $85, %xmm1, %xmm0
                            addps %xmm1, %xmm0
                            unpcklps    %xmm0, %xmm0	
                                                                 39
最後に・・・	
  


             40
clangが出力する「unpack1」	
•  一部だけ抜粋(’	
  clang	
  -­‐S	
  -­‐O3	
  -­‐mllvm	
  -­‐vectorize’)	
  
    movsbl     (%rdi), %eax        # *in - %eax
    movd        %eax, %xmm0
    pshufd      $0, %xmm0, %xmm4
    pshufd      $68, %xmm4, %xmm3
    pand        %xmm8, %xmm4
    movl       %eax, %ecx
     ...
    shrq       $2, %r10
    movd       %r10, %xmm0
    punpcklqdq %xmm7, %xmm0
    pand 人類には早すぎる難解なアセンブリが出力された・・・
               %xmm1, %xmm0
    pshufd →nの値でunrollはしないgccに比べてコンサバな最適化	
               $-128, %xmm0, %xmm7
    movss      %xmm6, %xmm7
    movlhps    %xmm7, %xmm5
    shufps     $-30, %xmm7, %xmm5
    movups    %xmm5, (%rsi)       # %xmm5 - dst	

                                                                          41
gcc-­‐4.8	
  vs	
  clang-­‐3.2	
  	
•  「unapack1」の性能比較	
  
•  Intel	
  Core	
  i5-­‐3427@1.8GHzを使用	
  

                       n=15	
          n=16	
     n=32	
      n=64	
          gcc	
    0.051us	
      0.040us	
     0.073us	
   0.152us	
       clang	
     0.105us	
      0.110us	
     0.224us	
   0.446us	
        raQo	
          x2.1	
         x2.7	
      x3.1	
      x3.0	

                                 ベクトル化された状態で約3倍の性能差	




                                                                        42
本日のまとめ	
  


             43
本日のまとめ	
•  clang-­‐v3.2の自動ベクトル化の性能調査	
  
  –  基本的なものは自動的にベクトル化される	
  
  –  処理が複雑になるとgccに対して2~3倍程度の性能差も	
  


•  ‘Vectorizer-­‐Friendly’はまだまだ重要	
  
  –  完全にコンパイラ任せ,というわけには現在いかない	
  
  –  256-­‐bit,	
  512-­‐bit,	
  ...とベクトル長が増えると性能差は拡大	
  
   	
  




                                                            44
本日のまとめ	
•  自動ベクトル化のためのコード規約	
  
 	
  	
  	
  1.	
  ポインタのエイリアスは避ける	
  
 	
  	
  	
  	
  	
   ・必要な個所では__restrict__を付ける	
  
 	
  
 	
  	
  	
  2.	
  ベクトル長の境界に合わせる	
  
 	
  	
  	
  	
  	
  	
  	
  	
  ・__builQn_assume_aligned(X),	
  __aCribute__((aligned(X))の活用	
  
 	
  
 	
  	
  	
  3.	
  Loop内の手作業のinline化は避ける	
  
 	
  	
  	
  	
  	
  	
  	
  ・Loop	
  Vectorizerに任せたほうが賢い	
  
  	
  




                                                                                                    45
1 de 45

Recomendados

ARM CPUにおけるSIMDを用いた高速計算入門 por
ARM CPUにおけるSIMDを用いた高速計算入門ARM CPUにおけるSIMDを用いた高速計算入門
ARM CPUにおけるSIMDを用いた高速計算入門Fixstars Corporation
7K vistas114 diapositivas
プログラムを高速化する話 por
プログラムを高速化する話プログラムを高速化する話
プログラムを高速化する話京大 マイコンクラブ
242.3K vistas120 diapositivas
Marp Tutorial por
Marp TutorialMarp Tutorial
Marp TutorialRui Watanabe
3.2K vistas15 diapositivas
高速な倍精度指数関数expの実装 por
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装MITSUNARI Shigeo
15K vistas20 diapositivas
組み込み関数(intrinsic)によるSIMD入門 por
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門Norishige Fukushima
47.5K vistas122 diapositivas
マルチコアを用いた画像処理 por
マルチコアを用いた画像処理マルチコアを用いた画像処理
マルチコアを用いた画像処理Norishige Fukushima
51.6K vistas142 diapositivas

Más contenido relacionado

La actualidad más candente

C++ マルチスレッド 入門 por
C++ マルチスレッド 入門C++ マルチスレッド 入門
C++ マルチスレッド 入門京大 マイコンクラブ
57.8K vistas53 diapositivas
プログラミングコンテストでの動的計画法 por
プログラミングコンテストでの動的計画法プログラミングコンテストでの動的計画法
プログラミングコンテストでの動的計画法Takuya Akiba
91.6K vistas59 diapositivas
AVX-512(フォーマット)詳解 por
AVX-512(フォーマット)詳解AVX-512(フォーマット)詳解
AVX-512(フォーマット)詳解MITSUNARI Shigeo
8.8K vistas29 diapositivas
llvm入門 por
llvm入門llvm入門
llvm入門MITSUNARI Shigeo
16.6K vistas19 diapositivas
SAT/SMTソルバの仕組み por
SAT/SMTソルバの仕組みSAT/SMTソルバの仕組み
SAT/SMTソルバの仕組みMasahiro Sakai
36.7K vistas51 diapositivas
条件分岐とcmovとmaxps por
条件分岐とcmovとmaxps条件分岐とcmovとmaxps
条件分岐とcmovとmaxpsMITSUNARI Shigeo
5.7K vistas24 diapositivas

La actualidad más candente(20)

プログラミングコンテストでの動的計画法 por Takuya Akiba
プログラミングコンテストでの動的計画法プログラミングコンテストでの動的計画法
プログラミングコンテストでの動的計画法
Takuya Akiba91.6K vistas
AVX-512(フォーマット)詳解 por MITSUNARI Shigeo
AVX-512(フォーマット)詳解AVX-512(フォーマット)詳解
AVX-512(フォーマット)詳解
MITSUNARI Shigeo8.8K vistas
SAT/SMTソルバの仕組み por Masahiro Sakai
SAT/SMTソルバの仕組みSAT/SMTソルバの仕組み
SAT/SMTソルバの仕組み
Masahiro Sakai36.7K vistas
何となく勉強した気分になれるパーサ入門 por masayoshi takahashi
何となく勉強した気分になれるパーサ入門何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門
masayoshi takahashi35.8K vistas
DockerコンテナでGitを使う por Kazuhiro Suga
DockerコンテナでGitを使うDockerコンテナでGitを使う
DockerコンテナでGitを使う
Kazuhiro Suga18.8K vistas
本当は恐ろしい分散システムの話 por Kumazaki Hiroki
本当は恐ろしい分散システムの話本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話
Kumazaki Hiroki686.1K vistas
std::pin の勘所 por Hiroaki Goto
std::pin の勘所std::pin の勘所
std::pin の勘所
Hiroaki Goto2.7K vistas
並列化による高速化 por sakura-mike
並列化による高速化 並列化による高速化
並列化による高速化
sakura-mike6.7K vistas
中3女子でもわかる constexpr por Genya Murakami
中3女子でもわかる constexpr中3女子でもわかる constexpr
中3女子でもわかる constexpr
Genya Murakami49K vistas
SSE4.2の文字列処理命令の紹介 por MITSUNARI Shigeo
SSE4.2の文字列処理命令の紹介SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介
MITSUNARI Shigeo8.8K vistas
乱択データ構造の最新事情 -MinHash と HyperLogLog の最近の進歩- por Takuya Akiba
乱択データ構造の最新事情 -MinHash と HyperLogLog の最近の進歩-乱択データ構造の最新事情 -MinHash と HyperLogLog の最近の進歩-
乱択データ構造の最新事情 -MinHash と HyperLogLog の最近の進歩-
Takuya Akiba32.4K vistas

Similar a LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)

Halide による画像処理プログラミング入門 por
Halide による画像処理プログラミング入門Halide による画像処理プログラミング入門
Halide による画像処理プログラミング入門Fixstars Corporation
15.5K vistas70 diapositivas
HaskellではじめるCortex-M3組込みプログラミング por
HaskellではじめるCortex-M3組込みプログラミングHaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミングKiwamu Okabe
2.8K vistas11 diapositivas
Prosym2012 por
Prosym2012Prosym2012
Prosym2012MITSUNARI Shigeo
2.7K vistas33 diapositivas
あるRISC-V CPUの 浮動小数点数(異常なし) por
あるRISC-V CPUの 浮動小数点数(異常なし)あるRISC-V CPUの 浮動小数点数(異常なし)
あるRISC-V CPUの 浮動小数点数(異常なし)たけおか しょうぞう
395 vistas17 diapositivas
osoljp 2011.08 por
osoljp 2011.08osoljp 2011.08
osoljp 2011.08@ otsuka752
603 vistas36 diapositivas
PEZY-SC2上における倍々精度Rgemmの実装と評価 por
PEZY-SC2上における倍々精度Rgemmの実装と評価PEZY-SC2上における倍々精度Rgemmの実装と評価
PEZY-SC2上における倍々精度Rgemmの実装と評価Toshiaki Hishinuma
1.8K vistas47 diapositivas

Similar a LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)(20)

Halide による画像処理プログラミング入門 por Fixstars Corporation
Halide による画像処理プログラミング入門Halide による画像処理プログラミング入門
Halide による画像処理プログラミング入門
Fixstars Corporation15.5K vistas
HaskellではじめるCortex-M3組込みプログラミング por Kiwamu Okabe
HaskellではじめるCortex-M3組込みプログラミングHaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミング
Kiwamu Okabe2.8K vistas
PEZY-SC2上における倍々精度Rgemmの実装と評価 por Toshiaki Hishinuma
PEZY-SC2上における倍々精度Rgemmの実装と評価PEZY-SC2上における倍々精度Rgemmの実装と評価
PEZY-SC2上における倍々精度Rgemmの実装と評価
Toshiaki Hishinuma1.8K vistas
PL/CUDA - Fusion of HPC Grade Power with In-Database Analytics por Kohei KaiGai
PL/CUDA - Fusion of HPC Grade Power with In-Database AnalyticsPL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
PL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
Kohei KaiGai1.1K vistas
【関東GPGPU勉強会#4】GTX 1080でComputer Vision アルゴリズムを色々動かしてみる por Yasuhiro Yoshimura
【関東GPGPU勉強会#4】GTX 1080でComputer Visionアルゴリズムを色々動かしてみる【関東GPGPU勉強会#4】GTX 1080でComputer Visionアルゴリズムを色々動かしてみる
【関東GPGPU勉強会#4】GTX 1080でComputer Vision アルゴリズムを色々動かしてみる
Yasuhiro Yoshimura5.3K vistas
130710 02 por openrtm
130710 02130710 02
130710 02
openrtm1.4K vistas
第11回 配信講義 計算科学技術特論B(2022) por RCCSRENKEI
第11回 配信講義 計算科学技術特論B(2022)第11回 配信講義 計算科学技術特論B(2022)
第11回 配信講義 計算科学技術特論B(2022)
RCCSRENKEI160 vistas
Bluetooth通信の 仕組みと活用法紹介 por Takehiko YOSHIDA
Bluetooth通信の仕組みと活用法紹介Bluetooth通信の仕組みと活用法紹介
Bluetooth通信の 仕組みと活用法紹介
Takehiko YOSHIDA12.7K vistas
Dalvik仮想マシンのアーキテクチャ 改訂版 por Takuya Matsunaga
Dalvik仮想マシンのアーキテクチャ 改訂版Dalvik仮想マシンのアーキテクチャ 改訂版
Dalvik仮想マシンのアーキテクチャ 改訂版
Takuya Matsunaga5.3K vistas
LUT-Network Revision2 por ryuz88
LUT-Network Revision2LUT-Network Revision2
LUT-Network Revision2
ryuz88980 vistas
x86とコンテキストスイッチ por Masami Ichikawa
x86とコンテキストスイッチx86とコンテキストスイッチ
x86とコンテキストスイッチ
Masami Ichikawa8.6K vistas
Emacsでの翻訳 - Emacsで訳す、gettextで国際化されたソフトウェア por Masaharu IWAI
Emacsでの翻訳 - Emacsで訳す、gettextで国際化されたソフトウェアEmacsでの翻訳 - Emacsで訳す、gettextで国際化されたソフトウェア
Emacsでの翻訳 - Emacsで訳す、gettextで国際化されたソフトウェア
Masaharu IWAI1.4K vistas
関東GPGPU勉強会 LLVM meets GPU por Takuro Iizuka
関東GPGPU勉強会 LLVM meets GPU関東GPGPU勉強会 LLVM meets GPU
関東GPGPU勉強会 LLVM meets GPU
Takuro Iizuka4.8K vistas

Más de Takeshi Yamamuro

LT: Spark 3.1 Feature Expectation por
LT: Spark 3.1 Feature ExpectationLT: Spark 3.1 Feature Expectation
LT: Spark 3.1 Feature ExpectationTakeshi Yamamuro
1K vistas9 diapositivas
Apache Spark + Arrow por
Apache Spark + ArrowApache Spark + Arrow
Apache Spark + ArrowTakeshi Yamamuro
1.2K vistas16 diapositivas
Quick Overview of Upcoming Spark 3.0 + α por
Quick Overview of Upcoming Spark 3.0 + αQuick Overview of Upcoming Spark 3.0 + α
Quick Overview of Upcoming Spark 3.0 + αTakeshi Yamamuro
713 vistas30 diapositivas
MLflowによる機械学習モデルのライフサイクルの管理 por
MLflowによる機械学習モデルのライフサイクルの管理MLflowによる機械学習モデルのライフサイクルの管理
MLflowによる機械学習モデルのライフサイクルの管理Takeshi Yamamuro
9.6K vistas20 diapositivas
Taming Distributed/Parallel Query Execution Engine of Apache Spark por
Taming Distributed/Parallel Query Execution Engine of Apache SparkTaming Distributed/Parallel Query Execution Engine of Apache Spark
Taming Distributed/Parallel Query Execution Engine of Apache SparkTakeshi Yamamuro
1.4K vistas43 diapositivas
LLJVM: LLVM bitcode to JVM bytecode por
LLJVM: LLVM bitcode to JVM bytecodeLLJVM: LLVM bitcode to JVM bytecode
LLJVM: LLVM bitcode to JVM bytecodeTakeshi Yamamuro
1.3K vistas21 diapositivas

Más de Takeshi Yamamuro(20)

Quick Overview of Upcoming Spark 3.0 + α por Takeshi Yamamuro
Quick Overview of Upcoming Spark 3.0 + αQuick Overview of Upcoming Spark 3.0 + α
Quick Overview of Upcoming Spark 3.0 + α
Takeshi Yamamuro713 vistas
MLflowによる機械学習モデルのライフサイクルの管理 por Takeshi Yamamuro
MLflowによる機械学習モデルのライフサイクルの管理MLflowによる機械学習モデルのライフサイクルの管理
MLflowによる機械学習モデルのライフサイクルの管理
Takeshi Yamamuro9.6K vistas
Taming Distributed/Parallel Query Execution Engine of Apache Spark por Takeshi Yamamuro
Taming Distributed/Parallel Query Execution Engine of Apache SparkTaming Distributed/Parallel Query Execution Engine of Apache Spark
Taming Distributed/Parallel Query Execution Engine of Apache Spark
Takeshi Yamamuro1.4K vistas
LLJVM: LLVM bitcode to JVM bytecode por Takeshi Yamamuro
LLJVM: LLVM bitcode to JVM bytecodeLLJVM: LLVM bitcode to JVM bytecode
LLJVM: LLVM bitcode to JVM bytecode
Takeshi Yamamuro1.3K vistas
An Experimental Study of Bitmap Compression vs. Inverted List Compression por Takeshi Yamamuro
An Experimental Study of Bitmap Compression vs. Inverted List CompressionAn Experimental Study of Bitmap Compression vs. Inverted List Compression
An Experimental Study of Bitmap Compression vs. Inverted List Compression
Takeshi Yamamuro3.7K vistas
Sparkのクエリ処理系と周辺の話題 por Takeshi Yamamuro
Sparkのクエリ処理系と周辺の話題Sparkのクエリ処理系と周辺の話題
Sparkのクエリ処理系と周辺の話題
Takeshi Yamamuro2.8K vistas
浮動小数点(IEEE754)を圧縮したい@dsirnlp#4 por Takeshi Yamamuro
浮動小数点(IEEE754)を圧縮したい@dsirnlp#4浮動小数点(IEEE754)を圧縮したい@dsirnlp#4
浮動小数点(IEEE754)を圧縮したい@dsirnlp#4
Takeshi Yamamuro3.9K vistas
Introduction to Modern Analytical DB por Takeshi Yamamuro
Introduction to Modern Analytical DBIntroduction to Modern Analytical DB
Introduction to Modern Analytical DB
Takeshi Yamamuro11.7K vistas
SIGMOD’12勉強会 -Session 7- por Takeshi Yamamuro
SIGMOD’12勉強会 -Session 7-SIGMOD’12勉強会 -Session 7-
SIGMOD’12勉強会 -Session 7-
Takeshi Yamamuro3.7K vistas
A x86-optimized rank&select dictionary for bit sequences por Takeshi Yamamuro
A x86-optimized rank&select dictionary for bit sequencesA x86-optimized rank&select dictionary for bit sequences
A x86-optimized rank&select dictionary for bit sequences
Takeshi Yamamuro2K vistas
研究動向から考えるx86/x64最適化手法 por Takeshi Yamamuro
研究動向から考えるx86/x64最適化手法研究動向から考えるx86/x64最適化手法
研究動向から考えるx86/x64最適化手法
Takeshi Yamamuro6K vistas

LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)

  • 1. LLVMで遊ぶ   整数圧縮とか、x86向け自動ベクトル化とか 2013/3/30   maropu@x86/64最適化勉強会5     1
  • 2. clang LLVMで遊ぶ   整数圧縮とか、x86向け自動ベクトル化とか 2013/3/30   maropu@x86/64最適化勉強会5     2
  • 3. 本日の概要 •  なんでお前clang(LLVM)の話してんの?   –  RDBMS関連の話題で最近良く扱われるため勉強中   –  今書いている整数圧縮のコードをより高速化したい   •  整数圧縮ライブラリ:  vpacker   –  hCps://github.com/maropu/vpacker   •  clangのx86向け自動ベクトル化   –  SIMDを使用した命令列への自動変換   3
  • 5. DB業界におけるLLVMの利活用 •  SQLによる関係代数の処理をLLVM-­‐JITで改善   –  既存DBのSQL処理系*1は冗長的で非効率   *1SQLコンパイラとSQL実行エンジンのこと Thomas Neumann, Efficiently Compiling Efficient Query Plans for Modern Hardware, Proc. of VLDB’11 5
  • 6. DB業界におけるLLVMの利活用 •  Cloudera  ImpalaにおけるLLVMの利用   •  SQL対応の分散クエリエンジン   •  aggregaQon/join/scanの一部をJITで効率化   •  hCps://github.com/cloudera/impala   引用: http://www.theregister.co.uk/2012/10/24/cloudera_hadoop_impala_real_time_query/ 6
  • 8. vpacker •  32/64-­‐bit整数列を圧縮するライブラリ(C/C++/Java)   –  hCps://github.com/maropu/vpacker     •  前提条件:  正の歪度をもつ整数列を効率的に圧縮   –  大半が小さい値で、稀に大きな値が発生   •  ライブラリの特徴   –  少ないメモリ量で圧縮&展開   –  ILPを考慮した展開処理  -­‐  γ/δ符号と比べて速い   –  動的計画法による圧縮率の最適化   –  ヘッダファイルの読み込みのみで使用可能   8
  • 10. 近年の整数圧縮手法 ~1990’s ~2000’s ~2013 BP/SIMD-BP(2012) γ/δ/Variable-Byte符号 Varint-G8IU(2011) Simple9(2005) Simple16(2009) Simple8b(2010) VSEncoding(2010) PForDelta(2006) OPTPForDelta(2009) SIMD-FastPFor/SimplePFor(2012) 10
  • 11. 近年の整数圧縮手法 ~1990’s ~2000’s ~2013 BP/SIMD-BP(2012) γ/δ/Variable-Byte符号 Varint-G8IU(2011) Simple9(2005) Simple16(2009) Simple8b(2010) -  現在、最速の手法で秒間2000M個整数を展開 -  vpackerは20130330現在の実装で秒間600〜700M程度 VSEncoding(2010) PForDelta(2006) OPTPForDelta(2009) SIMD-FastPFor/SimplePFor(2012) 11
  • 12. vpacker  –  内部構造   •  圧縮データのバイナリフォーマット   –  前半のディスクリプタ部と圧縮したデータ部で構成   ディスクリプタ部(desc) 圧縮データ部(in) 1-byteのディスクリプタの列 圧縮された整数データ 後半の圧縮したデータが どのように格納されているかを記録 12
  • 13. vpacker  –  内部構造   •  圧縮データのバイナリフォーマット   ディスクリプタ部(desc) 圧縮データ部(in) 1-byteのデータに固定長1-bitで8個の整数が格納 void unpack1_8(const char *in, uint32_t *out) { *out++ = in[0] & 0x01; *out++ = (in[0] >> 1) & 0x01; *out++ = (in[0] >> 2) & 0x01; ... *out++ = (in[0] >> 7) & 0x01; } 13
  • 14. vpacker  –  内部構造 •  圧縮データのバイナリフォーマット   2-byteのデータに固定長2-bitで8個の整数が格納 ディスクリプタ部(desc) 圧縮データ部(in) 1-byteのデータに固定長1-bitで8個の整数が格納 void unpack2_8(const char *in, uint32_t *out) { *out++ = in[0] & 0x03; *out++ = (in[0] >> 2) & 0x03; *out++ = (in[0] >> 4) & 0x03; ... *out++ = (in[1] >> 6) & 0x03; } 14
  • 15. vpacker  –  内部構造 •  復元処理の動作概要   2-byteのデータに固定長2-bitで8個の整数が格納 ディスクリプタ部(desc) 圧縮データ部(in) 1-byteのデータに固定長1-bitで8個の整数が格納 while (1) { switch (*desc++) { case 1-bitで8個の整数を展開: unpack1_8(in, out); break; case 2-bitで8個の整数を展開: unpack2_8(in, out); break; ... } -  VMのインタプリタ的な処理の流れ } -  descは1-byteのため最大256分岐(分岐数は設計による) 15
  • 16. vpacker  –  内部構造 •  LLVM-­‐JITを用いてwhile-­‐switchを軽量化   –  共通する復元処理をまとめることでjmp命令を除去   ディスクリプタ部(desc) 圧縮データ部(in) 「前提条件」より大半の復元処理は 一部の関数に集中 while (1) { switch (*desc++) { case 1-bitで8個の整数を展開: unpack1_8(in, out); break; case 2-bitで8個の整数を展開: unpack2_8(in, out); break; ... } } 16
  • 17. vpacker  –  内部構造 •  呼び出しが集中している関数を高速化   –  基本はSIMDを利用したデータ並列性の向上   ディスクリプタ部(desc) 圧縮データ部(in) 呼び出しが集中している関数を高速化 while (1) { switch (*desc++) { case 1-bitで8個の整数を展開: unpack1_8(in, out); break; case 2-bitで8個の整数を展開: unpack2_8(in, out); break; ... } } 17
  • 18. gcc(v4.8)の自動ベクトル化 •  この関数*1ってどんな機械語に変換されるの?   –  処理に依存関係が無く,ベクトル化しやすそうな印象   void unpack1(const char *in, uint32_t *out, int n) { for (int i = 0; i < n; i++) { *out++ = in[0] & 0x01; *out++ = (in[0] >> 1) & 0x01; *out++ = (in[0] >> 2) & 0x01; ... *out++ = (in[0] >> 7) & 0x01; } } *1 現実に即して,ループ回数(n)を指定できるように変更しました 18
  • 19. gcc(v4.8)の自動ベクトル化 •  この関数ってどんな機械語に変換されるの?   –  処理に依存関係が無く,ベクトル化しやすそうな印象   void unpack1(const char *in, uint32_t *out, int n) { for (int i = 0; i < n; i++) { *out++ = in[0] & 0x01; *out++ = (in[0] >> 1) & 0x01; *out++ = (in[0] >> 2) & 0x01; ... *out++ = (in[0] >> 7) & 0x01; } } 重要) コンパイルする前に自動ベクトル化されやすいように前処理 19
  • 20. gcc(v4.8)の自動ベクトル化 •  この関数ってどんな機械語に変換されるの?   –  処理に依存関係が無く,ベクトル化しやすそうな印象   void unpack1(const char *in, uint32_t *out, int n) { for (int i = 0; i < n; i++) { for (int j = 0; j < 8; j++) *out++ = (*in >> j) & 0x01; in++; } } gccの場合、SLP(Superword-Level Parallelism)による最適化より Loop Vectorizerに任せたほうが良いらしいです 20
  • 21. gcc(v4.8)の自動ベクトル化 •  この関数ってどんな機械語に変換されるの?   –  処理に依存関係が無く,ベクトル化しやすそうな印象   void unpack1(const char * __restrict__ in, uint32_t * __restrict__ out, int n) { for (int i = 0; i < n; i++) { for (int j = 0; j < 8; j++) *out++ = (*in >> j) & 0x01; in++; } } __restrict__を付与してin/outを呼び出し側で16Bにアライメント 21
  • 22. gcc(v4.8)の自動ベクトル化 •  一部だけ抜粋  &  並び替え(’gcc  -­‐O3’)   movdqu (%r9), %xmm1 // in - %xmm1 pxor %xmm2, %xmm2 pcmpgtb %xmm1, %xmm2 movdqa %xmm1, %xmm3 punpckhbw %xmm2, %xmm1 punpcklbw %xmm2, %xmm3       pxor %xmm2, %xmm2 movdqa %xmm3, %xmm4 pcmpgtw %xmm3, %xmm2 punpcklwd %xmm2, %xmm4 movdqa %xmm4, %xmm5 pand %xmm0, %xmm5 // %xmm1=[0x01, 0x01, 0x01, 0x01] .... 22
  • 23. gcc(v4.8)の自動ベクトル化 •  一部だけ抜粋    並び替え(’gcc  -­‐O3’)   movdqu (%r9), %xmm1 // in - %xmm1 pxor %xmm2, %xmm2 pcmpgtb %xmm1, %xmm2 movdqa %xmm1, %xmm3 punpckhbw %xmm2, %xmm1 punpcklbw %xmm2, %xmm3 バイトからワードに符号拡張       pxor %xmm2, %xmm2 movdqa %xmm3, %xmm4 pcmpgtw %xmm3, %xmm2 punpcklwd %xmm2, %xmm4 ワードからダブルワードに符号拡張 movdqa %xmm4, %xmm5 pand %xmm0, %xmm5 // %xmm1=[0x01, 0x01, 0x01, 0x01] .... 0x01でマスクして展開処理完了 23
  • 24. gcc(v4.8)の自動ベクトル化 •  一部だけ抜粋    並び替え(’gcc  -­‐O3’)   movdqu (%r9), %xmm1 // in - %xmm1 pxor %xmm2, %xmm2 pcmpgtb %xmm1, %xmm2 movdqa %xmm1, %xmm3 punpckhbw %xmm2, %xmm1 punpcklbw %xmm2, %xmm3 バイトからワードに符号拡張       pxor %xmm2, %xmm2 movdqa %xmm3, %xmm4 pcmpgtw %xmm3, %xmm2 punpcklwd %xmm2, %xmm4 ワードからダブルワードに符号拡張 ‘n 15’で分岐させてLoopを全てinline化するアグレッシブな最適化 movdqa %xmm4, %xmm5 →’n = 15’はベクトル化されていないパスに分岐 pand %xmm0, %xmm5 // %xmm1=[0x01, 0x01, 0x01, 0x01] .... 0x01でマスクして展開処理完了 24
  • 26. clangと自動ベクトル化 •  LLVM上に実装されたC/C++用フロントエンド   –  hCp://clang.llvm.org/index.html   •  Auto-­‐VectorizaQon  in  LLVM   –  hCp://llvm.org/docs/Vectorizers.html   •  Linpackを用いた性能評価   –  with  loop  vectorizaQon  at  -­‐O3  running  on  a  Sandybridge   自動ベクトル化の有無で 性能差が3倍程度! 26
  • 27. clangにおける2種類のVectorizer •  Basic-­‐Block(BB)  Vectorizer  –  SLP  in  gcc     –  v3.1で”  -­‐mllvm  –vectorize”として導入   –  最適化の対象が「Basic  Block」   –  歴史的に実装されたのはコチラが先   •  Loop  Vectorizer   –  v3.2でようやく”  -­‐mllvm  –vectorize-­‐loops”として導入   –  「Unroll+BB  Vectorizer」にLoop間依存解析を加えたもの   –  自動ベクトル化の制約(v3.2のReleaseNotesより)   •  Loop枚のカウントは”1”のみ   •  InducQon変数は一番内側のLoopのみ使用可能   27
  • 28. clangの自動ベクトル化パラメータ •  clang-­‐v3.2を利用(2013/3/30現在最新)   –  デフォルトで自動ベクトル化は全てOFF   –  v3.3からLoop  Vectorizerはデフォルトに     •  -­‐mllvm  –vectorize,  -­‐mllvm  –vectorize-­‐loops   –  -­‐O2/-­‐O3との併用が必要   –  -­‐Osはコード増加が発生しない場合に適用   •  -­‐mllvm  –bb-­‐vectorize-­‐aligned-­‐only   –  アラインされたstore/loadのみを最適化に使用   •  -­‐mllvm  –force-­‐vector-­‐width=X   –  最適化で使用するベクトル要素数をXで指定   28
  • 29. その他の補助パラメータ •  -­‐mllvm  –unroll-­‐allow-­‐parQal   –  Loop内の部分的なUnrollを可能に   •  -­‐mllvm  –unroll-­‐runQme   –  実行時にLoopを数えてUnroll可能に   •  -­‐funsafe-­‐math-­‐opQmizaQons,  -­‐ffast-­‐math   –  浮動小数点演算にIEEE/ISO仕様外の最適化を適用   •  他の関連するパラメータは以下の資料が詳しい   –  Auto-­‐vectorizaQon  with  LLVM   –  hCp://llvm.org/devmtg/2012-­‐04-­‐12/Slides/Hal_Finkel.pdf     29
  • 30. WriQng  Vectorizer-­‐Friendly  Code  in  clang     •  example.1#   –  clang  -­‐O3  -­‐mllvm  -­‐vectorize-­‐loops     void test1(float * __restrict__ a, float * __restrict__ b, int n) { for (int i = 0; i n; i++) a[i] += b[i]; } 30
  • 31. WriQng  Vectorizer-­‐Friendly  Code  in  clang     •  example.1#   –  clang  -­‐O3  -­‐mllvm  -­‐vectorize-­‐loops     %rdiと%rsiは16Bに揃えてあるのに .LBB0_2: なぜかmovapsに変換されない? movups 16(%rdi,%rax,4), %xmm1 movups 16(%rsi,%rax,4), %xmm0 addps %xmm1, %xmm0 movups (%rdi,%rax,4), %xmm1 movups (%rsi,%rax,4), %xmm2 movups %xmm0, 16(%rdi,%rax,4) addps %xmm1, %xmm2 movups %xmm2, (%rdi,%rax,4) addq $8, %rax cmpq %rax, %rcx jne .LBB0_2 31
  • 32. WriQng  Vectorizer-­‐Friendly  Code  in  clang     •  example.2#   –  clang  -­‐O3  -­‐mllvm  -­‐vectorize-­‐loops     void test2(float * __restrict__ a, float * __restrict__ b, int n) { for (int i = 0; i n; i += 2) a[i] += b[i]; } 32
  • 33. WriQng  Vectorizer-­‐Friendly  Code  in  clang     •  example.2#   –  clang  -­‐O3  -­‐mllvm  -­‐vectorize-­‐loops     .LBB0_2: movss (%rsi,%rax,4), %xmm0 addss (%rdi,%rax,4), %xmm0 movss %xmm0, (%rdi,%rax,4) addq $2, %rax cmpl %edx, %eax jl .LBB0_2 33
  • 34. WriQng  Vectorizer-­‐Friendly  Code  in  clang     •  example.3#   –  clang  -­‐O3  -­‐mllvm  -­‐vectorize-­‐loops     void test3(float * __restrict__ a, float * __restrict__ b, int n) { for (int i = 0; i n; i += 1) { for (int j = 0; j SIZE; j++) a[i * SIZE + j] += b[i * SIZE + j]; } } 34
  • 35. WriQng  Vectorizer-­‐Friendly  Code  in  clang     •  example.3#   –  clang  -­‐O3  -­‐mllvm  -­‐vectorize-­‐loops     .LBB1_22: # = The Inner Loop movups (%rbx), %xmm2 movups 16(%rbx), %xmm1 movups (%rax), %xmm0 movups 16(%rax), %xmm3 addps %xmm2, %xmm0 addps %xmm1, %xmm3 movups %xmm3, 16(%rbx) movups %xmm0, (%rbx) addq $32, %rbx addq $32, %rax addq $-8, %rdi jne .LBB1_22 35
  • 36. WriQng  Vectorizer-­‐Friendly  Code  in  clang     •  example.4#   –  clang  -­‐O3  -­‐mllvm  -­‐vectorize-­‐loops     float test4(float * __restrict__ a, int n) { float S = 0.0; for (int i = 0; i n; i += 1) S += a[i]; return S; } 36
  • 37. WriQng  Vectorizer-­‐Friendly  Code  in  clang     •  example.4#   –  clang  -­‐O3  -­‐mllvm  -­‐vectorize-­‐loops     .LBB0_1: addss (%rdi), %xmm0 addq $4, %rdi decl %esi jne .LBB0_1 浮動小数点演算は結合則が成り立たないため、こういう命令列に →clangにも’-ffast-math’があるが、出力する命令は同じだった 37
  • 38. WriQng  Vectorizer-­‐Friendly  Code  in  clang     •  example.4#   –  gcc  -­‐O3  -­‐ffast-­‐math     .L33: addps (%rax), %xmm0 addq $16, %rax cmpq %rdx, %rax jne .L33 movaps %xmm0, %xmm1 movhlps %xmm0, %xmm1 addps %xmm0, %xmm1 movaps %xmm1, %xmm0 shufps $85, %xmm1, %xmm0 addps %xmm1, %xmm0 unpcklps %xmm0, %xmm0 38
  • 39. WriQng  Vectorizer-­‐Friendly  Code  in  clang     •  example.4#   –  gcc  -­‐O3  -­‐ffast-­‐math   ベクトル加算して   .L33: addps (%rax), %xmm0 addq $16, %rax cmpq %rdx, %rax jne .L33 水平加算 movaps %xmm0, %xmm1 movhlps %xmm0, %xmm1 addps %xmm0, %xmm1 movaps %xmm1, %xmm0 shufps $85, %xmm1, %xmm0 addps %xmm1, %xmm0 unpcklps %xmm0, %xmm0 39
  • 41. clangが出力する「unpack1」 •  一部だけ抜粋(’  clang  -­‐S  -­‐O3  -­‐mllvm  -­‐vectorize’)   movsbl (%rdi), %eax # *in - %eax movd %eax, %xmm0 pshufd $0, %xmm0, %xmm4 pshufd $68, %xmm4, %xmm3 pand %xmm8, %xmm4 movl %eax, %ecx ... shrq $2, %r10 movd %r10, %xmm0 punpcklqdq %xmm7, %xmm0 pand 人類には早すぎる難解なアセンブリが出力された・・・ %xmm1, %xmm0 pshufd →nの値でunrollはしないgccに比べてコンサバな最適化 $-128, %xmm0, %xmm7 movss %xmm6, %xmm7 movlhps %xmm7, %xmm5 shufps $-30, %xmm7, %xmm5 movups %xmm5, (%rsi) # %xmm5 - dst 41
  • 42. gcc-­‐4.8  vs  clang-­‐3.2   •  「unapack1」の性能比較   •  Intel  Core  i5-­‐3427@1.8GHzを使用   n=15 n=16 n=32 n=64 gcc 0.051us 0.040us 0.073us 0.152us clang 0.105us 0.110us 0.224us 0.446us raQo x2.1 x2.7 x3.1 x3.0 ベクトル化された状態で約3倍の性能差 42
  • 44. 本日のまとめ •  clang-­‐v3.2の自動ベクトル化の性能調査   –  基本的なものは自動的にベクトル化される   –  処理が複雑になるとgccに対して2~3倍程度の性能差も   •  ‘Vectorizer-­‐Friendly’はまだまだ重要   –  完全にコンパイラ任せ,というわけには現在いかない   –  256-­‐bit,  512-­‐bit,  ...とベクトル長が増えると性能差は拡大       44
  • 45. 本日のまとめ •  自動ベクトル化のためのコード規約        1.  ポインタのエイリアスは避ける             ・必要な個所では__restrict__を付ける          2.  ベクトル長の境界に合わせる                  ・__builQn_assume_aligned(X),  __aCribute__((aligned(X))の活用          3.  Loop内の手作業のinline化は避ける                ・Loop  Vectorizerに任せたほうが賢い       45