[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