Nested function in RSL.

by syoyo

RSL(RenderMan Shading Language) のコンパイラ作成は順調ですが、
いろいろ RSL を食わせてテストしていたらネスト関数に出くわしました.

これってアリなの?と RIspec を見ると, ちゃんとネスト関数は仕様として定義されていることが判りました.

Functions may be declared anyplace that it is legal to declare a variable or have any other
language statement, including inside the body of a shader, inside another function, or in-
side any other code block. A function may only be called within the lexical scope in which
it is declared, and only after its declaration (the same rules that apply to using a declared
variable). The only data that functions may access are those passed as parameters, except
for variables declared with the extern keyword, which indicates that the variable is in an
outer scope rather than that local storage should be allocated. For example:

surface mysurf (float Knoise = 0.5;) /* parameter */

  color shadernoise (point p)
    extern float Knoise;
    return Knoise * color noise (transform (”shader”, p));

  /* code for the shader */
  Ci = shadernoise(P) * diffuse(faceforward(normalize(N),I));

うーん、 lexical scope なくせにネスト関数内部から外の変数にアクセスするには extern 宣言する必要があるって, なんかすごい劣化したクロージャという感じであまりユーザにとって利益がないような構文という気がします(コンパイラを書くほうにとっては楽なのかもしれませんが).

LLVM IR で実現するには

さて、RSL コンパイラは LLVM IR を出力するので、このネスト関数を LLVM IR でどう実現すればいいのか,
llvm-gcc に似たような構文を食わせて結果を見てみました.
(clang だとネスト関数はサポートされていないみたいなので llvm-gcc を利用)

これを llvm-gcc で -fnested-functions 付きでコンパイルして LLVM IR を吐くとこんな感じになります.

ふむふむ、ネスト関数のローカル変数以外は struct を作ってパラメータを渡すようにしているのね.