Я всегда использую 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* }
исй 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
}
Когда я использую пасс модуля с ИК-Builder, как я добавить llvm.a_start? Например, если я хочу выполнить выделение, я вызываю builder.Alloca(). Я не вижу ничего подобного для va_start или end – teslik
va_start, va_end и va_copy - это llvm intrinsics, чтобы добавить их вызов, вы можете использовать sIRB.CreateCall (Intrinsic :: getDeclaration (currentModule, llvm :: Intrinsic :: va_start, ArrayRef (Tys, numTys)), args), это добавит объявление и вызовет вызов. P.S вам нужно проверить, не перегружена ли внутренняя или нет во время getDeclaration. –
см. Http://stackoverflow.com/questions/27681500/generate-call-to-intrinsic-using-llvm-c-api для уточнения. –