単一の引数に適用でき、続いて別の引数に適用できる関数「add」を作成しようとしています。単一の値で関数を呼び出し、その値をメモリのどこかに保存し、その値に適用される別の関数を返す方法がわからないため、LLVM IR でこれを表す方法がわかりません。LLVM にはある種の閉鎖メカニズムが必要です。
C での実装を検索して、出力された LLVM を clang で表示できるようにしましたが、見つかった解決策は非常に複雑だったので、LLVM を直接調査するだけでよいと考えました。
これはカリー化されていないバージョンになります
define i8 @add(i8 %a, i8 %b) {
entry:
%res = add i8 %a, %b
ret i8 %res
}
そして、どういうわけか、型add(1)
を返したいと思います。i8 (i8)
どうにかして機能を分割する必要があると思います。
ps。私は小さな関数型言語のコンパイラに取り組んでいるので、これを調べています。そのため、一般的なコンパイラ設計における部分的なアプリケーション/カリー化の実装に関するアドバイスを探しています。
更新: 次のコードが機能するようになりましたが、非常に複雑で、自動的に生成するのは簡単ではないと思います
declare i32 @printf(i8* noalias nocapture, ...)
define { i8, i8 (i8, i8) * } @add1(i8 %a) {
; allocate the struct containing the supplied argument
; and a function ptr to the actual function
%nextPtr = alloca { i8, i8 (i8, i8) * }
store { i8, i8 (i8, i8) * } { i8 undef, i8 (i8, i8) * @add2 }, { i8, i8 (i8, i8) * } * %nextPtr
%next0 = load { i8, i8 (i8, i8) * } * %nextPtr
; insert the supplied arg into the struct
%next1 = insertvalue { i8, i8 (i8, i8) * } %next0, i8 %a, 0
ret { i8, i8 (i8, i8) * } %next1
}
define i8 @add2(i8 %a, i8 %b) {
%res = add i8 %a, %b
ret i8 %res
}
define i8 @main() {
; call add(35) resulting in 'fn' of type {35, &add2}
%res1 = call { i8, i8 (i8, i8) * } @add1(i8 35)
; get the arg of the first call, ie element 0 of the resulting struct
%arg = extractvalue { i8, i8 (i8, i8) * } %res1, 0
; similarily get the function ptr
%fn = extractvalue { i8, i8 (i8, i8) * } %res1, 1
; apply the argument to the function
%res = call i8 %fn(i8 %arg, i8 30)
; print result
%ptr = alloca i8
store i8 %res, i8* %ptr
call i32 (i8*, ...)* @printf(i8* %ptr)
ret i8 0
}