From c78b1639b445e31274858d0801d30a2f9cd3d7e6 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Mon, 24 Oct 2011 17:03:18 -0700
Subject: [PATCH] fix c-stack-cdecl when used w/ i64

---
 src/comp/back/upcall.rs                      | 10 +++++++---
 src/comp/middle/trans.rs                     | 10 ++++++++--
 src/rt/arch/i386/ccall.S                     |  4 ++++
 src/rt/rustrt.def.in                         |  1 +
 src/test/run-pass/c-stack-returning-int64.rs | 20 ++++++++++++++++++++
 5 files changed, 40 insertions(+), 5 deletions(-)
 create mode 100644 src/test/run-pass/c-stack-returning-int64.rs

diff --git a/src/comp/back/upcall.rs b/src/comp/back/upcall.rs
index 04bdebb04a1..0eaef300d80 100644
--- a/src/comp/back/upcall.rs
+++ b/src/comp/back/upcall.rs
@@ -3,7 +3,7 @@ import std::str;
 import middle::trans;
 import trans::decl_cdecl_fn;
 import middle::trans_common::{T_f32, T_f64, T_fn, T_bool, T_i1, T_i8, T_i32,
-                              T_int, T_vec, T_nil, T_opaque_chan_ptr,
+                              T_i64, T_int, T_vec, T_nil, T_opaque_chan_ptr,
                               T_opaque_vec, T_opaque_port_ptr, T_ptr,
                               T_size_t, T_void, T_float};
 import lib::llvm::type_names;
@@ -28,6 +28,7 @@ type upcalls =
      dynastack_free: ValueRef,
      alloc_c_stack: ValueRef,
      call_c_stack: ValueRef,
+     call_c_stack_i64: ValueRef,
      call_c_stack_float: ValueRef,
      rust_personality: ValueRef};
 
@@ -76,8 +77,11 @@ fn declare_upcalls(_tn: type_names, tydesc_type: TypeRef,
           dynastack_free: dv("dynastack_free", [T_ptr(T_i8())]),
           alloc_c_stack: d("alloc_c_stack", [T_size_t()], T_ptr(T_i8())),
           call_c_stack: d("call_c_stack",
-                          [T_ptr(T_fn([], T_int())), T_ptr(T_i8())],
-                          T_int()),
+                              [T_ptr(T_fn([], T_int())), T_ptr(T_i8())],
+                              T_int()),
+          call_c_stack_i64: d("call_c_stack_i64",
+                              [T_ptr(T_fn([], T_int())), T_ptr(T_i8())],
+                              T_i64()),
           call_c_stack_float: d("call_c_stack_float",
                                 [T_ptr(T_fn([], T_int())), T_ptr(T_i8())],
                                 T_float()),
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 11d7d62436a..7fe35776529 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -3878,13 +3878,19 @@ fn trans_c_stack_native_call(bcx: @block_ctxt, f: @ast::expr,
         ccx.upcalls.call_c_stack_float
       }
 
+      7 {
+        // LLVMIntegerTypeKind
+        let width = lib::llvm::llvm::LLVMGetIntTypeWidth(llretty);
+        if width == 64u { ccx.upcalls.call_c_stack_i64 }
+        else { ccx.upcalls.call_c_stack } // on 64-bit target, no diff
+      }
+
       _ { ccx.upcalls.call_c_stack }
     };
 
     // Call and cast the return type.
     // TODO: Invoke instead.
-    let llrawretval = Call(bcx, upcall_fn,
-                           [llfn, llrawargbundle]);
+    let llrawretval = Call(bcx, upcall_fn, [llfn, llrawargbundle]);
     let llretval;
     if lib::llvm::llvm::LLVMGetTypeKind(llretty) as int == 11 { // pointer
         llretval = IntToPtr(bcx, llrawretval, llretty);
diff --git a/src/rt/arch/i386/ccall.S b/src/rt/arch/i386/ccall.S
index 378ea5e0b67..d901666c6a4 100644
--- a/src/rt/arch/i386/ccall.S
+++ b/src/rt/arch/i386/ccall.S
@@ -6,13 +6,17 @@
 // slower.
 #if defined(__APPLE__) || defined(_WIN32)
 .globl _upcall_call_c_stack
+.globl _upcall_call_c_stack_i64
 .globl _upcall_call_c_stack_float
 _upcall_call_c_stack:
+_upcall_call_c_stack_i64:
 _upcall_call_c_stack_float:
 #else
 .globl upcall_call_c_stack
+.globl upcall_call_c_stack_i64
 .globl upcall_call_c_stack_float
 upcall_call_c_stack:
+upcall_call_c_stack_i64:
 upcall_call_c_stack_float:
 #endif
     pushl %ebp
diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in
index 6b70e283957..8293a23d126 100644
--- a/src/rt/rustrt.def.in
+++ b/src/rt/rustrt.def.in
@@ -65,6 +65,7 @@ task_join
 unsupervise
 upcall_alloc_c_stack
 upcall_call_c_stack
+upcall_call_c_stack_i64
 upcall_call_c_stack_float
 upcall_cmp_type
 upcall_dynastack_alloc
diff --git a/src/test/run-pass/c-stack-returning-int64.rs b/src/test/run-pass/c-stack-returning-int64.rs
new file mode 100644
index 00000000000..33e8b73a495
--- /dev/null
+++ b/src/test/run-pass/c-stack-returning-int64.rs
@@ -0,0 +1,20 @@
+use std;
+import std::str;
+
+native "c-stack-cdecl" mod libc = "" {
+    fn atol(x: str::sbuf) -> int;
+    fn atoll(x: str::sbuf) -> i64;
+}
+
+fn atol(s: str) -> int {
+    ret str::as_buf(s, { |x| libc::atol(x) });
+}
+
+fn atoll(s: str) -> i64 {
+    ret str::as_buf(s, { |x| libc::atoll(x) });
+}
+
+fn main() {
+    assert atol("1024") * 10 == atol("10240");
+    assert (atoll("11111111111111111") * 10i64) == atoll("111111111111111110");
+}