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