1 // Copyright 2012-2015 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.
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.
11 //! # Translation of inline assembly.
18 use trans::cleanup::CleanupMethods;
21 use trans::type_::Type;
24 use std::ffi::CString;
25 use libc::{c_uint, c_char};
27 // Take an inline assembly expression and splat it out via LLVM
28 pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
29 -> Block<'blk, 'tcx> {
32 let mut constraints = Vec::new();
33 let mut output_types = Vec::new();
35 let temp_scope = fcx.push_custom_cleanup_scope();
37 let mut ext_inputs = Vec::new();
38 let mut ext_constraints = Vec::new();
40 // Prepare the output operands
41 let outputs = ia.outputs.iter().enumerate().map(|(i, &(ref c, ref out, is_rw))| {
42 constraints.push((*c).clone());
44 let out_datum = unpack_datum!(bcx, expr::trans(bcx, &**out));
45 output_types.push(type_of::type_of(bcx.ccx(), out_datum.ty));
46 let val = out_datum.val;
48 ext_inputs.push(unpack_result!(bcx, {
49 callee::trans_arg_datum(bcx,
52 cleanup::CustomScope(temp_scope),
53 callee::DontAutorefArg)
55 ext_constraints.push(i.to_string());
59 }).collect::<Vec<_>>();
61 // Now the input operands
62 let mut inputs = ia.inputs.iter().map(|&(ref c, ref input)| {
63 constraints.push((*c).clone());
65 let in_datum = unpack_datum!(bcx, expr::trans(bcx, &**input));
67 callee::trans_arg_datum(bcx,
68 expr_ty(bcx, &**input),
70 cleanup::CustomScope(temp_scope),
71 callee::DontAutorefArg)
73 }).collect::<Vec<_>>();
74 inputs.push_all(&ext_inputs[]);
76 // no failure occurred preparing operands, no need to cleanup
77 fcx.pop_custom_cleanup_scope(temp_scope);
79 let mut constraints = constraints.iter()
80 .map(|s| s.to_string())
81 .chain(ext_constraints.into_iter())
82 .collect::<Vec<String>>()
85 let mut clobbers = ia.clobbers.iter()
86 .map(|s| format!("~{{{}}}", &s))
87 .collect::<Vec<String>>()
89 let more_clobbers = get_clobbers();
90 if !more_clobbers.is_empty() {
91 if !clobbers.is_empty() {
94 clobbers.push_str(&more_clobbers[]);
97 // Add the clobbers to our constraints list
98 if clobbers.len() != 0 && constraints.len() != 0 {
99 constraints.push(',');
100 constraints.push_str(&clobbers[]);
102 constraints.push_str(&clobbers[]);
105 debug!("Asm Constraints: {}", &constraints[]);
107 let num_outputs = outputs.len();
109 // Depending on how many outputs we have, the return type is different
110 let output_type = if num_outputs == 0 {
111 Type::void(bcx.ccx())
112 } else if num_outputs == 1 {
115 Type::struct_(bcx.ccx(), &output_types[], false)
118 let dialect = match ia.dialect {
119 ast::AsmAtt => llvm::AD_ATT,
120 ast::AsmIntel => llvm::AD_Intel
123 let asm = CString::from_slice(ia.asm.as_bytes());
124 let constraints = CString::from_slice(constraints.as_bytes());
125 let r = InlineAsmCall(bcx,
127 constraints.as_ptr(),
134 // Again, based on how many outputs we have
135 if num_outputs == 1 {
136 Store(bcx, r, outputs[0]);
138 for (i, o) in outputs.iter().enumerate() {
139 let v = ExtractValue(bcx, r, i);
144 // Store expn_id in a metadata node so we can map LLVM errors
145 // back to source locations. See #17552.
148 let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx().llcx(),
149 key.as_ptr() as *const c_char, key.len() as c_uint);
151 let val: llvm::ValueRef = C_i32(bcx.ccx(), ia.expn_id.to_llvm_cookie());
153 llvm::LLVMSetMetadata(r, kind,
154 llvm::LLVMMDNodeInContext(bcx.ccx().llcx(), &val, 1));
161 // Default per-arch clobbers
162 // Basically what clang does
164 #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
165 fn get_clobbers() -> String {
169 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
170 fn get_clobbers() -> String {
171 "~{dirflag},~{fpsr},~{flags}".to_string()