]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/asm.rs
Auto merge of #22517 - brson:relnotes, r=Gankro
[rust.git] / src / librustc_trans / trans / asm.rs
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.
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 //! # Translation of inline assembly.
12
13 use llvm;
14 use trans::build::*;
15 use trans::callee;
16 use trans::common::*;
17 use trans::cleanup;
18 use trans::cleanup::CleanupMethods;
19 use trans::expr;
20 use trans::type_of;
21 use trans::type_::Type;
22
23 use syntax::ast;
24 use std::ffi::CString;
25 use libc::{c_uint, c_char};
26
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> {
30     let fcx = bcx.fcx;
31     let mut bcx = bcx;
32     let mut constraints = Vec::new();
33     let mut output_types = Vec::new();
34
35     let temp_scope = fcx.push_custom_cleanup_scope();
36
37     let mut ext_inputs = Vec::new();
38     let mut ext_constraints = Vec::new();
39
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());
43
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;
47         if is_rw {
48             ext_inputs.push(unpack_result!(bcx, {
49                 callee::trans_arg_datum(bcx,
50                                        expr_ty(bcx, &**out),
51                                        out_datum,
52                                        cleanup::CustomScope(temp_scope),
53                                        callee::DontAutorefArg)
54             }));
55             ext_constraints.push(i.to_string());
56         }
57         val
58
59     }).collect::<Vec<_>>();
60
61     // Now the input operands
62     let mut inputs = ia.inputs.iter().map(|&(ref c, ref input)| {
63         constraints.push((*c).clone());
64
65         let in_datum = unpack_datum!(bcx, expr::trans(bcx, &**input));
66         unpack_result!(bcx, {
67             callee::trans_arg_datum(bcx,
68                                     expr_ty(bcx, &**input),
69                                     in_datum,
70                                     cleanup::CustomScope(temp_scope),
71                                     callee::DontAutorefArg)
72         })
73     }).collect::<Vec<_>>();
74     inputs.push_all(&ext_inputs[]);
75
76     // no failure occurred preparing operands, no need to cleanup
77     fcx.pop_custom_cleanup_scope(temp_scope);
78
79     let mut constraints = constraints.iter()
80                                      .map(|s| s.to_string())
81                                      .chain(ext_constraints.into_iter())
82                                      .collect::<Vec<String>>()
83                                      .connect(",");
84
85     let mut clobbers = ia.clobbers.iter()
86                                   .map(|s| format!("~{{{}}}", &s))
87                                   .collect::<Vec<String>>()
88                                   .connect(",");
89     let more_clobbers = get_clobbers();
90     if !more_clobbers.is_empty() {
91         if !clobbers.is_empty() {
92             clobbers.push(',');
93         }
94         clobbers.push_str(&more_clobbers[]);
95     }
96
97     // Add the clobbers to our constraints list
98     if clobbers.len() != 0 && constraints.len() != 0 {
99         constraints.push(',');
100         constraints.push_str(&clobbers[]);
101     } else {
102         constraints.push_str(&clobbers[]);
103     }
104
105     debug!("Asm Constraints: {}", &constraints[]);
106
107     let num_outputs = outputs.len();
108
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 {
113         output_types[0]
114     } else {
115         Type::struct_(bcx.ccx(), &output_types[], false)
116     };
117
118     let dialect = match ia.dialect {
119         ast::AsmAtt   => llvm::AD_ATT,
120         ast::AsmIntel => llvm::AD_Intel
121     };
122
123     let asm = CString::from_slice(ia.asm.as_bytes());
124     let constraints = CString::from_slice(constraints.as_bytes());
125     let r = InlineAsmCall(bcx,
126                           asm.as_ptr(),
127                           constraints.as_ptr(),
128                           &inputs,
129                           output_type,
130                           ia.volatile,
131                           ia.alignstack,
132                           dialect);
133
134     // Again, based on how many outputs we have
135     if num_outputs == 1 {
136         Store(bcx, r, outputs[0]);
137     } else {
138         for (i, o) in outputs.iter().enumerate() {
139             let v = ExtractValue(bcx, r, i);
140             Store(bcx, v, *o);
141         }
142     }
143
144     // Store expn_id in a metadata node so we can map LLVM errors
145     // back to source locations.  See #17552.
146     unsafe {
147         let key = "srcloc";
148         let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx().llcx(),
149             key.as_ptr() as *const c_char, key.len() as c_uint);
150
151         let val: llvm::ValueRef = C_i32(bcx.ccx(), ia.expn_id.to_llvm_cookie());
152
153         llvm::LLVMSetMetadata(r, kind,
154             llvm::LLVMMDNodeInContext(bcx.ccx().llcx(), &val, 1));
155     }
156
157     return bcx;
158
159 }
160
161 // Default per-arch clobbers
162 // Basically what clang does
163
164 #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
165 fn get_clobbers() -> String {
166     "".to_string()
167 }
168
169 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
170 fn get_clobbers() -> String {
171     "~{dirflag},~{fpsr},~{flags}".to_string()
172 }