[LLVMdev] [PATCH] LangRef: va_arg doesn't work on X86_64; update example
Ramkumar Ramachandra
artagnon at gmail.com
Tue Oct 28 18:32:12 PDT 2014
Provide a full-fledged example of working variable arguments on X86_64,
since it's easily the most popular platform.
Cc: Reid Kleckner <rnk at google.com>
Signed-off-by: Ramkumar Ramachandra <artagnon at gmail.com>
---
docs/LangRef.rst | 44 ++++++++++++++++++++++++++++++--------------
1 file changed, 30 insertions(+), 14 deletions(-)
diff --git a/docs/LangRef.rst b/docs/LangRef.rst
index ddef803..f429062 100644
--- a/docs/LangRef.rst
+++ b/docs/LangRef.rst
@@ -6695,7 +6695,8 @@ Overview:
The '``va_arg``' instruction is used to access arguments passed through
the "variable argument" area of a function call. It is used to implement
-the ``va_arg`` macro in C.
+the ``va_arg`` macro in C. Note that ``va_arg`` does not work on
+platforms that have a non-builtin ``va_list`` type, like x86_64.
Arguments:
""""""""""
@@ -6879,29 +6880,44 @@ value type "``va_list``". The LLVM assembly language reference manual
does not define what this type is, so all transformations should be
prepared to handle these functions regardless of the type used.
-This example shows how the :ref:`va_arg <i_va_arg>` instruction and the
-variable argument handling intrinsic functions are used.
+This example shows how the variable argument handling is done on
+x86_64. The complexity arises from the fact that ``va_arg`` does not
+work on this type of ``va_list``.
.. code-block:: llvm
+ %struct.__va_list_tag = type { i32, i32, i8*, i8* }
+
define i32 @test(i32 %X, ...) {
; Initialize variable argument processing
- %ap = alloca i8*
- %ap2 = bitcast i8** %ap to i8*
+ %ap = alloca %struct.__va_list_tag
+ %ap2 = bitcast %struct.__va_list_tag* %ap to i8*
+ %retptr = alloca i32
call void @llvm.va_start(i8* %ap2)
; Read a single integer argument
- %tmp = va_arg i8** %ap, i32
-
- ; Demonstrate usage of llvm.va_copy and llvm.va_end
- %aq = alloca i8*
- %aq2 = bitcast i8** %aq to i8*
- call void @llvm.va_copy(i8* %aq2, i8* %ap2)
- call void @llvm.va_end(i8* %aq2)
-
+ %idxptr = getelementptr inbounds %struct.__va_list_tag* %ap, i32 0, i32 0
+ %idx = load i32* %idxptr
+ %tmp = getelementptr inbounds %struct.__va_list_tag* %ap, i32 0, i32 3
+ %extract = load i8** %tmp
+ %rawel = getelementptr i8* %extract, i32 %idx
+ %elptr = bitcast i8* %rawel to i32*
+ %newidx = add i32 %idx, 8
+ store i32 %idx, i32* %idxptr
+
+ ; Store that argument in el
+ %el = load i32* %elptr
+ store i32 %el, i32* %retptr
+ %ret = load i32* %retptr
+
; Stop processing of arguments.
call void @llvm.va_end(i8* %ap2)
- ret i32 %tmp
+ ret i32 %ret
+ }
+
+ define i32 @main() {
+ %call = call i32 (i32, ...)* @test(i32 1, i32 3)
+ ret i32 %call
}
declare void @llvm.va_start(i8*)
--
1.9.3 (Apple Git-50)
More information about the llvm-dev
mailing list