]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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 | ||
e9174d1e | 23 | use rustc_front::hir as ast; |
1a4d82fc | 24 | use std::ffi::CString; |
b039eaaf | 25 | use syntax::ast::AsmDialect; |
1a4d82fc JJ |
26 | use libc::{c_uint, c_char}; |
27 | ||
28 | // Take an inline assembly expression and splat it out via LLVM | |
29 | pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm) | |
30 | -> Block<'blk, 'tcx> { | |
31 | let fcx = bcx.fcx; | |
32 | let mut bcx = bcx; | |
33 | let mut constraints = Vec::new(); | |
34 | let mut output_types = Vec::new(); | |
35 | ||
36 | let temp_scope = fcx.push_custom_cleanup_scope(); | |
37 | ||
38 | let mut ext_inputs = Vec::new(); | |
39 | let mut ext_constraints = Vec::new(); | |
40 | ||
41 | // Prepare the output operands | |
9cc50fc6 SL |
42 | let mut outputs = Vec::new(); |
43 | let mut inputs = Vec::new(); | |
44 | for (i, out) in ia.outputs.iter().enumerate() { | |
45 | constraints.push(out.constraint.clone()); | |
1a4d82fc | 46 | |
7453a54e | 47 | let out_datum = unpack_datum!(bcx, expr::trans(bcx, &out.expr)); |
9cc50fc6 | 48 | if out.is_indirect { |
62682a34 | 49 | bcx = callee::trans_arg_datum(bcx, |
7453a54e | 50 | expr_ty(bcx, &out.expr), |
62682a34 SL |
51 | out_datum, |
52 | cleanup::CustomScope(temp_scope), | |
53 | callee::DontAutorefArg, | |
9cc50fc6 SL |
54 | &mut inputs); |
55 | if out.is_rw { | |
56 | ext_inputs.push(*inputs.last().unwrap()); | |
57 | ext_constraints.push(i.to_string()); | |
58 | } | |
59 | } else { | |
60 | output_types.push(type_of::type_of(bcx.ccx(), out_datum.ty)); | |
61 | outputs.push(out_datum.val); | |
62 | if out.is_rw { | |
63 | bcx = callee::trans_arg_datum(bcx, | |
7453a54e | 64 | expr_ty(bcx, &out.expr), |
9cc50fc6 SL |
65 | out_datum, |
66 | cleanup::CustomScope(temp_scope), | |
67 | callee::DontAutorefArg, | |
68 | &mut ext_inputs); | |
69 | ext_constraints.push(i.to_string()); | |
70 | } | |
1a4d82fc | 71 | } |
9cc50fc6 | 72 | } |
1a4d82fc JJ |
73 | |
74 | // Now the input operands | |
62682a34 | 75 | for &(ref c, ref input) in &ia.inputs { |
1a4d82fc JJ |
76 | constraints.push((*c).clone()); |
77 | ||
7453a54e | 78 | let in_datum = unpack_datum!(bcx, expr::trans(bcx, &input)); |
62682a34 | 79 | bcx = callee::trans_arg_datum(bcx, |
7453a54e | 80 | expr_ty(bcx, &input), |
1a4d82fc JJ |
81 | in_datum, |
82 | cleanup::CustomScope(temp_scope), | |
62682a34 SL |
83 | callee::DontAutorefArg, |
84 | &mut inputs); | |
85 | } | |
92a42be0 | 86 | inputs.extend_from_slice(&ext_inputs[..]); |
1a4d82fc JJ |
87 | |
88 | // no failure occurred preparing operands, no need to cleanup | |
89 | fcx.pop_custom_cleanup_scope(temp_scope); | |
90 | ||
c34b1796 AL |
91 | let clobbers = ia.clobbers.iter() |
92 | .map(|s| format!("~{{{}}}", &s)); | |
93 | ||
94 | // Default per-arch clobbers | |
95 | // Basically what clang does | |
96 | let arch_clobbers = match &bcx.sess().target.target.arch[..] { | |
97 | "x86" | "x86_64" => vec!("~{dirflag}", "~{fpsr}", "~{flags}"), | |
98 | _ => Vec::new() | |
99 | }; | |
1a4d82fc | 100 | |
c34b1796 AL |
101 | let all_constraints= constraints.iter() |
102 | .map(|s| s.to_string()) | |
62682a34 | 103 | .chain(ext_constraints) |
c34b1796 AL |
104 | .chain(clobbers) |
105 | .chain(arch_clobbers.iter() | |
106 | .map(|s| s.to_string())) | |
107 | .collect::<Vec<String>>() | |
c1a9b12d | 108 | .join(","); |
1a4d82fc | 109 | |
c34b1796 | 110 | debug!("Asm Constraints: {}", &all_constraints[..]); |
1a4d82fc JJ |
111 | |
112 | // Depending on how many outputs we have, the return type is different | |
c34b1796 AL |
113 | let num_outputs = outputs.len(); |
114 | let output_type = match num_outputs { | |
115 | 0 => Type::void(bcx.ccx()), | |
116 | 1 => output_types[0], | |
117 | _ => Type::struct_(bcx.ccx(), &output_types[..], false) | |
1a4d82fc JJ |
118 | }; |
119 | ||
120 | let dialect = match ia.dialect { | |
b039eaaf SL |
121 | AsmDialect::Att => llvm::AD_ATT, |
122 | AsmDialect::Intel => llvm::AD_Intel | |
1a4d82fc JJ |
123 | }; |
124 | ||
85aaf69f | 125 | let asm = CString::new(ia.asm.as_bytes()).unwrap(); |
c34b1796 | 126 | let constraint_cstr = CString::new(all_constraints).unwrap(); |
1a4d82fc JJ |
127 | let r = InlineAsmCall(bcx, |
128 | asm.as_ptr(), | |
c34b1796 | 129 | constraint_cstr.as_ptr(), |
85aaf69f | 130 | &inputs, |
1a4d82fc JJ |
131 | output_type, |
132 | ia.volatile, | |
133 | ia.alignstack, | |
134 | dialect); | |
135 | ||
136 | // Again, based on how many outputs we have | |
137 | if num_outputs == 1 { | |
138 | Store(bcx, r, outputs[0]); | |
139 | } else { | |
140 | for (i, o) in outputs.iter().enumerate() { | |
141 | let v = ExtractValue(bcx, r, i); | |
142 | Store(bcx, v, *o); | |
143 | } | |
144 | } | |
145 | ||
146 | // Store expn_id in a metadata node so we can map LLVM errors | |
147 | // back to source locations. See #17552. | |
148 | unsafe { | |
149 | let key = "srcloc"; | |
150 | let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx().llcx(), | |
151 | key.as_ptr() as *const c_char, key.len() as c_uint); | |
152 | ||
d9579d0f | 153 | let val: llvm::ValueRef = C_i32(bcx.ccx(), ia.expn_id.into_u32() as i32); |
1a4d82fc JJ |
154 | |
155 | llvm::LLVMSetMetadata(r, kind, | |
156 | llvm::LLVMMDNodeInContext(bcx.ccx().llcx(), &val, 1)); | |
157 | } | |
158 | ||
159 | return bcx; | |
160 | ||
161 | } |