(index<- )        ./librustc/middle/trans/foreign.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Wed Apr  9 17:27:02 2014
   1  // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  
  12  use back::{link};
  13  use lib::llvm::llvm;
  14  use lib::llvm::{ValueRef, CallConv, StructRetAttribute, Linkage};
  15  use lib;
  16  use middle::trans::base::push_ctxt;
  17  use middle::trans::base;
  18  use middle::trans::build::*;
  19  use middle::trans::builder::noname;
  20  use middle::trans::cabi;
  21  use middle::trans::common::*;
  22  use middle::trans::machine;
  23  use middle::trans::type_::Type;
  24  use middle::trans::type_of::*;
  25  use middle::trans::type_of;
  26  use middle::ty::FnSig;
  27  use middle::ty;
  28  use std::cmp;
  29  use libc::c_uint;
  30  use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi};
  31  use syntax::abi::{RustIntrinsic, Rust, Stdcall, Fastcall, System};
  32  use syntax::codemap::Span;
  33  use syntax::parse::token::{InternedString, special_idents};
  34  use syntax::parse::token;
  35  use syntax::{ast};
  36  use syntax::{attr, ast_map};
  37  use util::ppaux::{Repr, UserString};
  38  
  39  ///////////////////////////////////////////////////////////////////////////
  40  // Type definitions
  41  
  42  struct ForeignTypes {
  43      /// Rust signature of the function
  44      fn_sig: ty::FnSig,
  45  
  46      /// Adapter object for handling native ABI rules (trust me, you
  47      /// don't want to know)
  48      fn_ty: cabi::FnType,
  49  
  50      /// LLVM types that will appear on the foreign function
  51      llsig: LlvmSignature,
  52  
  53      /// True if there is a return value (not bottom, not unit)
  54      ret_def: bool,
  55  }
  56  
  57  struct LlvmSignature {
  58      // LLVM versions of the types of this function's arguments.
  59      llarg_tys: Vec<Type> ,
  60  
  61      // LLVM version of the type that this function returns.  Note that
  62      // this *may not be* the declared return type of the foreign
  63      // function, because the foreign function may opt to return via an
  64      // out pointer.
  65      llret_ty: Type,
  66  
  67      // True if *Rust* would use an outpointer for this function.
  68      sret: bool,
  69  }
  70  
  71  
  72  ///////////////////////////////////////////////////////////////////////////
  73  // Calls to external functions
  74  
  75  pub fn llvm_calling_convention(ccx: &CrateContext,
  76                                 abiAbi) -> Option<CallConv> {
  77      let os = ccx.sess().targ_cfg.os;
  78      let arch = ccx.sess().targ_cfg.arch;
  79      abi.for_target(os, arch).map(|abi| {
  80          match abi {
  81              RustIntrinsic => {
  82                  // Intrinsics are emitted by monomorphic fn
  83                  ccx.sess().bug(format!("asked to register intrinsic fn"));
  84              }
  85  
  86              Rust => {
  87                  // FIXME(#3678) Implement linking to foreign fns with Rust ABI
  88                  ccx.sess().unimpl(
  89                      format!("foreign functions with Rust ABI"));
  90              }
  91  
  92              // It's the ABI's job to select this, not us.
  93              System => ccx.sess().bug("system abi should be selected elsewhere"),
  94  
  95              Stdcall => lib::llvm::X86StdcallCallConv,
  96              Fastcall => lib::llvm::X86FastcallCallConv,
  97              C => lib::llvm::CCallConv,
  98              Win64 => lib::llvm::X86_64_Win64,
  99  
 100              // These API constants ought to be more specific...
 101              Cdecl => lib::llvm::CCallConv,
 102              Aapcs => lib::llvm::CCallConv,
 103          }
 104      })
 105  }
 106  
 107  pub fn llvm_linkage_by_name(name: &str) -> Option<Linkage> {
 108      // Use the names from src/llvm/docs/LangRef.rst here. Most types are only
 109      // applicable to variable declarations and may not really make sense for
 110      // Rust code in the first place but whitelist them anyway and trust that
 111      // the user knows what s/he's doing. Who knows, unanticipated use cases
 112      // may pop up in the future.
 113      //
 114      // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
 115      // and don't have to be, LLVM treats them as no-ops.
 116      match name {
 117          "appending" => Some(lib::llvm::AppendingLinkage),
 118          "available_externally" => Some(lib::llvm::AvailableExternallyLinkage),
 119          "common" => Some(lib::llvm::CommonLinkage),
 120          "extern_weak" => Some(lib::llvm::ExternalWeakLinkage),
 121          "external" => Some(lib::llvm::ExternalLinkage),
 122          "internal" => Some(lib::llvm::InternalLinkage),
 123          "linkonce" => Some(lib::llvm::LinkOnceAnyLinkage),
 124          "linkonce_odr" => Some(lib::llvm::LinkOnceODRLinkage),
 125          "private" => Some(lib::llvm::PrivateLinkage),
 126          "weak" => Some(lib::llvm::WeakAnyLinkage),
 127          "weak_odr" => Some(lib::llvm::WeakODRLinkage),
 128          _ => None,
 129      }
 130  }
 131  
 132  pub fn register_static(ccx: &CrateContext,
 133                         foreign_item: &ast::ForeignItem) -> ValueRef {
 134      let ty = ty::node_id_to_type(ccx.tcx(), foreign_item.id);
 135      let llty = type_of::type_of(ccx, ty);
 136  
 137      let ident = link_name(foreign_item);
 138      match attr::first_attr_value_str_by_name(foreign_item.attrs.as_slice(),
 139                                               "linkage") {
 140          // If this is a static with a linkage specified, then we need to handle
 141          // it a little specially. The typesystem prevents things like &T and
 142          // extern "C" fn() from being non-null, so we can't just declare a
 143          // static and call it a day. Some linkages (like weak) will make it such
 144          // that the static actually has a null value.
 145          Some(name) => {
 146              let linkage = match llvm_linkage_by_name(name.get()) {
 147                  Some(linkage) => linkage,
 148                  None => {
 149                      ccx.sess().span_fatal(foreign_item.span,
 150                                            "invalid linkage specified");
 151                  }
 152              };
 153              let llty2 = match ty::get(ty).sty {
 154                  ty::ty_ptr(ref mt) => type_of::type_of(ccx, mt.ty),
 155                  _ => {
 156                      ccx.sess().span_fatal(foreign_item.span,
 157                                            "must have type `*T` or `*mut T`");
 158                  }
 159              };
 160              unsafe {
 161                  let g1 = ident.get().with_c_str(|buf| {
 162                      llvm::LLVMAddGlobal(ccx.llmod, llty2.to_ref(), buf)
 163                  });
 164                  lib::llvm::SetLinkage(g1, linkage);
 165  
 166                  let real_name = "_rust_extern_with_linkage_" + ident.get();
 167                  let g2 = real_name.with_c_str(|buf| {
 168                      llvm::LLVMAddGlobal(ccx.llmod, llty.to_ref(), buf)
 169                  });
 170                  lib::llvm::SetLinkage(g2, lib::llvm::InternalLinkage);
 171                  llvm::LLVMSetInitializer(g2, g1);
 172                  g2
 173              }
 174          }
 175          None => unsafe {
 176              ident.get().with_c_str(|buf| {
 177                  llvm::LLVMAddGlobal(ccx.llmod, llty.to_ref(), buf)
 178              })
 179          }
 180      }
 181  }
 182  
 183  pub fn register_foreign_item_fn(ccx: &CrateContext, abiAbi,
 184                                  foreign_item: &ast::ForeignItem) -> ValueRef {
 185      /*!
 186       * Registers a foreign function found in a library.
 187       * Just adds a LLVM global.
 188       */
 189  
 190      debug!("register_foreign_item_fn(abi={}, \
 191              path={}, \
 192              foreign_item.id={})",
 193             abi.repr(ccx.tcx()),
 194             ccx.tcx.map.path_to_str(foreign_item.id),
 195             foreign_item.id);
 196  
 197      let cc = match llvm_calling_convention(ccx, abi) {
 198          Some(cc) => cc,
 199          None => {
 200              ccx.sess().span_fatal(foreign_item.span,
 201                  format!("ABI `{}` has no suitable calling convention \
 202                        for target architecture",
 203                        abi.user_string(ccx.tcx())));
 204          }
 205      };
 206  
 207      // Register the function as a C extern fn
 208      let lname = link_name(foreign_item);
 209      let tys = foreign_types_for_id(ccx, foreign_item.id);
 210  
 211      // Make sure the calling convention is right for variadic functions
 212      // (should've been caught if not in typeck)
 213      if tys.fn_sig.variadic {
 214          assert!(cc == lib::llvm::CCallConv);
 215      }
 216  
 217      // Create the LLVM value for the C extern fn
 218      let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
 219  
 220      let llfn = base::get_extern_fn(&mut *ccx.externs.borrow_mut(),
 221                                     ccx.llmod,
 222                                     lname.get(),
 223                                     cc,
 224                                     llfn_ty,
 225                                     tys.fn_sig.output);
 226      add_argument_attributes(&tys, llfn);
 227  
 228      llfn
 229  }
 230  
 231  pub fn trans_native_call<'a>(
 232                           bcx: &'a Block<'a>,
 233                           callee_tyty::t,
 234                           llfnValueRef,
 235                           llretptrValueRef,
 236                           llargs_rust: &[ValueRef],
 237                           passed_arg_tysVec<ty::t> )
 238                           -> &'a Block<'a> {
 239      /*!
 240       * Prepares a call to a native function. This requires adapting
 241       * from the Rust argument passing rules to the native rules.
 242       *
 243       * # Parameters
 244       *
 245       * - `callee_ty`: Rust type for the function we are calling
 246       * - `llfn`: the function pointer we are calling
 247       * - `llretptr`: where to store the return value of the function
 248       * - `llargs_rust`: a list of the argument values, prepared
 249       *   as they would be if calling a Rust function
 250       * - `passed_arg_tys`: Rust type for the arguments. Normally we
 251       *   can derive these from callee_ty but in the case of variadic
 252       *   functions passed_arg_tys will include the Rust type of all
 253       *   the arguments including the ones not specified in the fn's signature.
 254       */
 255  
 256      let ccx = bcx.ccx();
 257      let tcx = bcx.tcx();
 258  
 259      debug!("trans_native_call(callee_ty={}, \
 260              llfn={}, \
 261              llretptr={})",
 262             callee_ty.repr(tcx),
 263             ccx.tn.val_to_str(llfn),
 264             ccx.tn.val_to_str(llretptr));
 265  
 266      let (fn_abi, fn_sig) = match ty::get(callee_ty).sty {
 267          ty::ty_bare_fn(ref fn_ty) => (fn_ty.abi, fn_ty.sig.clone()),
 268          _ => ccx.sess().bug("trans_native_call called on non-function type")
 269      };
 270      let llsig = foreign_signature(ccx, &fn_sig, passed_arg_tys.as_slice());
 271      let ret_def = !return_type_is_void(bcx.ccx(), fn_sig.output);
 272      let fn_type = cabi::compute_abi_info(ccx,
 273                                           llsig.llarg_tys.as_slice(),
 274                                           llsig.llret_ty,
 275                                           ret_def);
 276  
 277      let arg_tys&[cabi::ArgType] = fn_type.arg_tys.as_slice();
 278  
 279      let mut llargs_foreign = Vec::new();
 280  
 281      // If the foreign ABI expects return value by pointer, supply the
 282      // pointer that Rust gave us. Sometimes we have to bitcast
 283      // because foreign fns return slightly different (but equivalent)
 284      // views on the same type (e.g., i64 in place of {i32,i32}).
 285      if fn_type.ret_ty.is_indirect() {
 286          match fn_type.ret_ty.cast {
 287              Some(ty) => {
 288                  let llcastedretptr =
 289                      BitCast(bcx, llretptr, ty.ptr_to());
 290                  llargs_foreign.push(llcastedretptr);
 291              }
 292              None => {
 293                  llargs_foreign.push(llretptr);
 294              }
 295          }
 296      }
 297  
 298      for (i, &llarg_rust) in llargs_rust.iter().enumerate() {
 299          let mut llarg_rust = llarg_rust;
 300  
 301          if arg_tys[i].is_ignore() {
 302              continue;
 303          }
 304  
 305          // Does Rust pass this argument by pointer?
 306          let rust_indirect = type_of::arg_is_indirect(ccx,
 307                                                       *passed_arg_tys.get(i));
 308  
 309          debug!("argument {}, llarg_rust={}, rust_indirect={}, arg_ty={}",
 310                 i,
 311                 ccx.tn.val_to_str(llarg_rust),
 312                 rust_indirect,
 313                 ccx.tn.type_to_str(arg_tys[i].ty));
 314  
 315          // Ensure that we always have the Rust value indirectly,
 316          // because it makes bitcasting easier.
 317          if !rust_indirect {
 318              let scratch =
 319                  base::alloca(bcx,
 320                               type_of::type_of(ccx, *passed_arg_tys.get(i)),
 321                               "__arg");
 322              Store(bcx, llarg_rust, scratch);
 323              llarg_rust = scratch;
 324          }
 325  
 326          debug!("llarg_rust={} (after indirection)",
 327                 ccx.tn.val_to_str(llarg_rust));
 328  
 329          // Check whether we need to do any casting
 330          match arg_tys[i].cast {
 331              Some(ty) => llarg_rust = BitCast(bcx, llarg_rust, ty.ptr_to()),
 332              None => ()
 333          }
 334  
 335          debug!("llarg_rust={} (after casting)",
 336                 ccx.tn.val_to_str(llarg_rust));
 337  
 338          // Finally, load the value if needed for the foreign ABI
 339          let foreign_indirect = arg_tys[i].is_indirect();
 340          let llarg_foreign = if foreign_indirect {
 341              llarg_rust
 342          } else {
 343              Load(bcx, llarg_rust)
 344          };
 345  
 346          debug!("argument {}, llarg_foreign={}",
 347                 i, ccx.tn.val_to_str(llarg_foreign));
 348  
 349          // fill padding with undef value
 350          match arg_tys[i].pad {
 351              Some(ty) => llargs_foreign.push(C_undef(ty)),
 352              None => ()
 353          }
 354          llargs_foreign.push(llarg_foreign);
 355      }
 356  
 357      let cc = match llvm_calling_convention(ccx, fn_abi) {
 358          Some(cc) => cc,
 359          None => {
 360              // FIXME(#8357) We really ought to report a span here
 361              ccx.sess().fatal(
 362                  format!("ABI string `{}` has no suitable ABI \
 363                          for target architecture",
 364                          fn_abi.user_string(ccx.tcx())));
 365          }
 366      };
 367  
 368      // A function pointer is called without the declaration available, so we have to apply
 369      // any attributes with ABI implications directly to the call instruction. Right now, the
 370      // only attribute we need to worry about is `sret`.
 371      let sret_attr = if fn_type.ret_ty.is_indirect() {
 372          Some((1, StructRetAttribute))
 373      } else {
 374          None
 375      };
 376      let attrs = sret_attr.as_slice();
 377      let llforeign_retval = CallWithConv(bcx,
 378                                          llfn,
 379                                          llargs_foreign.as_slice(),
 380                                          cc,
 381                                          attrs);
 382  
 383      // If the function we just called does not use an outpointer,
 384      // store the result into the rust outpointer. Cast the outpointer
 385      // type to match because some ABIs will use a different type than
 386      // the Rust type. e.g., a {u32,u32} struct could be returned as
 387      // u64.
 388      if ret_def && !fn_type.ret_ty.is_indirect() {
 389          let llrust_ret_ty = llsig.llret_ty;
 390          let llforeign_ret_ty = match fn_type.ret_ty.cast {
 391              Some(ty) => ty,
 392              None => fn_type.ret_ty.ty
 393          };
 394  
 395          debug!("llretptr={}", ccx.tn.val_to_str(llretptr));
 396          debug!("llforeign_retval={}", ccx.tn.val_to_str(llforeign_retval));
 397          debug!("llrust_ret_ty={}", ccx.tn.type_to_str(llrust_ret_ty));
 398          debug!("llforeign_ret_ty={}", ccx.tn.type_to_str(llforeign_ret_ty));
 399  
 400          if llrust_ret_ty == llforeign_ret_ty {
 401              Store(bcx, llforeign_retval, llretptr);
 402          } else {
 403              // The actual return type is a struct, but the ABI
 404              // adaptation code has cast it into some scalar type.  The
 405              // code that follows is the only reliable way I have
 406              // found to do a transform like i64 -> {i32,i32}.
 407              // Basically we dump the data onto the stack then memcpy it.
 408              //
 409              // Other approaches I tried:
 410              // - Casting rust ret pointer to the foreign type and using Store
 411              //   is (a) unsafe if size of foreign type > size of rust type and
 412              //   (b) runs afoul of strict aliasing rules, yielding invalid
 413              //   assembly under -O (specifically, the store gets removed).
 414              // - Truncating foreign type to correct integral type and then
 415              //   bitcasting to the struct type yields invalid cast errors.
 416              let llscratch = base::alloca(bcx, llforeign_ret_ty, "__cast");
 417              Store(bcx, llforeign_retval, llscratch);
 418              let llscratch_i8 = BitCast(bcx, llscratch, Type::i8(ccx).ptr_to());
 419              let llretptr_i8 = BitCast(bcx, llretptr, Type::i8(ccx).ptr_to());
 420              let llrust_size = machine::llsize_of_store(ccx, llrust_ret_ty);
 421              let llforeign_align = machine::llalign_of_min(ccx, llforeign_ret_ty);
 422              let llrust_align = machine::llalign_of_min(ccx, llrust_ret_ty);
 423              let llalign = cmp::min(llforeign_align, llrust_align);
 424              debug!("llrust_size={:?}", llrust_size);
 425              base::call_memcpy(bcx, llretptr_i8, llscratch_i8,
 426                                C_uint(ccx, llrust_size as uint), llalign as u32);
 427          }
 428      }
 429  
 430      return bcx;
 431  }
 432  
 433  pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) {
 434      let _icx = push_ctxt("foreign::trans_foreign_mod");
 435      for &foreign_item in foreign_mod.items.iter() {
 436          match foreign_item.node {
 437              ast::ForeignItemFn(..) => {
 438                  match foreign_mod.abi {
 439                      Rust | RustIntrinsic => {}
 440                      abi => { register_foreign_item_fn(ccx, abi, foreign_item); }
 441                  }
 442              }
 443              _ => {}
 444          }
 445  
 446          let lname = link_name(foreign_item);
 447          ccx.item_symbols.borrow_mut().insert(foreign_item.id,
 448                                               lname.get().to_owned());
 449      }
 450  }
 451  
 452  ///////////////////////////////////////////////////////////////////////////
 453  // Rust functions with foreign ABIs
 454  //
 455  // These are normal Rust functions defined with foreign ABIs.  For
 456  // now, and perhaps forever, we translate these using a "layer of
 457  // indirection". That is, given a Rust declaration like:
 458  //
 459  //     extern "C" fn foo(i: u32) -> u32 { ... }
 460  //
 461  // we will generate a function like:
 462  //
 463  //     S foo(T i) {
 464  //         S r;
 465  //         foo0(&r, NULL, i);
 466  //         return r;
 467  //     }
 468  //
 469  //     #[inline_always]
 470  //     void foo0(uint32_t *r, void *env, uint32_t i) { ... }
 471  //
 472  // Here the (internal) `foo0` function follows the Rust ABI as normal,
 473  // where the `foo` function follows the C ABI. We rely on LLVM to
 474  // inline the one into the other. Of course we could just generate the
 475  // correct code in the first place, but this is much simpler.
 476  
 477  pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext,
 478                                           spSpan,
 479                                           sym: ~str,
 480                                           node_idast::NodeId)
 481                                           -> ValueRef {
 482      let _icx = push_ctxt("foreign::register_foreign_fn");
 483  
 484      let tys = foreign_types_for_id(ccx, node_id);
 485      let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
 486      let t = ty::node_id_to_type(ccx.tcx(), node_id);
 487      let (cconv, output) = match ty::get(t).sty {
 488          ty::ty_bare_fn(ref fn_ty) => {
 489              let c = llvm_calling_convention(ccx, fn_ty.abi);
 490              (c.unwrap_or(lib::llvm::CCallConv), fn_ty.sig.output)
 491          }
 492          _ => fail!("expected bare fn in register_rust_fn_with_foreign_abi")
 493      };
 494      let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, cconv, llfn_ty, output);
 495      add_argument_attributes(&tys, llfn);
 496      debug!("register_rust_fn_with_foreign_abi(node_id={:?}, llfn_ty={}, llfn={})",
 497             node_id, ccx.tn.type_to_str(llfn_ty), ccx.tn.val_to_str(llfn));
 498      llfn
 499  }
 500  
 501  pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
 502                                        decl: &ast::FnDecl,
 503                                        body: &ast::Block,
 504                                        attrs: &[ast::Attribute],
 505                                        llwrapfnValueRef,
 506                                        idast::NodeId) {
 507      let _icx = push_ctxt("foreign::build_foreign_fn");
 508      let tys = foreign_types_for_id(ccx, id);
 509  
 510      unsafe { // unsafe because we call LLVM operations
 511          // Build up the Rust function (`foo0` above).
 512          let llrustfn = build_rust_fn(ccx, decl, body, attrs, id);
 513  
 514          // Build up the foreign wrapper (`foo` above).
 515          return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys);
 516      }
 517  
 518      fn build_rust_fn(ccx: &CrateContext,
 519                       decl: &ast::FnDecl,
 520                       body: &ast::Block,
 521                       attrs: &[ast::Attribute],
 522                       idast::NodeId)
 523                       -> ValueRef {
 524          let _icx = push_ctxt("foreign::foreign::build_rust_fn");
 525          let tcx = ccx.tcx();
 526          let t = ty::node_id_to_type(tcx, id);
 527  
 528          let ps = ccx.tcx.map.with_path(id, |path| {
 529              let abi = Some(ast_map::PathName(special_idents::clownshoe_abi.name));
 530              link::mangle(path.chain(abi.move_iter()), None, None)
 531          });
 532  
 533          // Compute the type that the function would have if it were just a
 534          // normal Rust function. This will be the type of the wrappee fn.
 535          let f = match ty::get(t).sty {
 536              ty::ty_bare_fn(ref f) => {
 537                  assert!(f.abi != Rust && f.abi != RustIntrinsic);
 538                  f
 539              }
 540              _ => {
 541                  ccx.sess().bug(format!("build_rust_fn: extern fn {} has ty {}, \
 542                                         expected a bare fn ty",
 543                                         ccx.tcx.map.path_to_str(id),
 544                                         t.repr(tcx)));
 545              }
 546          };
 547  
 548          debug!("build_rust_fn: path={} id={} t={}",
 549                 ccx.tcx.map.path_to_str(id),
 550                 id, t.repr(tcx));
 551  
 552          let llfn = base::decl_internal_rust_fn(ccx,
 553                                                 false,
 554                                                 f.sig.inputs.as_slice(),
 555                                                 f.sig.output,
 556                                                 ps);
 557          base::set_llvm_fn_attrs(attrs, llfn);
 558          base::trans_fn(ccx, decl, body, llfn, None, id, []);
 559          llfn
 560      }
 561  
 562      unsafe fn build_wrap_fn(ccx: &CrateContext,
 563                              llrustfnValueRef,
 564                              llwrapfnValueRef,
 565                              tys: &ForeignTypes) {
 566          let _icx = push_ctxt(
 567              "foreign::trans_rust_fn_with_foreign_abi::build_wrap_fn");
 568          let tcx = ccx.tcx();
 569  
 570          debug!("build_wrap_fn(llrustfn={}, llwrapfn={})",
 571                 ccx.tn.val_to_str(llrustfn),
 572                 ccx.tn.val_to_str(llwrapfn));
 573  
 574          // Avoid all the Rust generation stuff and just generate raw
 575          // LLVM here.
 576          //
 577          // We want to generate code like this:
 578          //
 579          //     S foo(T i) {
 580          //         S r;
 581          //         foo0(&r, NULL, i);
 582          //         return r;
 583          //     }
 584  
 585          let the_block =
 586              "the block".with_c_str(
 587                  |s| llvm::LLVMAppendBasicBlockInContext(ccx.llcx, llwrapfn, s));
 588  
 589          let builder = ccx.builder.b;
 590          llvm::LLVMPositionBuilderAtEnd(builder, the_block);
 591  
 592          // Array for the arguments we will pass to the rust function.
 593          let mut llrust_args = Vec::new();
 594          let mut next_foreign_arg_counterc_uint = 0;
 595          let next_foreign_arg|pad: bool| -> c_uint = |padbool{
 596              next_foreign_arg_counter += if pad {
 597                  2
 598              } else {
 599                  1
 600              };
 601              next_foreign_arg_counter - 1
 602          };
 603  
 604          // If there is an out pointer on the foreign function
 605          let foreign_outptr = {
 606              if tys.fn_ty.ret_ty.is_indirect() {
 607                  Some(llvm::LLVMGetParam(llwrapfn, next_foreign_arg(false)))
 608              } else {
 609                  None
 610              }
 611          };
 612  
 613          // Push Rust return pointer, using null if it will be unused.
 614          let rust_uses_outptr =
 615              type_of::return_uses_outptr(ccx, tys.fn_sig.output);
 616          let return_allocaOption<ValueRef>;
 617          let llrust_ret_ty = tys.llsig.llret_ty;
 618          let llrust_retptr_ty = llrust_ret_ty.ptr_to();
 619          if rust_uses_outptr {
 620              // Rust expects to use an outpointer. If the foreign fn
 621              // also uses an outpointer, we can reuse it, but the types
 622              // may vary, so cast first to the Rust type. If the
 623              // foreign fn does NOT use an outpointer, we will have to
 624              // alloca some scratch space on the stack.
 625              match foreign_outptr {
 626                  Some(llforeign_outptr) => {
 627                      debug!("out pointer, foreign={}",
 628                             ccx.tn.val_to_str(llforeign_outptr));
 629                      let llrust_retptr =
 630                          llvm::LLVMBuildBitCast(builder,
 631                                                 llforeign_outptr,
 632                                                 llrust_ret_ty.ptr_to().to_ref(),
 633                                                 noname());
 634                      debug!("out pointer, foreign={} (casted)",
 635                             ccx.tn.val_to_str(llrust_retptr));
 636                      llrust_args.push(llrust_retptr);
 637                      return_alloca = None;
 638                  }
 639  
 640                  None => {
 641                      let slot = {
 642                          "return_alloca".with_c_str(
 643                              |s| llvm::LLVMBuildAlloca(builder,
 644                                                        llrust_ret_ty.to_ref(),
 645                                                        s))
 646                      };
 647                      debug!("out pointer, \
 648                              allocad={}, \
 649                              llrust_ret_ty={}, \
 650                              return_ty={}",
 651                             ccx.tn.val_to_str(slot),
 652                             ccx.tn.type_to_str(llrust_ret_ty),
 653                             tys.fn_sig.output.repr(tcx));
 654                      llrust_args.push(slot);
 655                      return_alloca = Some(slot);
 656                  }
 657              }
 658          } else {
 659              // Rust does not expect an outpointer. If the foreign fn
 660              // does use an outpointer, then we will do a store of the
 661              // value that the Rust fn returns.
 662              return_alloca = None;
 663          };
 664  
 665          // Build up the arguments to the call to the rust function.
 666          // Careful to adapt for cases where the native convention uses
 667          // a pointer and Rust does not or vice versa.
 668          for i in range(0, tys.fn_sig.inputs.len()) {
 669              let rust_ty = *tys.fn_sig.inputs.get(i);
 670              let llrust_ty = *tys.llsig.llarg_tys.get(i);
 671              let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty);
 672              let llforeign_arg_ty = *tys.fn_ty.arg_tys.get(i);
 673              let foreign_indirect = llforeign_arg_ty.is_indirect();
 674  
 675              // skip padding
 676              let foreign_index = next_foreign_arg(llforeign_arg_ty.pad.is_some());
 677              let mut llforeign_arg = llvm::LLVMGetParam(llwrapfn, foreign_index);
 678  
 679              debug!("llforeign_arg \\#{}{}",
 680                     i, ccx.tn.val_to_str(llforeign_arg));
 681              debug!("rust_indirect = {}, foreign_indirect = {}",
 682                     rust_indirect, foreign_indirect);
 683  
 684              // Ensure that the foreign argument is indirect (by
 685              // pointer).  It makes adapting types easier, since we can
 686              // always just bitcast pointers.
 687              if !foreign_indirect {
 688                  let lltemp =
 689                      llvm::LLVMBuildAlloca(
 690                          builder, val_ty(llforeign_arg).to_ref(), noname());
 691                  llvm::LLVMBuildStore(
 692                      builder, llforeign_arg, lltemp);
 693                  llforeign_arg = lltemp;
 694              }
 695  
 696              // If the types in the ABI and the Rust types don't match,
 697              // bitcast the llforeign_arg pointer so it matches the types
 698              // Rust expects.
 699              if llforeign_arg_ty.cast.is_some() {
 700                  assert!(!foreign_indirect);
 701                  llforeign_arg = llvm::LLVMBuildBitCast(
 702                      builder, llforeign_arg,
 703                      llrust_ty.ptr_to().to_ref(), noname());
 704              }
 705  
 706              let llrust_arg = if rust_indirect {
 707                  llforeign_arg
 708              } else {
 709                  llvm::LLVMBuildLoad(builder, llforeign_arg, noname())
 710              };
 711  
 712              debug!("llrust_arg \\#{}{}",
 713                     i, ccx.tn.val_to_str(llrust_arg));
 714              llrust_args.push(llrust_arg);
 715          }
 716  
 717          // Perform the call itself
 718          debug!("calling llrustfn = {}", ccx.tn.val_to_str(llrustfn));
 719          let llrust_ret_val = llvm::LLVMBuildCall(builder, llrustfn, llrust_args.as_ptr(),
 720                                                   llrust_args.len() as c_uint, noname());
 721  
 722          // Get the return value where the foreign fn expects it.
 723          let llforeign_ret_ty = match tys.fn_ty.ret_ty.cast {
 724              Some(ty) => ty,
 725              None => tys.fn_ty.ret_ty.ty
 726          };
 727          match foreign_outptr {
 728              None if !tys.ret_def => {
 729                  // Function returns `()` or `bot`, which in Rust is the LLVM
 730                  // type "{}" but in foreign ABIs is "Void".
 731                  llvm::LLVMBuildRetVoid(builder);
 732              }
 733  
 734              None if rust_uses_outptr => {
 735                  // Rust uses an outpointer, but the foreign ABI does not. Load.
 736                  let llrust_outptr = return_alloca.unwrap();
 737                  let llforeign_outptr_casted =
 738                      llvm::LLVMBuildBitCast(builder,
 739                                             llrust_outptr,
 740                                             llforeign_ret_ty.ptr_to().to_ref(),
 741                                             noname());
 742                  let llforeign_retval =
 743                      llvm::LLVMBuildLoad(builder, llforeign_outptr_casted, noname());
 744                  llvm::LLVMBuildRet(builder, llforeign_retval);
 745              }
 746  
 747              None if llforeign_ret_ty != llrust_ret_ty => {
 748                  // Neither ABI uses an outpointer, but the types don't
 749                  // quite match. Must cast. Probably we should try and
 750                  // examine the types and use a concrete llvm cast, but
 751                  // right now we just use a temp memory location and
 752                  // bitcast the pointer, which is the same thing the
 753                  // old wrappers used to do.
 754                  let lltemp =
 755                      llvm::LLVMBuildAlloca(
 756                          builder, llforeign_ret_ty.to_ref(), noname());
 757                  let lltemp_casted =
 758                      llvm::LLVMBuildBitCast(builder,
 759                                             lltemp,
 760                                             llrust_ret_ty.ptr_to().to_ref(),
 761                                             noname());
 762                  llvm::LLVMBuildStore(
 763                      builder, llrust_ret_val, lltemp_casted);
 764                  let llforeign_retval =
 765                      llvm::LLVMBuildLoad(builder, lltemp, noname());
 766                  llvm::LLVMBuildRet(builder, llforeign_retval);
 767              }
 768  
 769              None => {
 770                  // Neither ABI uses an outpointer, and the types
 771                  // match. Easy peasy.
 772                  llvm::LLVMBuildRet(builder, llrust_ret_val);
 773              }
 774  
 775              Some(llforeign_outptr) if !rust_uses_outptr => {
 776                  // Foreign ABI requires an out pointer, but Rust doesn't.
 777                  // Store Rust return value.
 778                  let llforeign_outptr_casted =
 779                      llvm::LLVMBuildBitCast(builder,
 780                                             llforeign_outptr,
 781                                             llrust_retptr_ty.to_ref(),
 782                                             noname());
 783                  llvm::LLVMBuildStore(
 784                      builder, llrust_ret_val, llforeign_outptr_casted);
 785                  llvm::LLVMBuildRetVoid(builder);
 786              }
 787  
 788              Some(_) => {
 789                  // Both ABIs use outpointers. Easy peasy.
 790                  llvm::LLVMBuildRetVoid(builder);
 791              }
 792          }
 793      }
 794  }
 795  
 796  ///////////////////////////////////////////////////////////////////////////
 797  // General ABI Support
 798  //
 799  // This code is kind of a confused mess and needs to be reworked given
 800  // the massive simplifications that have occurred.
 801  
 802  pub fn link_name(i: &ast::ForeignItem) -> InternedString {
 803       match attr::first_attr_value_str_by_name(i.attrs.as_slice(),
 804                                                "link_name") {
 805          None => token::get_ident(i.ident),
 806          Some(ln) => ln.clone(),
 807      }
 808  }
 809  
 810  fn foreign_signature(ccx: &CrateContext, fn_sig: &ty::FnSig, arg_tys: &[ty::t])
 811                       -> LlvmSignature {
 812      /*!
 813       * The ForeignSignature is the LLVM types of the arguments/return type
 814       * of a function.  Note that these LLVM types are not quite the same
 815       * as the LLVM types would be for a native Rust function because foreign
 816       * functions just plain ignore modes.  They also don't pass aggregate
 817       * values by pointer like we do.
 818       */
 819  
 820      let llarg_tys = arg_tys.iter().map(|&arg| type_of(ccx, arg)).collect();
 821      let llret_ty = type_of::type_of(ccx, fn_sig.output);
 822      LlvmSignature {
 823          llarg_tys: llarg_tys,
 824          llret_ty: llret_ty,
 825          sret: type_of::return_uses_outptr(ccx, fn_sig.output),
 826      }
 827  }
 828  
 829  fn foreign_types_for_id(ccx: &CrateContext,
 830                          idast::NodeId) -> ForeignTypes {
 831      foreign_types_for_fn_ty(ccx, ty::node_id_to_type(ccx.tcx(), id))
 832  }
 833  
 834  fn foreign_types_for_fn_ty(ccx: &CrateContext,
 835                             tyty::t) -> ForeignTypes {
 836      let fn_sig = match ty::get(ty).sty {
 837          ty::ty_bare_fn(ref fn_ty) => fn_ty.sig.clone(),
 838          _ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type")
 839      };
 840      let llsig = foreign_signature(ccx, &fn_sig, fn_sig.inputs.as_slice());
 841      let ret_def = !return_type_is_void(ccx, fn_sig.output);
 842      let fn_ty = cabi::compute_abi_info(ccx,
 843                                         llsig.llarg_tys.as_slice(),
 844                                         llsig.llret_ty,
 845                                         ret_def);
 846      debug!("foreign_types_for_fn_ty(\
 847             ty={}, \
 848             llsig={} -> {}, \
 849             fn_ty={} -> {}, \
 850             ret_def={}",
 851             ty.repr(ccx.tcx()),
 852             ccx.tn.types_to_str(llsig.llarg_tys.as_slice()),
 853             ccx.tn.type_to_str(llsig.llret_ty),
 854             ccx.tn.types_to_str(fn_ty.arg_tys.iter().map(|t| t.ty).collect::<Vec<_>>().as_slice()),
 855             ccx.tn.type_to_str(fn_ty.ret_ty.ty),
 856             ret_def);
 857  
 858      ForeignTypes {
 859          fn_sig: fn_sig,
 860          llsig: llsig,
 861          ret_def: ret_def,
 862          fn_ty: fn_ty
 863      }
 864  }
 865  
 866  fn lltype_for_fn_from_foreign_types(ccx: &CrateContext, tys: &ForeignTypes) -> Type {
 867      let mut llargument_tys = Vec::new();
 868  
 869      let ret_ty = tys.fn_ty.ret_ty;
 870      let llreturn_ty = if ret_ty.is_indirect() {
 871          llargument_tys.push(ret_ty.ty.ptr_to());
 872          Type::void(ccx)
 873      } else {
 874          match ret_ty.cast {
 875              Some(ty) => ty,
 876              None => ret_ty.ty
 877          }
 878      };
 879  
 880      for &arg_ty in tys.fn_ty.arg_tys.iter() {
 881          if arg_ty.is_ignore() {
 882              continue;
 883          }
 884          // add padding
 885          match arg_ty.pad {
 886              Some(ty) => llargument_tys.push(ty),
 887              None => ()
 888          }
 889  
 890          let llarg_ty = if arg_ty.is_indirect() {
 891              arg_ty.ty.ptr_to()
 892          } else {
 893              match arg_ty.cast {
 894                  Some(ty) => ty,
 895                  None => arg_ty.ty
 896              }
 897          };
 898  
 899          llargument_tys.push(llarg_ty);
 900      }
 901  
 902      if tys.fn_sig.variadic {
 903          Type::variadic_func(llargument_tys.as_slice(), &llreturn_ty)
 904      } else {
 905          Type::func(llargument_tys.as_slice(), &llreturn_ty)
 906      }
 907  }
 908  
 909  pub fn lltype_for_foreign_fn(ccx: &CrateContext, tyty::t) -> Type {
 910      lltype_for_fn_from_foreign_types(ccx, &foreign_types_for_fn_ty(ccx, ty))
 911  }
 912  
 913  fn add_argument_attributes(tys: &ForeignTypes,
 914                             llfnValueRef) {
 915      let mut i = 0;
 916  
 917      if tys.fn_ty.ret_ty.is_indirect() {
 918          match tys.fn_ty.ret_ty.attr {
 919              Some(attr) => {
 920                  let llarg = get_param(llfn, i);
 921                  unsafe {
 922                      llvm::LLVMAddAttribute(llarg, attr as c_uint);
 923                  }
 924              }
 925              None => {}
 926          }
 927  
 928          i += 1;
 929      }
 930  
 931      for &arg_ty in tys.fn_ty.arg_tys.iter() {
 932          if arg_ty.is_ignore() {
 933              continue;
 934          }
 935          // skip padding
 936          if arg_ty.pad.is_some() { i += 1; }
 937  
 938          match arg_ty.attr {
 939              Some(attr) => {
 940                  let llarg = get_param(llfn, i);
 941                  unsafe {
 942                      llvm::LLVMAddAttribute(llarg, attr as c_uint);
 943                  }
 944              }
 945              None => ()
 946          }
 947  
 948          i += 1;
 949      }
 950  }


