LLVM中的部分应用程序

时间:2014-04-12 18:18:20

标签: compiler-construction llvm llvm-ir compiler-development

我正在尝试创建一个可以应用于单个参数的函数“add”,然后是另一个。我无法弄清楚如何使用LLVM IR来表示这一点,因为我不明白如何使用单个值调用函数,然后将值保存在内存中的某个位置并返回应用于该val的另一个函数。我需要在LLVM中使用某种闭包机制。

我在C中搜索了这个实现,这样我就可以通过clang查看发出的LLVM,但我发现的解决方案非常复杂,所以我想我可能只是直接调查LLVM。

这将是未经证实的版本

define i8 @add(i8 %a, i8 %b) {
entry:
  %res = add i8 %a, %b
  ret i8 %res
}

不知何故,我希望add(1)返回i8 (i8)类型。我想我必须以某种方式分割功能。

PS。我正在调查这个因为我正在编写一个小函数式语言的编译器,所以我正在寻找任何关于在编译器设计中实现部分应用程序/ currying的建议。

更新: 我现在有以下代码工作,但它是一个相当复杂的我不认为它会很容易自动生成

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
}

1 个答案:

答案 0 :(得分:2)

我写了this example C code来模仿我的函数式语言编译器支持的部分应用程序' (lambda演算)。我不会发出' C'但是,代码直接发送到LLVM-IR。您只需从示例源发出即可看到LLVM-IR透视图:

clang -S -emit-llvm partial.c

当它通过AST节点时,触发编译器在LLVM-IR中发出部分机制,反映括号括起来(给出或采取一些额外的细节)表达式。

希望这有帮助。