wiki:CALプログラミング(3)

Version 7 (modified by nakasato, 16 years ago) (diff)

--

  • 何か役立つ計算をおこなうためには、ループ処理が必須となる。CALでループ処理を実装してみよう。
  • /home/nakasato/CALTEST3"にループを使った計算例のプログラムを置いたので、自分のディレクトリにコピーして実行すること。
    gpu1[~/CALTEST3] ./hellocal
    55.000000 55.000000 55.000000 55.000000 55.000000 55.000000 55.000000 55.000000
    55.000000 55.000000 55.000000 55.000000 55.000000 55.000000 55.000000 55.000000
    
    Press enter to exit...
    
  • このプログラムは、1から10までの合計を計算するプログラムである。
  • なお、このプログラムから、kernelプログラムは別ファイルとして処理している。"hellocal.cpp"の34-51行にて、"prog.il"というファイルを読み込んでいる。kernelプログラムのみに変更を加える場合には、このファイルを変更するだけでよくて、再度makeする必要はない。
  • "hellocal.cpp"の本体部分は、これまでのプログラムとほとんど変わりがない。入出力用の配列を2次元から1次元としたことが大きな違いである。69-70行で、"calResAllocLocal1D()"によって1次元のメモリを確保している。この入力用のメモリには、78-84行にて1からnx(=256)の数字を代入している。
  • 計算domainは(0, 0, 256, 1)としている(109行)ので、256個の論理プロセッサにて"prog.il"が実行される。
  • kernelプログラムは、前と比べるとかなり変更がある。重要な変更点は:
    1. "dcl_literal"による定数値の宣言と利用
    2. "whileloop"によるループ処理の記述
    3. データを読み込むポインタの更新

以下、個々の点について詳しく説明する。

  • 定数について。初級のプログラムでは、浮動小数点整数をホストプログラムから転送していたが、CALでは定数値を直接プログラム中で利用することもできる。今回のプログラムでは"l0"と"l1"という定数値が5-6行で定義されている。
    dcl_literal 変数名, xの値, yの値, zの値, wの値
    
    というように宣言する。4要素を持つ変数であることに注意すること。整数を書けばそのままであり、"0xXX"とすれば16進数になるし、小数点が含まれる数は浮動小数点として扱われる。5-6行での宣言により、CAL上では以下のような定数として、"l0"と"l1"を利用できる。
    l0.x = 0.0f, l0.y = 0.0f, l0.z = 1.0f, l0.w = 0.0f
    l1.x = 0, l1.y = 0, l1.z = 1, l1.w = 10
    
    "l0"は、8行において、"r1.xy"への代入で利用されている。結果として
    r1.x = 0.0, r1.y = 0.0
    
    となる。"l1"も同様に使われている。実際には、これらの数字には以下のような意味がある:
l0.xとl0.y データの読み込みのポインタ初期値
l0.z そのポインタのインクリメント用
l1.x ループカウンタの初期値
l1.z   ループカウンタのインクリメント用

これらはループ処理とデータの読み込みに利用される。詳細は以下で説明する。

  • ループについて。CALでのループの実現には、色々な方法があるが、ここでは"whileloop"文を利用する。これは、"whileloop"と"endloop"に挟まれた命令列を永久に実行するという命令文である。よって、無限ループを終わらせる処理を自前で書く必要がある。必要な部分だけを抜き出すと以下のようなCALプログラムがループのひな形となる:
    whileloop
      ige r2.x, r4.x, r4.w
      break_logicalnz r2.x
      iadd r4.x, r4.x, r4.z
    endloop
    
    ここで、"r4.x"がループカウンタとして、"r4.w"をループの上限値として使っている。これはC言語で書くと以下のような処理に相当する:
    while(1) {
      if (r4.x >= r4.w) break;
      r4.x = r4.x + 1;
    }
    
  • "ige"の行は、"r4.x"と"r4.w"の大小を比較して、"r4.x >= r4.w"が成り立っているならば、"r2.x"にTRUEがセットされる(詳しくはil.pdfの43ページを参照のこと。以下同様)。
  • "break_logicalnz r2.x"は、"r2.x"が0でないならば、今のループを終了する。TRUEは0ではないので、"ige"でTRUEがセットされていたら、このループが終了する。この2命令を合わせて、C言語のほうのif文に相当することになる。
  • "iadd"は、単純に整数の加算である。"r4.z"は"1"として初期化されているので、"r4.x"をインクリメントすることになる。

Attachments (1)

Download all attachments as: .zip