librustc/middle/trans/foreign.rs:828:1-828:1 -fn- definition:
fn foreign_types_for_id(ccx: &CrateContext,
                        id: ast::NodeId) -> ForeignTypes {
    foreign_types_for_fn_ty(ccx, ty::node_id_to_type(ccx.tcx(), id))
references:- 3
484:     let tys = foreign_types_for_id(ccx, node_id);
485:     let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
--
507:     let _icx = push_ctxt("foreign::build_foreign_fn");
508:     let tys = foreign_types_for_id(ccx, id);


librustc/middle/trans/foreign.rs:912:1-912:1 -fn- definition:
fn add_argument_attributes(tys: &ForeignTypes,
                           llfn: ValueRef) {
    let mut i = 0;
references:- 2
225:                                    tys.fn_sig.output);
226:     add_argument_attributes(&tys, llfn);
--
494:     let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, cconv, llfn_ty, output);
495:     add_argument_attributes(&tys, llfn);
496:     debug!("register_rust_fn_with_foreign_abi(node_id={:?}, llfn_ty={}, llfn={})",


librustc/middle/trans/foreign.rs:833:1-833:1 -fn- definition:
fn foreign_types_for_fn_ty(ccx: &CrateContext,
                           ty: ty::t) -> ForeignTypes {
    let fn_sig = match ty::get(ty).sty {
references:- 2
909: pub fn lltype_for_foreign_fn(ccx: &CrateContext, ty: ty::t) -> Type {
910:     lltype_for_fn_from_foreign_types(ccx, &foreign_types_for_fn_ty(ccx, ty))
911: }


librustc/middle/trans/foreign.rs:801:1-801:1 -fn- definition:
pub fn link_name(i: &ast::ForeignItem) -> InternedString {
     match attr::first_attr_value_str_by_name(i.attrs.as_slice(),
                                              "link_name") {
references:- 3
137:     let ident = link_name(foreign_item);
138:     match attr::first_attr_value_str_by_name(foreign_item.attrs.as_slice(),
--
446:         let lname = link_name(foreign_item);
447:         ccx.item_symbols.borrow_mut().insert(foreign_item.id,


librustc/middle/trans/foreign.rs:56:1-56:1 -struct- definition:
struct LlvmSignature {
    // LLVM versions of the types of this function's arguments.
    llarg_tys: Vec<Type> ,
references:- 3
821:     let llret_ty = type_of::type_of(ccx, fn_sig.output);
822:     LlvmSignature {
823:         llarg_tys: llarg_tys,


librustc/middle/trans/foreign.rs:182:1-182:1 -fn- definition:
pub fn register_foreign_item_fn(ccx: &CrateContext, abi: Abi,
                                foreign_item: &ast::ForeignItem) -> ValueRef {
    /*!
references:- 2
librustc/middle/trans/base.rs:
1991:                     let abi = ccx.tcx.map.get_foreign_abi(id);
1992:                     foreign::register_foreign_item_fn(ccx, abi, ni)
1993:                 }
librustc/middle/trans/foreign.rs:
439:                     Rust | RustIntrinsic => {}
440:                     abi => { register_foreign_item_fn(ccx, abi, foreign_item); }
441:                 }


librustc/middle/trans/foreign.rs:809:1-809:1 -fn- definition:
fn foreign_signature(ccx: &CrateContext, fn_sig: &ty::FnSig, arg_tys: &[ty::t])
                     -> LlvmSignature {
    /*!
references:- 2
839:     };
840:     let llsig = foreign_signature(ccx, &fn_sig, fn_sig.inputs.as_slice());
841:     let ret_def = !return_type_is_void(ccx, fn_sig.output);


librustc/middle/trans/foreign.rs:865:1-865:1 -fn- definition:
fn lltype_for_fn_from_foreign_types(ccx: &CrateContext, tys: &ForeignTypes) -> Type {
    let mut llargument_tys = Vec::new();
    let ret_ty = tys.fn_ty.ret_ty;
references:- 3
217:     // Create the LLVM value for the C extern fn
218:     let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
--
484:     let tys = foreign_types_for_id(ccx, node_id);
485:     let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
486:     let t = ty::node_id_to_type(ccx.tcx(), node_id);
--
909: pub fn lltype_for_foreign_fn(ccx: &CrateContext, ty: ty::t) -> Type {
910:     lltype_for_fn_from_foreign_types(ccx, &foreign_types_for_fn_ty(ccx, ty))
911: }


librustc/middle/trans/foreign.rs:41:1-41:1 -struct- definition:
struct ForeignTypes {
    /// Rust signature of the function
    fn_sig: ty::FnSig,
references:- 6
858:     ForeignTypes {
859:         fn_sig: fn_sig,
--
913: fn add_argument_attributes(tys: &ForeignTypes,
914:                            llfn: ValueRef) {


librustc/middle/trans/foreign.rs:74:1-74:1 -fn- definition:
pub fn llvm_calling_convention(ccx: &CrateContext,
                               abi: Abi) -> Option<CallConv> {
    let os = ccx.sess().targ_cfg.os;
references:- 4
488:         ty::ty_bare_fn(ref fn_ty) => {
489:             let c = llvm_calling_convention(ccx, fn_ty.abi);
490:             (c.unwrap_or(lib::llvm::CCallConv), fn_ty.sig.output)
librustc/middle/trans/base.rs:
858:                 Some(..) | None => {
859:                     let c = foreign::llvm_calling_convention(ccx, fn_ty.abi);
860:                     let cconv = c.unwrap_or(lib::llvm::CCallConv);
librustc/middle/trans/foreign.rs:
197:     let cc = match llvm_calling_convention(ccx, abi) {
198:         Some(cc) => cc,