LLVM创建VarArg函数并访问var args

时间:2016-03-08 18:10:37

标签: llvm llvm-clang llvm-ir

我一直在尝试使用LLVM中的模块传递创建一个函数。我要做的是创建一个变量参数函数,然后添加逻辑来操作变量参数。 例如:

/\*can do this\*/

int foo(int a, ...)
{

    double var1;
    //can't figure out how to add any of this using llvm

    va_list ap;     
    va_start(ap, a);
    va_arg(var1,double);
    va_end(ap);
}

创建函数类型很简单,因为我只是将vararg boolean设置为true。之后我该怎么办?

1 个答案:

答案 0 :(得分:2)

我总是使用clang来检查转换为c / c ++ lang需要什么。 使用llvm指令va_arg和intinsics llvm.va_start,llvm.va_end,llvm.va_copy来使用llvm变量参数支持。

对于对使用此参数的参数进行操作的函数,您还需要特定于目标的值类型“va_list”。

; This struct is different for every platform. For most platforms,
; it is merely an i8*.
%struct.va_list = type { i8* }

; For Unix x86_64 platforms, va_list is the following struct:
; %struct.va_list = type { i32, i32, i8*, i8* }

ref http://llvm.org/docs/LangRef.html#variable-argument-handling-intrinsics

列出的代码,

    ; ModuleID = 'test.c'
    target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
    target triple = "x86_64-pc-linux-gnu"

    %struct.__va_list_tag = type { i32, i32, i8*, i8* }

    ; Function Attrs: nounwind uwtable
    define i32 @foo(i32 %a, ...) #0 {
      %1 = alloca i32, align 4
      %2 = alloca i32, align 4
      %var1 = alloca double, align 8
      %ap = alloca [1 x %struct.__va_list_tag], align 16
      store i32 %a, i32* %2, align 4
      %3 = getelementptr inbounds [1 x %struct.__va_list_tag]* %ap, i32 0, i32 0
      %4 = bitcast %struct.__va_list_tag* %3 to i8*
      call void @llvm.va_start(i8* %4)
      %5 = getelementptr inbounds [1 x %struct.__va_list_tag]* %ap, i32 0, i32 0
      %6 = getelementptr inbounds %struct.__va_list_tag* %5, i32 0, i32 1
      %7 = load i32* %6
      %8 = icmp ule i32 %7, 160
      br i1 %8, label %9, label %15

    ; <label>:9                                       ; preds = %0
      %10 = getelementptr inbounds %struct.__va_list_tag* %5, i32 0, i32 3
      %11 = load i8** %10
      %12 = getelementptr i8* %11, i32 %7
      %13 = bitcast i8* %12 to double*
      %14 = add i32 %7, 16
      store i32 %14, i32* %6
      br label %20

    ; <label>:15                                      ; preds = %0
      %16 = getelementptr inbounds %struct.__va_list_tag* %5, i32 0, i32 2
      %17 = load i8** %16
      %18 = bitcast i8* %17 to double*
      %19 = getelementptr i8* %17, i32 8
      store i8* %19, i8** %16
      br label %20

    ; <label>:20                                      ; preds = %15, %9
      %21 = phi double* [ %13, %9 ], [ %18, %15 ]
      %22 = load double* %21
      %23 = getelementptr inbounds [1 x %struct.__va_list_tag]* %ap, i32 0, i32 0
      %24 = bitcast %struct.__va_list_tag* %23 to i8*
      call void @llvm.va_end(i8* %24)
      %25 = load i32* %1
      ret i32 %25
    }

    ; Function Attrs: nounwind
    declare void @llvm.va_start(i8*) #1

    ; Function Attrs: nounwind
    declare void @llvm.va_end(i8*) #1

    ; Function Attrs: nounwind uwtable
    define i32 @main() #0 {
      ret i32 0
    }