\documentclass[12pt]{jarticle}

\usepackage{graphicx}

% \oddsidemargin -10mm
% \evensidemargin -10mm
% \textwidth 180mm

\oddsidemargin 0mm
\evensidemargin 0mm
\topmargin -10mm
\textwidth 160mm
\textheight 230mm

\newcommand{\Vec}[1]{\mbox{$\vec{#1}$}}

\newcommand{\Section}[1]{\section{\textmd{\textgt{\textsf{#1}}}}}
\newcommand{\Subsection}[1]{\subsection{\textmd{\textgt{\textsf{#1}}}}}
\newcommand{\Subsubsection}[1]{\subsubsection{\textmd{\textgt{\textsf{#1}}}}}

% #1:width(mm), #2:.eps, #3:caption

\newcommand{\FigureL}[3]{
\vspace*{7mm}
\begin{minipage}{140mm}
\includegraphics[width= #1 mm]{#2}\\
{#3}\\[5mm]
\end{minipage}
}
\newcommand{\Figure}[3]{
\begin{center}
\FigureL{#1}{#2}{#3}
\end{center}
}

\newcounter{bibno}
\newcommand{\mycite}[1]{[\ref{bib:#1}]}
\newcommand{\mybibitem}[2]{
  \refstepcounter{bibno}
  \label{bib:#1}
  \noindent
  [\thebibno]
  \begin{minipage}[t]{150mm}
  #2
  \end{minipage}
  \vskip 5mm
}

\begin{document}

\gtfamily
\sffamily

\thispagestyle{empty}

% \mcfamily
% \rmfamily

\vspace*{40mm}
\begin{center}
{\Huge Goose ソフトウェアパッケージ\\[3mm]
ユーザガイド}\\[10mm]

\vspace*{5mm}
{\LARGE for}
\begin{minipage}[t]{50mm}
\vspace*{-10mm}
\includegraphics[width=50mm]{gooselogo.eps}
\end{minipage}
{\LARGE version 1.0.1$\alpha$}\\

\vspace*{10mm}
{\large 最終更新 : 2009 年 9 月 28 日
}
\end{center}

\bigskip

\vfill

%
\hfill
\begin{minipage}{80mm}
    {\large
      \includegraphics[width=70mm]{kfcrlogo.eps}\\[3mm]
      ~~株式会社 K \& F Computing Research\\
      ~~E-mail: support@kfcr.jp
    }
\end{minipage}

\clearpage

\vspace*{-3mm}
\tableofcontents

\clearpage

\Section{本文書の概要}

この文書では Goose ソフトウェアパッケージの使用方法を説明します。
%
Goose は株式会社 K\&F Computing Research 開発の、SIMD 型計算機向けソフ
トウェア開発環境です。C 言語などの高級言語で記述された PC 上で動作する
プログラムを、ソースコードへの変更を極力抑えたまま、SIMD 型ハードウェア
アクセラレータ上で動作させることを目的としています。現段階 (version
1.0.1$\alpha$) では、高級言語として C 言語を、ハードウェアアクセラレー
タとして当社 GRAPE-DR をサポートしています。近日中に Fortran、GPU
(AMD, NVIDIA)、SSE テクノロジ、GRAPE-7 への対応を予定しています。

Goose はあえて高級言語の言語仕様を完全にはサポートしない、ドメイン特
化 (domain specific) 型の開発環境です。SIMD 型アクセラレータ上での実行
に適した文法記述のみを処理し、それ以外の記述は通常のコンパイラ (gcc 等)
へ渡して PC 向けにコンパイルします。この切り分けによって、PC 上で動作す
る既存のプログラムをアクセラレータへ移植する際に必要となるソースコード
の変更を、最小限に抑えられます。

以降、
%
第 \ref{sec:install} 章では Goose ソフトウェアパッケージ (以降
「本パッケージ」と呼びます) のインストール方法を説明します。
%
第 \ref{sec:basics} 章では基本的な使用方法を、具体例を用いたチュー
トリアル形式で説明します。
%
第 \ref{sec:pragma} 章では Goose 疑似命令の詳細を説明します。
%
第 \ref{sec:cgrammar} 章では Goose がサポートする C 言語記述について説明します。
%
第 \ref{sec:advanced} 章では Goose コンパイラやハードウェアアクセラレー
タの詳細について説明します。

なお以降では、本パッケージのルートディレクトリ ({\tt /{\it パッケージを
    展開したディレクトリ}/goosepkg{\it バージョン番号}/}) を {\tt
  \$goosepkg} と表記します。

\clearpage
\Section{インストール}\label{sec:install}

\Subsection{準備}

本パッケージは以下のソフトウェアに依存しています。
インストール作業の前に、これらの動作環境を整えて下さい。

\begin{itemize}

\item C コンパイラ (gcc version 4.1.0 以降を推奨)\\
{\tt http://gcc.gnu.org/}

\item Ruby (version 1.8.5 以降を推奨)\\
{\tt http://www.ruby-lang.org/}

\item Perl (version 5.8.8 以降を推奨)\\
{\tt http://www.perl.com/}

% \item Google Ctemplate 共有ライブラリ (version 0.9 以降を推奨)\\
% {\tt http://code.google.com/p/google-ctemplate/}

\item LSUMP (中間言語コンパイラ。会津大学中里直人氏開発)\\
{\tt http://www.kfcr.jp/goose.html}

\item VSM (GRAPE-DR 用アセンブラ。国立天文台牧野淳一郎氏開発)\\
{\tt http://www.kfcr.jp/goose.html}

\item GRAPE Software Package (version 1.1.0 以降を推奨)\\
{\tt http://www.kfcr.jp/goose.html}

\end{itemize}
%

\Subsection{パッケージの展開と環境変数の設定}

ソフトウェアパッケージ {\tt goosepkg{\it nnn}.tar.gz} を展開してくださ
い ({\it nnn} はバージョン番号)。パッケージには以下のファイルが含まれて
います:

\vspace*{3mm}
\begin{tabular}{ll}
  00readme-j                & パッケージ概要。\\
  00readme                  & パッケージ概要英語版。\\
  doc/                      & ユーザガイド、その他の文書。\\
  scripts/                  & パッケージ管理ユーティリティ。\\
  bin/goosecc               & Goose 疑似命令を埋め込んだ C 言語のソースコードから、\\
                            & ハードウェアアクセラレータ用の実行ファイルを生成するツール。\\
  include/                  & ヘッダファイル。\\
  lib/                      & ライブラリ。\\
  singutil/                 & GRAPE-DR 制御用ライブラリ。\\
  sample/                   & Goose でコンパイル可能なアプリケーションプログラムの例。\\
  init/                     & sample/ 内のプログラムが使用するデータファイル。\\
  misc/                     & 環境変数設定のサンプル、init/ 内のデータを生成するプログラム等。\\
\end{tabular}\\

\vspace*{3mm}
以下の環境変数を設定してください。

\vspace*{3mm}
\begin{tabular}{ll}
  LSUMPPATH         & : LSUMP  のインストールされているパス。\\
  VSMPATH           & : VSM のインストールされているパス。\\
  GRAPEPKGPATH      & : GRAPE Software Package のインストールされているパス。\\
\end{tabular}\\

\vspace*{5mm}
\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
例 sh を使用する場合:
kawai@localhost>export LSUMPPATH=/home/kawai/src/lsumppkg
kawai@localhost>export VSMPATH=/home/kawai/src/vsm
kawai@localhost>export GRAPEPKGPATH=/home/kawai/src/grapepkg

例 csh を使用する場合:
kawai@localhost>setenv LSUMPPATH /home/kawai/src/lsumppkg
kawai@localhost>setenv VSMPATH /home/kawai/src/vsm
kawai@localhost>setenv GRAPEPKGPATH /home/kawai/src/grapepkg
\end{verbatim}
\end{minipage}\\[3mm]

\noindent
以上の環境変数設定を行う sh 用、csh 用スクリプトのサンプルが、\\[-3mm]

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
$goosepkg/misc/rc/genv.sh
$goosepkg/misc/rc/genv.csh
\end{verbatim}
\end{minipage}\\

\noindent
に用意されています。自身の環境に合わせて修正のうえお使い下さい。
また、以下の環境変数も使用できますが、必ずしも設定する必要はありません。

\vspace*{3mm}
\begin{tabular}{ll}
  CC         & : 使用する C コンパイラを指定します。\\
  CFLAGS     & : C コンパイラへ渡す引数を指定します。\\
\end{tabular}\\
%

\Subsection{インストールスクリプトの実行と動作チェック}

\vspace*{5mm}
ディレクトリ {\tt \$goosepkg} へ移動し、コマンド {\tt
  \$goosepkg/script/install} を実行してください。各種ライブラリや、
サンプルコードの実行に必要なデータなどが生成されます。\\

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
kawai@localhost>./script/install 
cc -O3 -c singutil.c -I/home/kawai/grapepkg/include \
-L/home/kawai/grapepkg/lib -fopenmp
ar -r libsing.a singutil.o
ar: creating libsing.a
ranlib libsing.a
cc    -c -o mkdist.o mkdist.c
cc    -c -o util.o util.c
cc  -o mkdist mkdist.o util.o -lm
n: 1024  output file: pl1k
distribution: Plummer

...

done
\end{verbatim}
\end{minipage}\\[5mm]

\noindent
以上でインストールは完了です。インストールが正常に行われていれば、本パッ
ケージ付属の各種のサンプルプログラムをコンパイルできるはずです。例えば
重力多体シミュレーションを行うプログラム {\tt s9} をコンパイルするには、
ディレクトリ {\tt \$goosepkg/sample/s9/} へ移動し、コマンド {\tt make
 all} を実行します。\\

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
kawai@localhost>pwd
/home/kawai/src/goosepkg/sample/s9
kawai@localhost>make all
../../bin/goosecc -v3 --goose-arch gdr -o s9 sticky9.c  -lm -O3
$LSUMPPATH                           : /home/kawai/src/lsump
$VSMPATH                             : /home/kawai/src/vsm
$GRAPEPKGPATH                        : /home/kawai/src/grapepkg

...

=========================================
 executable file generated successfully.
=========================================
cc -O3 sticky9.c -o s9_host -lm  -fopenmp
kawai@localhost>ls
Makefile  goosetmp  inputpara9  s9  s9_host  sticky9.c
\end{verbatim}
\end{minipage}\\[5mm]

\noindent
コンパイルが正常に完了すると、二つの実行ファイル {\tt s9} および {\tt
  s9\_host} が生成されます。前者はハードウェアアクセラレータを使用して
計算を行うプログラム、後者はホスト計算機だけで計算を行うプログラムです。

\clearpage
\Section{基本的な使用方法}\label{sec:basics}

\Subsection{Goose の扱うプログラム記述}\label{sec:target}

Goose は C 言語などの高級言語で記述されたプログラムをハードウェアアクセ
ラレータ向けのコードにコンパイルしますが、すべての記述をコンパイル対象
とするわけではありません。SIMD 型アクセラレータ上での実行に適した記述の
みを処理の対象とします。それ以外の記述は通常のコンパイラ (gcc 等) へ渡し
て、ホスト計算機向けにコンパイルします。
%
ここでいう「SIMD 型アクセラレータ上での実行に適した記述」とは、
%
\begin{itemize}

\item[(a)] 並列性が高く、

\item[(b)] 外部 (プロセッサチップ外部のメモリやホスト計算機) との通信量
    が計算量に対して相対的に少ない、

\end{itemize}
%
という条件を満たす計算に関する記述を意味します。

Goose が処理対象とするのは、計算結果 $\Vec{r_i}$ が入力パラメタ
$\Vec{x_i}$ を用いて
%
\begin{equation}
  \Vec{r_i}  =  f(\Vec{x_i}) \label{eq:simd}
\end{equation}
%
という形に表せ、$\Vec{r_i}$ を求める計算を異なる $i$ に対して並列に行え
るタイプの計算です。そのような計算のなかでも特に、
%
\begin{equation}
  \Vec{r_i} = \sum_j f(\Vec{x_i}, \Vec{y_j}) \label{eq:sumj}
\end{equation}
%
という形に表せるものの処理に最適化されています。
%
式(\ref{eq:simd}) の形に表せる計算は、$i$ の総数が充分に大きけれ
ば 「(a) 並列度が高」いという条件を満たします。さらにそれが
式(\ref{eq:sumj}) の形に表せる場合には、「(b) 外部との通信量が計算量に
対して相対的に少ない」という条件をも満たします。これは多数の $i$ に対す
る計算を、同一の $\Vec{y_j}$ を使用して行えるからです。そのため $i$ ご
とに別個の $\Vec{y_i}$ が必要な場合に比べ、通信量が少なくてすみます。
%
式(\ref{eq:simd}) の形には表せるが、式(\ref{eq:sumj}) の形には表せない
タイプの計算も扱えますが、そのような計算に対しては、ハードウェアアクセ
ラレータの持つ演算能力を充分に活かしきれない場合があります。

なお、式 (\ref{eq:simd})、式(\ref{eq:sumj}) における $i$ や $j$ に、具
体的にどの程度の並列度が必要とされるかは、ハードウェアアクセラレータの
アーキテクチャに依存します。GRAPE-DR で式 (\ref{eq:sumj}) 型の計算を行う
場合には、$i$ の並列度が 128 以上、$j$ の並列度が 16 以上あれば、ハード
ウェアの持つすべてのプロセッサ要素を利用して計算を行えます (節
\ref{sec:gdr} 参照)。並列度がそれよりも低い場合には、一部のプロセッサ要
素は計算に利用されず、遊んでしまうことになります。

\vspace*{5mm}
\hspace*{5mm}
\begin{minipage}{150mm}
例 : 多数の質点間に働く重力相互作用の計算は、式 (\ref{eq:sumj}) の形で表現できます。
質点 $i$ に他のすべての質点から働く重力の総和 $\Vec{f_i}$ は、
質点の空間座標 $\Vec{x_i}$ と質量 $m_i$ を用いて下式で表せます ($G$ は万有引力定数)。
%
\begin{equation}
  \Vec{f_i} = \sum_{j \ne i} \frac{G m_i m_j (\Vec{x_j} - \Vec{x_i})}{|\Vec{x_j} - \Vec{x_i}|^3}
  \label{eq:gravity}
\end{equation}
%
\end{minipage}\\

C 言語を用いると、式 (\ref{eq:simd}) 型の計算は様々な記述で表現できます。
しかし簡単のため、Goose ではこの形式の計算を for 文によるループで表現し
た記述のみを扱います。また、式 (\ref{eq:sumj}) 型の場合は、入れ子になっ
た 2 重 for ループで表現した記述のみを扱います。他の方法、例え
ば while 文を用いた記述は、Goose の処理対象にはなりません。

\vspace*{5mm}
\hspace*{5mm}
\begin{minipage}{150mm}
例 : 式 (\ref{eq:gravity}) は for 文による 2 重ループで表現できます。
%
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
for (i = 0; i < n; i++) {
  for (j = 0; j < n; j++) {
    if (i != j) {
      dx[0] = x[j][0] - x[i][0];
      dx[1] = x[j][1] - x[i][1];
      dx[2] = x[j][2] - x[i][2];
      r2 = dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2];
      mmr3 = G * m[i] * m[j] / (sqrt(r2) * r2);
      f[i][0] += mmr3 * dx[0];
      f[i][1] += mmr3 * dx[1];
      f[i][2] += mmr3 * dx[2];
    }
  }
}
\end{verbatim}
%
\end{minipage}

\Subsection{プログラムの開発手順}

ユーザが直接使用するコマンドは、原則的には {\tt
  \$goosepkg/bin/goosecc} のみです。{\tt goosecc} は C 言語のソースコー
ドから、ハードウェアアクセラレータ用の実行ファイルを生成します。

ユーザは以下の手順でアプリケーションプログラムの開発を行います:

\begin{enumerate}

\item[(手順1)] アプリケーションプログラムを C 言語で記述し、ホスト計算
    機 (PC) 上で動作確認を行います。この際、SIMD 型アクセラレータでの実
    行に適していると予想される箇
    所 (節 \ref{sec:target} 参照) は、while 文や do while 文ではなく
    for 文を使用して記述します。

    計算結果が 2 重ループのカウンタ {\tt i, j} に関して対称な場合 (作用反
    作用則を満たす粒子間中心力など) には、その性質を利用して計算量を減
    らす工夫を行うことがあります (下記の例)。しかしこのような記述は
    Goose では扱えませんので避けて下さい。

\vspace*{5mm}
\hspace*{5mm}
\begin{minipage}{150mm}
例 : 作用反作用則を利用して式 (\ref{eq:gravity}) の計算量を減らす記述。Goose では扱えない。
%
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
for (i = 0; i < n; i++) {
  for (j = i+1; j < n; j++) {
    dx[0] = x[j][0] - x[i][0];
    dx[1] = x[j][1] - x[i][1];
    dx[2] = x[j][2] - x[i][2];
    r2 = dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2];
    mmr3 = G * m[i] * m[j] / (sqrt(r2) * r2);
    f[i][0] += mmr3 * dx[0];
    f[i][1] += mmr3 * dx[1];
    f[i][2] += mmr3 * dx[2];
    f[j][0] -= mmr3 * dx[0];
    f[j][1] -= mmr3 * dx[1];
    f[j][2] -= mmr3 * dx[2];
  }
}
\end{verbatim}
%
\end{minipage}

\item[(手順2)] 可能ならば、手順1で記述した for 文に OpenMP 疑似命令
    ({\tt \#pragma omp parallel for}) を付加し、スレッド並列化を行いま
    す。この過程は必須ではありませんが、並列動作時の演算結果の正しさや
    性能向上の程度を確認する手法として効果的です。OpenMP の使用法や詳細
    については {\tt http://openmp.org/} などを参照してください。

\item[(手順3)] 手順1で記述した for 文に、新たに Goose 疑似命令 ({\tt
      \#pragma goose parallel for}) を付加し、{\tt goosecc} を用いてコ
    ンパイルすると、実行ファイルが生成されます。この実行ファイルを実行
    すると、Goose 疑似命令を付加した for 文がハードウェアアクセラレータ
    上で実行されます。それ以外の部分はホスト計算機上で実行されます。

\end{enumerate}

\Subsection{チュートリアル1 -- 数値積分}\label{sec:tut1}

本節と次節では、Goose 疑似命令の記述方法とプログラムのコンパイル手順を、
具体例を用いて説明します。

\vspace*{3mm}
本節ではサンプルプログラムとして {\tt
  \$goosepkg/sample/midpoint/midpoint.c} を使用します。このプログラムは
中点法による数値積分で $\int_0^1 4 /(1+x^2) dx$ を計算します (解析解
は $\pi$)。このプログラムの中核は以下の for ループです。\\

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
  for(i=0;i<n;i++) {
    x = (i+0.5)*dx;
    sum += integrand(x)*dx;        
  }
\end{verbatim}
\end{minipage}

\vspace*{3mm}
\noindent
積分区間 $[0, 1]$ を {\tt n} 分割し、各区間における被積分関数の値と
{\tt dx} の積を求め、それを変数 {\tt sum} へ積算します。被積分関数
は C 言語の関数 {\tt integrand()} としてプログラム冒頭で定義されています。

\vspace*{3mm}
このプログラムを、通常の C コンパイラを用いてホスト計算機向け
にコンパイルしてみましょう。\\

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
kawai@localhost>cd $goosepkg/sample/midpoint/
kawai@localhost>cc midpoint.c -o midpoint_host
\end{verbatim}
\end{minipage}

\vspace*{3mm}
\noindent
生成された実行ファイル {\tt midpoint\_host} を実行すると、以下の出力が得られます。\\

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
kawai@localhost>./midpoint_host
n:16384  sum:3.14159265390022e+00  sum/M_PI-1.0:9.881305e-11
\end{verbatim}
\end{minipage}

\vspace*{5mm}
ホスト計算機上での動作を確認できたので、次はこのプログラムをハードウェ
アアクセラレータ向けにコンパイルすることを考えましょう。前述の for 文の
直前に、Goose 疑似命令 {\tt \#pragma goose parallel for} が付加され
ていることに着目してください (以降この疑似命令を「Goose for 疑似命令」と呼びます) 。\\

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
#pragma goose parallel for icnt(i) result(sum) ip(i) shared_ro(dx)
  for(i=0;i<n;i++) {
    x = (i+0.5)*dx;
    sum += integrand(x)*dx;        
  }
\end{verbatim}
\end{minipage}

\vspace*{3mm}
\noindent
プログラム内の、Goose for 疑似命令を付加した箇所が、ハードウェアアクセ
ラレータ上での実行対象となります。他の部分はホスト計算機上で実行されま
す。

\vspace*{3mm}
Goose for 疑似命令をもう少し詳しく見てゆきましょう。
疑似命令への引数として、{\tt icnt(i)} などが与えられています:

\begin{itemize}

\item 引数 {\tt icnt(i)} は、変数 {\tt i} を for 文のループカウンタとし
    て使用することを示しています。

\item 引数 {\tt result(sum)} は、変数 {\tt sum} の値を計算結果としてア
    クセラレータからホスト計算機へ回収する必要があることを示していま
    す。

\item 引数 {\tt ip(i)} は、計算の入力パラメタとして変数 {\tt i} の値を
    ホスト計算機からアクセラレータへ送信する必要があることを示していま
    す。

\item 引数 {\tt shared\_ro(dx)} も {\tt ip()} と同様に、変数 {\tt
      dx} の値をアクセラレータへ送信する必要があることを示しています。
    引数 {\tt ip()} との違いは、{\tt shared\_ro()} で指定した変数 {\tt
      dx} の値はループ内で不変であるのに対し、{\tt ip()} で指定した
    {\tt i} の値はカウンタ{\tt i} に依存してループ内で変化することで
    す。

\end{itemize}

\noindent
後述 (節 \ref{sec:iotype}) するように、実際にはこれらの引数すべてが必須
というわけではありません。しかし Goose の使い方に慣れるまでは、すべての
ループカウンタと、{\tt private} 型を除くすべての変数の「入出力
型」 (節 \ref{sec:iotype}) を明示することをお薦めします。

\vspace*{3mm}
次に被積分関数の定義に着目してください。\\

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
#pragma goose func
double integrand(double x)
{
  double s;
  s = 4.0/(1.0+x*x);
  return s;
}
\end{verbatim}
\end{minipage}

\vspace*{3mm}
\noindent
関数定義に Goose 疑似命令 {\tt \#pragma goose func} が付加されていま
す (以降この疑似命令を「Goose func 疑似命令」と呼びます)。この疑似命令
を付加すると、Goose for 疑似命令を付加したfor 文の内部から関数 {\tt
  integrand()} を呼び出せるようになります。なお、Goose func 疑似命令を
付加するためには、関数は引数を一つだけとり、なおかつ {\tt return} 文を
用いて明示的に返り値を返す必要があります。return 文の無い関数や、返り値
の型として {\tt void} 型を持つ関数は、Goose では使用できません。

\vspace*{3mm}
以上で Goose 疑似命令を理解できたので、実際にコンパイルを行いましょう。
コンパイルには {\tt \$goosepkg/bin/goosecc} を使用します。\\
ディレクトリ {\tt \$goosepkg/sample/midpoint/} 内で、以下のように
コマンドライン引数を与えて {\tt goosecc} を実行してください
({\tt goosecc} のコマンドライン引数詳細については節
\ref{sec:gooseccopt} を参照してください)。\\

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
kawai@localhost>../../bin/goosecc midpoint.c -o midpoint
========================
 processing midpoint.c.
========================
Info    : Goose::GforHandler : No j-loop found. The entire i-loop \
body is used as a kernel.
Info    : Goose::GforHandler : Recognized as an ip var : i
Info    : Goose::GforHandler : Recognized as a shared_ro var : dx
...
=========================================
 executable file generated successfully.
=========================================
\end{verbatim}
\end{minipage}

\vspace*{3mm}
\noindent
コンパイルに成功すると、実行ファイル {\tt midpoint} が生成されます。ハー
ドウェアアクセラレータを稼働させた状態で {\tt midpoint} を実行すると、
前述の Goose for 疑似命令を付加した for ループがアクセラレータ上で実行
されます。他の部分は {\tt midpoint\_host} と同様にホスト計算機上で実行
されます。実行の結果、{\tt midpoint\_host} と同様の出力が得られます。

\Subsection{チュートリアル2 -- 多粒子間重力相互作用}\label{sec:tut2}

本節で使用するサンプルプログラムは{\tt
  \$goosepkg/sample/gravity/gravity.c} です。このプログラムは多粒子系に
おいて、質点間の重力相互作用によって各質点が得る加速度 $a_i$ を計算しま
す。本来の重力相互作用は式 (\ref{eq:gravity}) の形で表現されますが、ここで
は万有引力定数を 1 にスケーリングし、また数値計算上の問題を回避するため
にソフトニングパラメタ $\epsilon$ を導入します。すると計算すべき式は
%
\begin{equation}
  \Vec{a_i} = \sum_{j \ne i} \frac{m_j (\Vec{x_j} - \Vec{x_i})}
{(|\Vec{x_j} - \Vec{x_i}|^2 + \epsilon^2)^{3/2}}
\end{equation}
%
と表されます。サンプルプログラム中の 2 重 for ループは
この式を表現しています。\\

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
#pragma goose parallel for icnt(i) jcnt(j) \
  ip(x[i][0..2]) jp(x[j][0..2],m[j]) result(a[i][0..2],pot[i])\
  precision ("double") 
    for(i=0;i<n;i++) {
      for(k=0;k<3;k++) a[i][k] = 0.0;
      pot[i] = 0.0;
      for(j=0;j<n;j++) {
        for(k=0;k<3;k++) dx[k] = x[j][k] - x[i][k];
        r2 = dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2] + eps2;
        rinv = rsqrt(r2);
        mrinv = m[j]*rinv;
        mr3inv = mrinv*rinv*rinv;
        for(k=0;k<3;k++) a[i][k] += mr3inv * dx[k];
        pot[i] += -mrinv;      
      }
    }
    get_cputime(&lt,&st);
    total_time += lt;
    for(i=0;i<n;i++) pot[i] += m[i]/sqrt(eps2);
\end{verbatim}
\end{minipage}

\vspace*{3mm}
\noindent
本サンプルのように計算対象が式 (\ref{eq:sumj}) の形式をとる場合には、プ
ログラム上では 2 重の for ループを用いて記述しま
す (節 \ref{sec:target} 参照)。プログラム内の、Goose for 疑似命令を付加
した 2 重ループが、ハードウェアアクセラレータ上での実行対象となります。
他の部分はホスト計算機上で実行されます。

\vspace*{3mm}
Goose for 疑似命令への引数として、以下のものが使用されています (一部は
節 \ref{sec:tut1} 説明したものも含みます)。

\begin{itemize}

\item 引数 {\tt icnt(i)} は、変数 {\tt i} を外側の for ループのカウンタ
    として使用することを示しています。同様に、引数 {\tt jcnt(j)} は変
    数 {\tt j} を外側の for ループのカウンタとして使用することを示して
    います。

\item 引数 {\tt ip(x[i][0..2])} は、計算の入力パラメタとして変数 {\tt
      x[i][0..2]} の値をホスト計算機からアクセラレータへ送信する必要が
    あることを示しています。ここで配列インデクス中の {\tt 0..2} は {\tt 0,
      1, 2} の 3 個のインデクスを表します。つまり {\tt
      x[i][0..2]} は{\tt x[i][0], x[i][1], x[i][2]} と同値です。この記
    法は Goose 疑似命令文中でのみ使用できます。

\item 引数 {\tt jp(x[j][0..2],m[j])} は、計算の入力パラメタとして変数
    {\tt x[j][0..2]} と {\tt m[j]} の値を、ホスト計算機からアクセラレー
    タへ送信する必要があることを示しています。引数 {\tt ip()} との違い
    は、{\tt jp()} で指定した変数の値は内側のループ内で変化するのに対
    し、{\tt ip()} で指定した変数の値は内側のループ内では不変であること
    です。

\item 引数 {\tt result(a[i][0..2],pot[i])} は、変数 {\tt
      a[i][0..2]} と {\tt pot[i]} の値を計算結果としてアクセラレータか
    らホスト計算機へ回収する必要があることを示しています。

\item 引数 {\tt precision("double")} は、変数の数値フォーマットとして
    64-bit 浮動小数点形式を用いることを示しています。C 言語での変数の型
    宣言は無視されます。指定が無い場合には 64-bit 浮動小数点形式を用い
    ます。指定できる数値フォーマットについては節 \ref{sec:foropt}を参照
    してください。

\end{itemize}

\vspace*{3mm}
以下の点に注意してください。

\begin{itemize}

\item Goose func 疑似命令を付加した関数と同名の関数が Gooseの組み込み
    関数としてあらかじめ用意されている場合には、関数の再定義は行われず
    に、組み込み関数が使用されます (節 \ref{sec:pragmafunc})。例えば
    {\tt rsqrt()} は組み込み関数として用意されているため、プログラム冒頭の定義:\\

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
double rsqrt(double r2)
{
  return 1.0/sqrt(r2);
}
\end{verbatim}
\end{minipage}

\vspace*{3mm}
\noindent
は使用されません。

\item 自己代入演算子 {\tt -=} は使用できません。{\tt +=} で代用してくだ
    さい。

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
例 : pot[i] += -mrinv
\end{verbatim}
\end{minipage}

\item 2 重 for ループのさらに内側にある for ループはアンロールされます。
    例えば\\[-3mm]

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
for(k=0;k<3;k++) dx[k] = x[j][k] - x[i][k];
\end{verbatim}
\end{minipage}

\vspace*{3mm}
という記述は、\\

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
dx[0] = x[j][0] - x[i][0];
dx[1] = x[j][1] - x[i][1];
dx[2] = x[j][2] - x[i][2];
\end{verbatim}
\end{minipage}

\vspace*{3mm}と同値です。なおループ範囲が有限でない for 文や、ループ範
囲がコンパイル時に確定しない for 文は、コンパイル時に警告メッセージが出
力され、無視されます (節 \ref{sec:cgrammarfor})。

\item プログラム中で数学関数 {\tt sqrt()} を使用しているため、コンパイ
    ルにはコマンドラインオプション {\tt -lm} が必要です。\\

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
kawai@localhost>cd $goosepkg/sample/gravity/
kawai@localhost>../../bin/goosecc gravity.c -o gravity -lm
\end{verbatim}
\end{minipage}

\vspace*{3mm}

\end{itemize}

\Subsection{サンプルプログラム}

ディレクトリ {\tt \$goosepkg}/sample/ 内に、{\tt goosecc} でコンパイル
可能なアプリケーションプログラムの記述例があります。Goose 疑似命令の使
い方などの参考にしてください。

\vspace*{3mm}
\begin{tabular}{ll}
\hline
\multicolumn{2}{l}{2重forループ (式(\ref{eq:sumj})型)}\\
\hline
  gravity/              & 重力相互作用を計算します\\
                        & (節 \ref{sec:tut2}のチュートリアルで使用)。\\[3mm]
  gravity\_cutoff/      & P${}^3$M 法向けカットオフの入った重力相互作用を\\
                        & 周期境界条件下で計算します。\\[3mm]
  hermite/              & 重力相互作用と、その時間微分を計算します。\\[3mm]
  tree/                 & Barnes-Hut ツリー法を用いて重力相互作用を計算します。\\[3mm]
  s9/                   & 重力多体シミュレーション を行います\\
                        & (leap-frog 公式、共通時間刻み)。\\[3mm]
  s8/                   & 重力多体シミュレーション を行います\\
                        & (4 次の Hermite 公式、独立時間刻み)。\\[3mm]
  vdw/                  & ファンデルワールス力を計算します\\
                        & (Lennard-Jones ポテンシャル)。\\[3mm]
  sph/                  & SPH 法における粒子への加速度を計算します\\
                        & (Spline カーネル、人工粘性無し)。\\[3mm]
\hline\\[3mm]

\hline
\multicolumn{2}{l}{1重forループ (式(\ref{eq:simd})型)}\\
\hline
  midpoint/             & 中点法を用いて $\int_0^1 4 /(1+x^2) dx$ を計算します\\
                        & (節 \ref{sec:tut1}のチュートリアルで使用)。\\[3mm]
  mesh1d/               & 1次元空間の格子点各点において、隣接する点の値との間で\\
                        & 重み付き平均をとります。\\[3mm]
\hline
\end{tabular}\\

\vspace*{3mm}
\noindent
各ディレクトリ内でコマンド {\tt make all} を実行すると、ハードウェアア
クセラレータ向けの実行ファイルが生成されます。アクセラレータを使用せず
にホスト計算機のみで計算を行う実行ファイルも、併せて生成されます。

\clearpage
\Section{Goose 疑似命令}\label{sec:pragma}

Goose の疑似命令は以下の 2 種類に大別されます:

\paragraph{Goose for 疑似命令}:
{\tt \#pragma goose parallel for [{\it optional-arguments}]}\\
for 文の直前に記述すると、その for 文をハードウェアアクセラレータ用のコードに置き換えます。

\paragraph{Goose func 疑似命令}:
{\tt \#pragma goose func}\\
関数定義の直前に記述すると、Goose for 疑似命令を付加した for 文の内部か
らその関数を呼び出せるようになります。

\vspace*{5mm}
\hspace*{5mm}
\begin{minipage}{150mm}
記法上の注意 :
Goose 疑似命令は 1 行で記述してください。複数行にまたがる場合には、
バックスラッシュを使用して改行コードをエスケープしてください。\\

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
  例 : #pragma goose \
         parallel for
\end{verbatim}
\end{minipage}
\end{minipage}

\Subsection{Goose for 疑似命令詳細}\label{sec:pragmafor}

Goose for 疑似命令は、その直後の for 文をハードウェアア
クセラレータ用のコードに置き換えます。典型的には、以下に示すよう
な 2 重for ループを置換対象としますが、1 重ループも置換できます。3 重以
上のループの場合には，内側のループはアンロールされます。\\

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
例 : #pragma goose parallel for
     for (i = 0; i < ni; i++) {      // 外側の 'for'。
       for (j = 0; j < nj; j++) {    // 内側の 'for'。
         for (k = 0; k < 3; k++) {   // この 'for' はアンロールされる。
           dx[k] = x[j][k] - x[i][k];
         }
         r2 = dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2] + eps2;
         rinv = rsqrt(r2);
         mf = m[j]*rinv*rinv*rinv;
         for (k = 0; k < 3; k++) {   // この 'for' はアンロールされる。
           a[i][k] += mf * dx[k];
         }
         p[i] -= m[j] * rinv;
       }
     }
\end{verbatim}
\end{minipage}\\[1mm]

\noindent
アクセラレータ上の計算に使用される変数の型はすべて double 型 (あるいは
後述の {\tt \#pragma goose parallel for precision} で指定した型) となり
ます。C 言語での型宣言は無視されます。

\Subsubsection{変数の入出力型}\label{sec:iotype}

Goose for 疑似命令 を付加した for ループ内で使用する変数
は、ハードウェアアクセラレータとホスト計算機との間で受渡しを行う必要が
あります。必要とされる受渡しの方法に応じて、各変数には「入出力型」とい
う属性が定義されます。\\

\noindent
{\bf 入出力型一覧}\\[3mm]
\begin{tabular}{ll}
\hline
型名 & 用法 \\
\hline
\hline
ip         & 計算の入力パラメタのうち、$i$ に依存する変数です (式 (\ref{eq:sumj}) の $\Vec{x_i}$)。\\
           & ホスト計算機からアクセラレータへ送信されます。\\
jp         & 計算の入力パラメタのうち、$j$ に依存する変数です (式 (\ref{eq:sumj}) の $\Vec{x_j}$)。\\
           & ホスト計算機からアクセラレータへ送信されます。\\
shared\_ro & 計算の入力パラメタのうち、$i$ や $j$ に依らない変数です。\\
           & ホスト計算機からアクセラレータへ送信されます。\\
private    & 計算中に一時的に使用される中間変数です。\\
           & アクセラレータ上だけで使用され、ホスト計算機へは回収されません。\\
result     & 計算結果です (式 (\ref{eq:sumj}) の $\Vec{r_i}$)。\\
           & アクセラレータからホスト計算機へ回収されます。\\
\hline
\end{tabular}

\vspace*{3mm}
\noindent
変数の入出力型は以下の規則に従って {\tt goosecc} により自動推論されます
が、後述 (節 \ref{sec:foropt}) のように Goose for 疑似命令への引数によっ
て明示的に指定することも可能です。

\vspace*{5mm}
\noindent
{\bf 入出力型の推論規則:}\\[3mm]
外側と内側の for ループのループカウンタを、それぞれ {\tt i}、{\tt j} とするとき、

\begin{itemize}

\item {\tt i} でインデクスされた変数は {\tt ip} 型と認識されます。ただ
    しその変数が左辺値として使用されている場合には、{\tt result} 型と認
    識されます。

\item {\tt j} でインデクスされた変数は {\tt jp} 型と認識されます。

\item 以上に該当しない変数のうち、左辺値として使用されているもの
    は、{\tt private} 型と認識されます。ただし Goose for 疑似命令への引
    数によって明示的に指定すると (節\ref{sec:foropt})、{\tt result} 型
    として認識させることが可能です。プログラム \\
    {\tt \$goosepkg/sample/midpoint/midpoint.c} 中の変数 {\tt sum} はそ
    のような使われかたをしています (節 \ref{sec:tut1} 参照)。

\item 右辺値としてしか使用されていない変数は、{\tt shared\_ro} 型と認識されます。

\end{itemize}


\clearpage
\Subsubsection{オプション引数}\label{sec:foropt}

Goose for 疑似命令 は、変数の入出力型指定を含む多くのオプション引数をと
ることができます。以下にオプションの一覧を示します。

\vspace*{5mm}
\noindent
\begin{minipage}{160mm}
{\bf オプション引数一覧:}\\[3mm]
\begin{tabular}{ll}
\hline
書式               & 機能 \\
\hline
\hline
{\tt icnt({\it var})}  &                 外側の for 文のループカウンタとして変数 {\it var} を指定します。\\
                       &                 指定がない場合には変数 {\tt i} を使用します。\\[3mm]
%
{\tt jcnt({\it var})}  &                 内側の for 文のループカウンタとして変数 {\it var} を指定します。\\
                       &                 指定がない場合には変数 {\tt j} を使用します。\\[3mm]
%
{\tt result({\it var, ...})}  &          変数 {\it var} の入出力型を {\tt result} 型に指定します。\\[3mm]
%
{\tt ip({\it var, ...})}  &              変数 {\it var} の入出力型を {\tt ip} 型に指定します。\\[3mm]
%
{\tt jp({\it var, ...})}  &              変数 {\it var} の入出力型を {\tt jp} 型に指定します。\\[3mm]
%
{\tt private({\it var, ...})}  &         変数 {\it var} の入出力型を {\tt private} 型に指定します。\\[3mm]
%
{\tt shared\_ro({\it var, ...})}  &      変数 {\it var} の入出力型を {\tt shared\_ro} 型に指定します。\\[3mm]
%
{\tt precision("{\it prec}")}  &
\begin{minipage}[t]{120mm}
変数の数値フォーマットとして、"{\it prec}" を指定します。
指定できる値は "{\tt double}" (64-bit 浮動小数点) と
"{\tt double-single}" (加減算 64-bit 浮動小数点、乗算 32-bit 浮動小数点) です。
"{\tt single}" (32-bit 浮動小数点) および
"{\tt quadruple}" (128-bit 浮動小数点) にも対応の予定です。
指定がない場合には "{\tt double}" を使用します。\\
\end{minipage}\\
%
{\tt asmfile("{\it filename}")}  &
\begin{minipage}[t]{120mm}
アセンブラに渡すアセンブリコードを指定します。
goosecc が出力したコード ({\it e.g.,} {\tt foo\_0.vsm}) の代わりに、
ハンドチューニングしたアセンブリコードを使用する場合に指定します。\\
\end{minipage}\\
%
~~(続く) & \\[3mm]
%
\hline
%
\end{tabular}
\end{minipage}

\clearpage
\vspace*{3mm}
\noindent
\begin{minipage}{160mm}
{\bf オプション引数一覧 (続き):}\\[3mm]
\begin{tabular}{ll}
\hline
書式               & 機能 \\
\hline
\hline
%
{\tt njp\_write({\it var})}  &
\begin{minipage}[t]{120mm}
指定すると、{\tt jp} 型データのうち、インデクス {\tt j} の値が
{\it var} 未満のものだけをアクセラレータに送信するようになります。
複数回の計算にまたがって {\tt jp} 型データの一部を使いまわせる場合に、
データ転送量を減らすことができます ({\tt \$goosepkg/sample/s8/} 参照)。
指定がない場合にはすべての {\tt jp} 型データを送信します。\\
\end{minipage}\\
%
{\tt nip\_pack({\it uint})}  &
\begin{minipage}[t]{120mm}
    ハードウェアアクセラレータのプロセッサ要素1個が処理する演算量を指定
    します。指定のない場合には、ひとつのプロセッサ要素が{\it
      nvec} 個の {\tt i} に対する計算を実行します (ここで {\it nvec} は
    ベクトルプロセッサのループ長) が、指定すると、{\it uint $\times$
      nvec} 個の {\tt i} に対する計算を実行するようになりま
    す。2$\sim$5 程度の値を指定すると、ホスト計算機との通信オーバヘッド
    が隠蔽され、実効性能が
    向上する場合があります。\\
\end{minipage}\\
\hline
%
\end{tabular}
\end{minipage}

\clearpage
\noindent
入出力型指定に関する注意:

\begin{itemize}

\item 複数の変数の入出力型を指定するには、カンマで区切って列挙します。\\[-5mm]

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
例 :  ip(a, b, c)
\end{verbatim}
\end{minipage}

\item 入出力型指定は、より正確には、変数でなく、変数によって参照される
    値に対して行います。従って例えば、ある変数配列のインデクスに別の変
    数を使用した表現や、ポインタ変数のデリファレンス、構造体のメンバ参照なども
    指定できます。\\[-3mm]

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
例 : double x[255];
     int index[255], j;
     struct a_struct_t a_struct, *a_struct_p;
     ip(x[0]);                 // 配列型変数の要素
     ip(x[i]);                 // 配列型変数のインデクスに変数を使用
     ip(x[index[i]]);          // 配列のインデクスに他の配列の要素を使用
     jp(*(x+j));               // ポインタのデリファレンス
     jp(a_struct.a_member);    // 構造体メンバの参照
     jp(a_struct_p->a_member); // 構造体へのポインタからのメンバ参照
\end{verbatim}
\end{minipage}

\item 配列型の変数を指定する際、配列の範囲を表す演算子 {\tt ..} を使用できます。\\[-5mm]

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
例 : ip(x[i][0..2])
\end{verbatim}
\end{minipage}

\noindent
という記述は\\[-7mm]

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
ip(x[i][0], x[i][1], x[i][2])
\end{verbatim}
\end{minipage}

\noindent
と同値です。

\item ハードウェアアクセラレータとホスト計算機はアドレス空間を共有して
    いないため、アドレスの受渡しは行えません。従ってアドレス参照に対する
    入出力型の指定は行えません。\\[-3mm]

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
例 : double x, y[255];
     int i;
     ip(&x);                // NG
     ip(x);                 // OK
     ip(y);                 // NG
     ip(y[0]);              // OK
     ip(y[i]);              // OK
     ip(*(y + i));          // OK
\end{verbatim}
\end{minipage}

\end{itemize}

\Subsection{Goose func 疑似命令詳細}\label{sec:pragmafunc}

Goose func 疑似命令 {\tt \#pragma goose func} を関数定義の直前に記述す
ると、Goose for 疑似命令を付加した for 文の内部からその関数を呼び出せる
ようになります。関数は引数を一つだけとり、なおかつ {\tt return} 文を用
いて明示的に返り値を返す必要があります ({\tt void} 型を返すことはできま
せん)。引数および返り値の型はすべて double 型(あるいは {\tt \#pragma
  goose parallel for precision} で指定した型) となります。
C 言語での型宣言は無視されます。\\

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
例 : #pragma goose func
     static double rsqrt(double r2)
     {
        int i;
        double x0 = 1.0;
        for (i = 0; i < 4; i++) {
            x0 = 0.5*x0*(3.0 - r2*x0*x0);
        }
        return x0;
     }
\end{verbatim}
\end{minipage}

\vspace*{3mm}
なお Goose func 疑似命令を付加した関数と同名の関数が Gooseの組み込み関
数としてあらかじめ定義されている場合には、関数の再定義は行われずに、
組み込み関数が使用されます。組み込み関数には以下のものがあります:

\begin{itemize}

\item {\tt rsqrt(x)} : 引数 {\tt x} の逆平方根 ($1/\sqrt{x}$) を返します。

\end{itemize}

\clearpage
\Section{コンパイル可能な C 言語記述}\label{sec:cgrammar}

{\tt goosecc} はすべての C 言語記述をコンパイルできるわけではありません。
本章ではコンパイル可能な記述について説明します。

\Subsection{代入文}

ほとんどの代入文はコンパイル可能です。\\[-3mm]

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
例 : r2 = dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2];
     a[i][k] += mf * dx[k];  // 自己代入。
     double eps = 0.01;      // 初期値つき変数宣言。
     rinv = rsqrt(r2);       // 関数の返り値の代入。
\end{verbatim}
\end{minipage}

\vspace*{3mm}
\noindent
代入表現を値として評価することも可能です。\\[-3mm]

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
例 : x = y = z = 0.0;
     rinv = rsqrt(r2 = dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2]);
\end{verbatim}
\end{minipage}

\Subsection{if 文}

if 文は、条件式が以下の形式にマッチするもののみコンパイル可能です。\\[-3mm]

\hspace*{5mm}
\begin{minipage}{150mm}
{\tt
{\it var0} {\it rel\_op} {\it var1}
}
\end{minipage}

\vspace*{3mm}
\noindent
ここで {\it var0, var1} は変数あるいは数値リテラル、\\
{\it rel\_op} は比較演算子 $<, <=, >, >=, ==, !=$ のいずれかです。\\[-3mm]

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
例 : if (i != j) {
       f[i] += fij;
     }
\end{verbatim}
\end{minipage}

\vspace*{3mm}
\noindent
ネストも可能です。\\[-3mm]

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
例 : if (q > 2.0) {
       wkernel = 0.0;
     }
     else if (q > 1.0) {
       wkernel = 0.25*(2.0-q)*(2.0-q)*(2.0-q);
     }
     else {
       wkernel = 1.0-1.5*q*q+0.75*q*q*q;
     }
\end{verbatim}
\end{minipage}

\Subsection{条件演算子}

条件演算子は、if 文と同様に、条件式が以下の形式にマッチするもの
のみコンパイル可能です。\\[-3mm]

\hspace*{5mm}
\begin{minipage}{150mm}
{\tt
{\it var0} {\it rel\_op} {\it var1}
}
\end{minipage}

\vspace*{3mm}
\noindent
ここで {\it var0, var1} は変数あるいは数値リテラル、\\
{\it rel\_op} は比較演算子 $<, <=, >, >=, ==, !=$ のいずれかです。\\[-3mm]

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
例: wkernel = q > 2.0 ? 0.0 : 0.25*(2.0-q)*(2.0-q)*(2.0-q);
\end{verbatim}
\end{minipage}

\vspace*{3mm}
\noindent
ネストも可能です。\\[-3mm]

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
例: wkernel = q > 2.0 ? 0.0 :
                        q > 1.0 ? 0.25*(2.0-q)*(2.0-q)*(2.0-q) :
                                  1.0-1.5*q*q+0.75*q*q*q;
\end{verbatim}
\end{minipage}

\Subsection{for 文}\label{sec:cgrammarfor}

Goose for 疑似命令 を付加した 2 重 for ループのさらに内側にある for 文、
および Goose func 疑似命令を付加した関数定義内の for 文は、アンロールさ
れます。ループがネストしている場合には、再帰的にすべてのループがアンロー
ルされます。

ループ範囲とループカウンタの増分が定数の場合のみアンロール可能です。
それ以外の場合にはコンパイル中に警告メッセージが出力され、for 文全体が無視されます。
より厳密には、以下の形式にマッチする for 文のみがアンロールの対象となります。\\[-3mm]

\hspace*{5mm}
\begin{minipage}{150mm}
{\tt
for ({\it var} = {\it init\_val} ; {\it var} {\it rel\_op} {\it final\_val} ; {\it var} = {\it var} + {\it inc\_val})
}
\end{minipage}

\vspace*{3mm}
\noindent
ここで {\it var} は変数、{\it init\_val, final\_val, inc\_val} は整数リテラル、
{\it rel\_op} は比較演算子 $<$ または $<=$ です。
式 {\it var} = {\it var} + {\it inc\_val} を
{\it var} += {\it inc\_val} と表記することも可能です。
{\it inc\_val} が 1 の場合には、{\it var}++ と表記することも可能です。\\

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
例 : for (k = 0; k < 3; k++) {
       a[i][k] += mf * dx[k];
     }
\end{verbatim}
\noindent
この for 文は、以下の記述にアンロールされます。
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
     a[i][0] += mf * dx[0];
     a[i][1] += mf * dx[1];
     a[i][2] += mf * dx[2];
\end{verbatim}
\end{minipage}

\Subsection{return 文}

Goose func 疑似命令を付加した関数定義内で使用できます。
Goose for 疑似命令を付加した for 文内では使用できません。

\Subsection{コンパイル不可能な記述の処置}\label{sec:invalidgrammar}

{\tt goosecc} はコンパイル不可能な記述を見つけると警告メッセージを出力
しますが、コンパイル自体は続行します。コンパイル不可能な記述は単に無視し
ます。そのため、例えばホスト計算機上でのデバッグに使用した {\tt
  printf()} 関数呼び出しがプログラム中に残っていても、ハードウェアアク
セラレータ上の計算に影響を与えることはありません。

\clearpage
\Section{Goose 詳細}\label{sec:advanced}

\Subsection{{\tt goosecc} コマンドライン引数}\label{sec:gooseccopt}

{\tt goosecc} の書式を以下に示します。\\[-3mm]

\hspace*{5mm}
\begin{minipage}{150mm}
{\tt
  goosecc [{\it options}] {\it inputfile(s)...}
}
\end{minipage}

\vspace*{3mm}
\noindent
{\it inputfile(s)...} は C 言語で記述されたプログラムのソースファイルです。
{\it options} には以下のものを指定できます。

\vspace*{3mm}
\noindent
{\bf コマンドラインオプション一覧}\\[3mm]
\begin{tabular}{ll}
\hline
オプション & 意味 ([~~] 内はデフォルト値) \\
\hline
\hline
--goose-arch $<$ {\it arch} $>$  & ハードウェアアクセラレータの種別を指定します。[gdr] \\[3mm]
%
--goose-backannotate             & アセンブリコードの再生成を抑止します。\\
                                 & アセンブリコードをハンドチューニングした場合に使用します。\\[3mm]
%
-o $<${\it outputfile} $>$       & 生成する実行ファイルのファイル名を指定します。[a.out] \\[3mm]
%
-I $<${\it headerpath}$>$        & ヘッダファイルの検索パスを指定します。\\[3mm]
%
--verbose [ = {\it level} ]      & 饒舌モードを指定します。饒舌度を指定することも可能です。\\
-v [ {\it level} ]               & 値が大きいほど饒舌になります。最小値は 0、デフォルト値は 2 です。\\[3mm]
%
--help                           & ヘルプメッセージを出力します。\\
-h                               & \\[3mm]
%
-Wcc ``{\it options}''           & C コンパイラへ渡すオプションを明示的に指定します。\\
\hline
\end{tabular}

\vspace*{5mm}
\noindent
なお、これら以外のオプションは、{\tt goosecc} では解釈されずに
C コンパイラへと渡されます。

\Subsection{{\tt goosecc} の内部動作}

{\tt goosecc} は内部的にいくつかのコマンドを呼び出してコンパイルを行い
ます。通常、ユーザがこれらの呼び出しを意識する必要はありませんので、本
節では動作の概要のみを簡単に説明します。

{\tt goosecc} は引数として渡されたファイルのうち、拡張子 .c を持つもの
についてのみ、ファイルの内部を走査します。内部に Goose 疑似命令が見つか
ると、そのファイルを C 言語フロントエンド ({\tt goosec2q}) へ渡しま
す。{\tt goosec2q} の出力は中間言語コンパイラ ({\tt LSUMP})、アセンブ
ラ ({\tt vsm}) を経由して C コンパイラ ({\tt gcc} もしくは環境変
数 CC で指定したコンパイラ) へと渡されます。

{\tt goosecc} に渡されたファイル内に Goose 疑似命令が見つからない場合に
は、そのファイルはそのまま C コンパイラへ渡されます。.c 以外の拡張子を
持つファイルについては、疑似命令の有無や記述言語にかかわらず、無条件
に C コンパイラへ渡されます。

C コンパイラは各プログラムから受け取った入力をコンパイルし、アクセラレー
タ制御用ライブラリ等とリンクして、実行ファイルを生成します。

%
\Figure{140}{comp_flow.eps}
{図 : {\tt goosecc} によるコンパイルの流れ\\
(ハードウェアアクセラレータとして GRAPE-DR を使用する場合)。}

\Subsection{ハードウェアアクセラレータのアーキテクチャ}

本節ではハードウェアアクセラレータのアーキテクチャを説明します。ただし
説明内容は、Goose からアクセラレータを使用する際の効率を向上させるため
に有用と思われる、基礎的な知識のみに限定します。詳細説明は各アクセラレー
タの関連文書を参照してください。

\Subsubsection{GRAPE-DR}\label{sec:gdr}

GRAPE-DR は GRAPE-DR プロセッサチップ (東京大学、国立天文台開発のカスタ
ム LSI) を搭載した、当社開発のハードウェアアクセラレータです。チップ
を 1 個搭載したモデル (model450 ほか) と、4 個搭載したモデル
(model1800 ほか) があります。

GRAPE-DR チップには 512 個のベクトルプロセッサ (processor element、以
降 PE と表記します) が集積されています。各 PE は乗算器と加算器、レジス
タファイル、ローカルメモリを持ち、外部から送られてくる命令を SIMD 的に
実行します。ベクトル演算のループ長は最大 4 です。

512 個の PE は 32 個ずつ、全 16 個の放送ブロックにまとめられています。
各放送ブロックは放送メモリを持ち、同一ブロック内の 32 個の PE に対して
データを放送することが可能です。

16 個の放送ブロックの出力は、ツリー型の結果縮約ネットワークによって相互
に接続されています。各放送ブロックからの 128 個 (PE 32 個 $\times$ ルー
プ長 4) の計算結果出力は、加算 (あるいは論理演算など) によってトーナメ
ント形式で縮約され、チップ外部へ出力されます。

%
\Figure{140}{gdrarch.eps}
{図 : GRAPE-DR チップの内部構成}

\noindent
2 重 for ループ (式(\ref{eq:sumj})型) の動作例:\\

節 \ref{sec:tut2} のチュートリアルで示した 2 重 for ループ
(以下に再掲) を例に、GRAPE-DR 上での計算の実行手順を説明します。

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
#pragma goose parallel for icnt(i) jcnt(j) \
  ip(x[i][0..2]) jp(x[j][0..2],m[j]) result(a[i][0..2],pot[i])\
  precision ("double") 
    for(i=0;i<n;i++) {
      for(k=0;k<3;k++) a[i][k] = 0.0;
      pot[i] = 0.0;
      for(j=0;j<n;j++) {
        for(k=0;k<3;k++) dx[k] = x[j][k] - x[i][k];
        r2 = dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2] + eps2;
        rinv = rsqrt(r2);
        mrinv = m[j]*rinv;
        mr3inv = mrinv*rinv*rinv;
        for(k=0;k<3;k++) a[i][k] += mr3inv * dx[k];
        pot[i] += -mrinv;      
      }
    }
    get_cputime(&lt,&st);
    total_time += lt;
    for(i=0;i<n;i++) pot[i] += m[i]/sqrt(eps2);
\end{verbatim}
\end{minipage}

\vspace*{3mm}
\noindent
\begin{enumerate}

\item[(手順1)] 入出力型として {\tt jp} を持つ {\tt n} 個の変数 {\tt
      x[j][0..2]} および {\tt m[j]} を、ホスト計算機から GRAPE-DR ボー
    ド上の外部メモリに書き込みます。

\item[(手順2)] 入出力型として {\tt ip} を持つ変数 {\tt x[i][0..2]} を、
    各 PE のローカルメモリに書き込みます。書き込まれるのは全 {\tt n} 個
    の {\tt x[i][0..2]} のうち、128 個だけです。この 128 個を全 16 個の
    放送ブロックに放送します。各放送ブロック内では、この 128 個を PE0
    $\sim$ PE31 の 32 個の PE それぞれへ 4 個 (つまりベクトルプロセッサ
    のループ長) ずつ書き込みます。すべての放送ブロックに、同一の {\tt
      x[i][0..2]} が書き込まれることに注意してください。

\item[(手順3)] 計算に先立ち、外部メモリから 16 個の{\tt x[j][0..2]} お
    よび {\tt m[j]} を読み出し、各放送ブロックの放送メモリに書き込んで
    おきます。各放送ブロックの放送メモリには、互いに異なる {\tt
      x[j][0..2], m[j]} が書き込まれます。

\item[(手順4)] 計算を開始すると、各放送ブロックの放送メモリか
    ら 32 個の PE へ {\tt x[j][0..2]} と{\tt m[j]} が放送されます。
    各PE はこれらと自身の {\tt x[i][0..2]} を用いて 2 重 for ループ最内
    部の計算を実行します。同一の放送ブロック内の PE は、共通の {\tt
      x[j][0..2], m[j]} から互いに異なる {\tt x[i][0..2]}に対して及ぼさ
    れる重力を計算することになります。これに対し、異なる放送ブロック内
    の 32 個の PE は、互いに異なる {\tt x[j][0..2], m[j]} から共通の
    {\tt x[i][0..2]}に対して及ぼされる重力を計算することになります。

\item[(手順5)] 16 個の放送ブロックからは、それぞれ 128 個の {\tt i} に
    対する {\tt a[i][0..2]} と {\tt pot[i]} が、計算結果として出力され
    ます。これら 128 $\times$ 16 個の計算結果は、ツリー型の結果縮約ネッ
    トワークを通して順次積算され、128 個に縮約されます。

\item[(手順6)] すべての {\tt i} に対する {\tt a[i][0..2]} と {\tt
      pot[i]} を求め終えるまで、(手順2)から(手順5)と同様の手順を、新た
    な 128 個の {\tt x[i][0..2]} について順次繰り返します。

\end{enumerate}

\noindent
この手順で計算を行う場合、{\tt i} に関する並列度が 128 以上、{\tt j} に
関する並列度が 16 以上あれば、チップ内のすべての PE を利用して計算を行
えます。並列度がそれよりも低い場合や、128 や 16 で割り切れない端数部分
の処理を行う場合には、一部のプロセッサ要素は計算に利用されず、遊んでし
まうことになります。

\vspace*{5mm}
\noindent
1 重 for ループ (式(\ref{eq:simd})型) の動作例:\\

節 \ref{sec:tut1} のチュートリアルで示した 1 重 for ループ
(以下に再掲) を例に、GRAPE-DR 上での計算の実行手順を説明します。\\

\hspace*{5mm}
\begin{minipage}{150mm}
\baselineskip=14pt \lineskiplimit=-\maxdimen
\begin{verbatim}
#pragma goose parallel for icnt(i) result(sum) ip(i) shared_ro(dx)
  for(i=0;i<n;i++) {
    x = (i+0.5)*dx;
    sum += integrand(x)*dx;        
  }
\end{verbatim}
\end{minipage}

\vspace*{3mm}
\noindent
\begin{enumerate}

\item[(手順1)] 入出力型として {\tt ip} を持つ変数 {\tt i} と、型 {\tt
      shared\_ro}を持つ変数 {\tt dx} を、各 PE のローカルメモリに書き込
    みます。書き込まれるのは全 {\tt n} 個の {\tt i]} と {\tt dx} のう
    ち、128 個だけです。この 128 個を全 16 個の放送ブロックに放送します。
    各放送ブロック内では、この 128 個を PE0 $\sim$
    PE31 の 32 個の PE それぞれへ 4 個 (つまりベクトルプロセッサのルー
    プ長) ずつ書き込みます。すべての放送ブロックに、同一の {\tt i} と
    {\tt dx} が書き込まれることに注意してください。

\item[(手順2)] 計算を開始すると、PE はを {\tt i} と {\tt dx} 用いfor ルー
    プ内部の計算を実行します。全 16 個の放送ブロックが同じ計算を実行
    することになります。

\item[(手順3)] 16 個の放送ブロックからは、それぞれ 128 個の {\tt i} に
    対する計算結果が出力されます。これら 128 $\times$ 16 個の計算結果は、
    ツリー型の結果縮約ネットワークを通して順次積算され、128 個に縮約さ
    れます。ホスト計算機上でこの結果を 16 で除し、最終的な計算結果を得ます。

\item[(手順4)] すべての {\tt i} に対する計算結果を求め終えるま
    で、(手順1)から(手順3)と同様の手順を、新たな 128 個の {\tt i}
    について順次繰り返します。

\end{enumerate}

\vspace*{5mm}
\noindent
この手順には 2 つの改善の余地があります。

\begin{itemize}

\item 全 16 個の放送ブロックが同じ計算を実行しています。本来であれば各
    放送ブロックには互いに異なる {\tt i} を書き込み、128 $\times$ 16 個
    の {\tt i} に対する計算を並列に実行することが可能ですが、実際にはそ
    うなっていません。

\item {\tt shared\_ro} 型変数は {\tt i} に依存しないため、本来であれば
    計算開始時に一度だけ、ホスト計算機からアクセラレータへ送信すれば充
    分のはずです。しかし実際には for ループ内で {\tt ip} 型変数と同様に
    繰り返し送信を行っています。この無駄な通信を省けば、通信時間を短縮
    できます。

\end{itemize}

これらの問題は近日中に修正の予定です。ただし、修正を行った場合であって
も、式 (\ref{eq:simd}) 型の計算には通信量に関する本質的な問題は残りま
す (節 \ref{sec:target})。

\clearpage

\Section{利用許諾}\label{sec:license}

Goose ソフトウェアパッケージ (以降「本ソフトウェア」と呼びます) の利用
を、本ソフトウェアの所有者に対してのみ許可します。本ソフトウェアの再配
布を禁じます。本ソフトウェアの改変物についても、本ソフトウェアの利用許
諾に従うものとします。

本ソフトウェアの著作権は株式会社 K\&F Computing Research に帰属します。
本ソフトウェアが依存する外部プログラムやライブラリについては、それぞれ
に個別の利用許諾と著作権が定められています。

\Section{謝辞}\label{sec:acknowledge}

Goose ソフトウェアパッケージの作成にあたり、以下の方々に協力を頂きました。
ここに感謝の意を表します: \\
%
中里直人氏 (会津大学) には LSUMP を Goose の中間言語コンパイラとして使
用することを快諾頂きました。また当社からの数多くの仕様拡張や仕様変更の
要求に対応して頂きました。
%
牧野淳一郎氏 (国立天文台) には GRAPE-DR 用アセンブラ VSM の利用を快諾頂
きました。
%
勝山哲志氏には Goose のロゴを作成して頂きました。
%
C 言語フロントエンド {\tt goosec2q} の開発には、青木峰郎氏開発のパー
サジェネレータ {\tt racc} を使用しました
({\tt http://i.loveruby.net/ja/projects/racc/})。

\Section{Goose ソフトウェアパッケージ更新履歴}\label{sec:history}
\vspace*{5mm}

\begin{tabular}{llll}
\hline
version & date & description & author(s)\\
\hline
1.0.1$\alpha$  & 28-Sep-2009 & 文書の英語版を追加         & AK\\
1.0.0$\alpha$  & 17-Sep-2009 & 初版作成。                 & A. Kawai, T. Fukushige\\
\hline
\end{tabular}\\[5mm]

\noindent
お問い合わせおよびバグレポートは下記まで:\\
株式会社 K\&F Computing Research ({\tt support@kfcr.jp})

\end{document}
