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

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Sat Apr 19 11:22:39 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  # Translation of inline assembly.
  13  */
  14  
  15  use lib;
  16  use middle::trans::build::*;
  17  use middle::trans::callee;
  18  use middle::trans::common::*;
  19  use middle::trans::cleanup;
  20  use middle::trans::cleanup::CleanupMethods;
  21  use middle::trans::expr;
  22  use middle::trans::type_of;
  23  use middle::trans::type_::Type;
  24  
  25  use std::c_str::ToCStr;
  26  use std::strbuf::StrBuf;
  27  use syntax::ast;
  28  
  29  // Take an inline assembly expression and splat it out via LLVM
  30  pub fn trans_inline_asm<'a>(bcx: &'a Block<'a>, ia: &ast::InlineAsm)
  31                          -> &'a Block<'a> {
  32      let fcx = bcx.fcx;
  33      let mut bcx = bcx;
  34      let mut constraints = Vec::new();
  35      let mut output_types = Vec::new();
  36  
  37      let temp_scope = fcx.push_custom_cleanup_scope();
  38  
  39      // Prepare the output operands
  40      let outputs = ia.outputs.iter().map(|&(ref c, out)| {
  41          constraints.push((*c).clone());
  42  
  43          let out_datum = unpack_datum!(bcx, expr::trans(bcx, out));
  44          output_types.push(type_of::type_of(bcx.ccx(), out_datum.ty));
  45          out_datum.val
  46  
  47      }).collect::<Vec<_>>();
  48  
  49      // Now the input operands
  50      let inputs = ia.inputs.iter().map(|&(ref c, input)| {
  51          constraints.push((*c).clone());
  52  
  53          let in_datum = unpack_datum!(bcx, expr::trans(bcx, input));
  54          unpack_result!(bcx, {
  55              callee::trans_arg_datum(bcx,
  56                                     expr_ty(bcx, input),
  57                                     in_datum,
  58                                     cleanup::CustomScope(temp_scope),
  59                                     callee::DontAutorefArg)
  60          })
  61      }).collect::<Vec<_>>();
  62  
  63      // no failure occurred preparing operands, no need to cleanup
  64      fcx.pop_custom_cleanup_scope(temp_scope);
  65  
  66      let mut constraints =
  67          StrBuf::from_str(constraints.iter()
  68                                      .map(|s| s.get().to_str())
  69                                      .collect::<Vec<~str>>()
  70                                      .connect(","));
  71  
  72      let mut clobbers = StrBuf::from_str(getClobbers());
  73      if !ia.clobbers.get().is_empty() && !clobbers.is_empty() {
  74          clobbers = StrBuf::from_owned_str(format!("{},{}",
  75                                                    ia.clobbers.get(),
  76                                                    clobbers));
  77      } else {
  78          clobbers.push_str(ia.clobbers.get());
  79      }
  80  
  81      // Add the clobbers to our constraints list
  82      if clobbers.len() != 0 && constraints.len() != 0 {
  83          constraints.push_char(',');
  84          constraints.push_str(clobbers.as_slice());
  85      } else {
  86          constraints.push_str(clobbers.as_slice());
  87      }
  88  
  89      debug!("Asm Constraints: {:?}", constraints.as_slice());
  90  
  91      let num_outputs = outputs.len();
  92  
  93      // Depending on how many outputs we have, the return type is different
  94      let output_type = if num_outputs == 0 {
  95          Type::void(bcx.ccx())
  96      } else if num_outputs == 1 {
  97          *output_types.get(0)
  98      } else {
  99          Type::struct_(bcx.ccx(), output_types.as_slice(), false)
 100      };
 101  
 102      let dialect = match ia.dialect {
 103          ast::AsmAtt   => lib::llvm::AD_ATT,
 104          ast::AsmIntel => lib::llvm::AD_Intel
 105      };
 106  
 107      let r = ia.asm.get().with_c_str(|a| {
 108          constraints.as_slice().with_c_str(|c| {
 109              InlineAsmCall(bcx,
 110                            a,
 111                            c,
 112                            inputs.as_slice(),
 113                            output_type,
 114                            ia.volatile,
 115                            ia.alignstack,
 116                            dialect)
 117          })
 118      });
 119  
 120      // Again, based on how many outputs we have
 121      if num_outputs == 1 {
 122          Store(bcx, r, *outputs.get(0));
 123      } else {
 124          for (i, o) in outputs.iter().enumerate() {
 125              let v = ExtractValue(bcx, r, i);
 126              Store(bcx, v, *o);
 127          }
 128      }
 129  
 130      return bcx;
 131  
 132  }
 133  
 134  // Default per-arch clobbers
 135  // Basically what clang does
 136  
 137  #[cfg(target_arch = "arm")]
 138  #[cfg(target_arch = "mips")]
 139  fn getClobbers() -> ~str {
 140      "".to_owned()
 141  }
 142  
 143  #[cfg(target_arch = "x86")]
 144  #[cfg(target_arch = "x86_64")]
 145  fn getClobbers() -> ~str {
 146      "~{dirflag},~{fpsr},~{flags}".to_owned()
 147  }