]>
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 | ||
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 { | |
62682a34 SL |
48 | bcx = callee::trans_arg_datum(bcx, |
49 | expr_ty(bcx, &**out), | |
50 | out_datum, | |
51 | cleanup::CustomScope(temp_scope), | |
52 | callee::DontAutorefArg, | |
53 | &mut ext_inputs); | |
1a4d82fc JJ |
54 | ext_constraints.push(i.to_string()); |
55 | } | |
56 | val | |
57 | ||
58 | }).collect::<Vec<_>>(); | |
59 | ||
60 | // Now the input operands | |
62682a34 SL |
61 | let mut inputs = Vec::new(); |
62 | for &(ref c, ref input) in &ia.inputs { | |
1a4d82fc JJ |
63 | constraints.push((*c).clone()); |
64 | ||
65 | let in_datum = unpack_datum!(bcx, expr::trans(bcx, &**input)); | |
62682a34 | 66 | bcx = callee::trans_arg_datum(bcx, |
1a4d82fc JJ |
67 | expr_ty(bcx, &**input), |
68 | in_datum, | |
69 | cleanup::CustomScope(temp_scope), | |
62682a34 SL |
70 | callee::DontAutorefArg, |
71 | &mut inputs); | |
72 | } | |
85aaf69f | 73 | inputs.push_all(&ext_inputs[..]); |
1a4d82fc JJ |
74 | |
75 | // no failure occurred preparing operands, no need to cleanup | |
76 | fcx.pop_custom_cleanup_scope(temp_scope); | |
77 | ||
c34b1796 AL |
78 | let clobbers = ia.clobbers.iter() |
79 | .map(|s| format!("~{{{}}}", &s)); | |
80 | ||
81 | // Default per-arch clobbers | |
82 | // Basically what clang does | |
83 | let arch_clobbers = match &bcx.sess().target.target.arch[..] { | |
84 | "x86" | "x86_64" => vec!("~{dirflag}", "~{fpsr}", "~{flags}"), | |
85 | _ => Vec::new() | |
86 | }; | |
1a4d82fc | 87 | |
c34b1796 AL |
88 | let all_constraints= constraints.iter() |
89 | .map(|s| s.to_string()) | |
62682a34 | 90 | .chain(ext_constraints) |
c34b1796 AL |
91 | .chain(clobbers) |
92 | .chain(arch_clobbers.iter() | |
93 | .map(|s| s.to_string())) | |
94 | .collect::<Vec<String>>() | |
95 | .connect(","); | |
1a4d82fc | 96 | |
c34b1796 | 97 | debug!("Asm Constraints: {}", &all_constraints[..]); |
1a4d82fc JJ |
98 | |
99 | // Depending on how many outputs we have, the return type is different | |
c34b1796 AL |
100 | let num_outputs = outputs.len(); |
101 | let output_type = match num_outputs { | |
102 | 0 => Type::void(bcx.ccx()), | |
103 | 1 => output_types[0], | |
104 | _ => Type::struct_(bcx.ccx(), &output_types[..], false) | |
1a4d82fc JJ |
105 | }; |
106 | ||
107 | let dialect = match ia.dialect { | |
108 | ast::AsmAtt => llvm::AD_ATT, | |
109 | ast::AsmIntel => llvm::AD_Intel | |
110 | }; | |
111 | ||
85aaf69f | 112 | let asm = CString::new(ia.asm.as_bytes()).unwrap(); |
c34b1796 | 113 | let constraint_cstr = CString::new(all_constraints).unwrap(); |
1a4d82fc JJ |
114 | let r = InlineAsmCall(bcx, |
115 | asm.as_ptr(), | |
c34b1796 | 116 | constraint_cstr.as_ptr(), |
85aaf69f | 117 | &inputs, |
1a4d82fc JJ |
118 | output_type, |
119 | ia.volatile, | |
120 | ia.alignstack, | |
121 | dialect); | |
122 | ||
123 | // Again, based on how many outputs we have | |
124 | if num_outputs == 1 { | |
125 | Store(bcx, r, outputs[0]); | |
126 | } else { | |
127 | for (i, o) in outputs.iter().enumerate() { | |
128 | let v = ExtractValue(bcx, r, i); | |
129 | Store(bcx, v, *o); | |
130 | } | |
131 | } | |
132 | ||
133 | // Store expn_id in a metadata node so we can map LLVM errors | |
134 | // back to source locations. See #17552. | |
135 | unsafe { | |
136 | let key = "srcloc"; | |
137 | let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx().llcx(), | |
138 | key.as_ptr() as *const c_char, key.len() as c_uint); | |
139 | ||
d9579d0f | 140 | let val: llvm::ValueRef = C_i32(bcx.ccx(), ia.expn_id.into_u32() as i32); |
1a4d82fc JJ |
141 | |
142 | llvm::LLVMSetMetadata(r, kind, | |
143 | llvm::LLVMMDNodeInContext(bcx.ccx().llcx(), &val, 1)); | |
144 | } | |
145 | ||
146 | return bcx; | |
147 | ||
148 | } | |
149 |