]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/asm.rs
b6057199a280fbccddba02aefe60d7b20f42c5f7
[rust.git] / src / librustc / middle / trans / asm.rs
1 // Copyright 2012-2013 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 /*!
12 # Translation of inline assembly.
13 */
14
15 use std::c_str::ToCStr;
16
17 use lib;
18 use middle::trans::build::*;
19 use middle::trans::callee;
20 use middle::trans::common::*;
21 use middle::ty;
22
23 use middle::trans::type_::Type;
24
25 use syntax::ast;
26
27 // Take an inline assembly expression and splat it out via LLVM
28 pub fn trans_inline_asm(bcx: @mut Block, ia: &ast::inline_asm) -> @mut Block {
29
30     let mut bcx = bcx;
31     let mut constraints = ~[];
32     let mut cleanups = ~[];
33     let mut aoutputs = ~[];
34
35     // Prepare the output operands
36     let outputs = do ia.outputs.map |&(c, out)| {
37         constraints.push(c);
38
39         aoutputs.push(unpack_result!(bcx, {
40             callee::trans_arg_expr(bcx,
41                                    expr_ty(bcx, out),
42                                    ty::ByCopy,
43                                    out,
44                                    &mut cleanups,
45                                    callee::DontAutorefArg)
46         }));
47
48         let e = match out.node {
49             ast::expr_addr_of(_, e) => e,
50             _ => fail!("Expression must be addr of")
51         };
52
53         unpack_result!(bcx, {
54             callee::trans_arg_expr(bcx,
55                                    expr_ty(bcx, e),
56                                    ty::ByCopy,
57                                    e,
58                                    &mut cleanups,
59                                    callee::DontAutorefArg)
60         })
61
62     };
63
64     for c in cleanups.iter() {
65         revoke_clean(bcx, *c);
66     }
67     cleanups.clear();
68
69     // Now the input operands
70     let inputs = do ia.inputs.map |&(c, input)| {
71         constraints.push(c);
72
73         unpack_result!(bcx, {
74             callee::trans_arg_expr(bcx,
75                                    expr_ty(bcx, input),
76                                    ty::ByCopy,
77                                    input,
78                                    &mut cleanups,
79                                    callee::DontAutorefArg)
80         })
81
82     };
83
84     for c in cleanups.iter() {
85         revoke_clean(bcx, *c);
86     }
87
88     let mut constraints = constraints.connect(",");
89
90     let mut clobbers = getClobbers();
91     if !ia.clobbers.is_empty() && !clobbers.is_empty() {
92         clobbers = fmt!("%s,%s", ia.clobbers, clobbers);
93     } else {
94         clobbers.push_str(ia.clobbers);
95     };
96
97     // Add the clobbers to our constraints list
98     if clobbers.len() != 0 && constraints.len() != 0 {
99         constraints.push_char(',');
100         constraints.push_str(clobbers);
101     } else {
102         constraints.push_str(clobbers);
103     }
104
105     debug!("Asm Constraints: %?", constraints);
106
107     let numOutputs = outputs.len();
108
109     // Depending on how many outputs we have, the return type is different
110     let output = if numOutputs == 0 {
111         Type::void()
112     } else if numOutputs == 1 {
113         val_ty(outputs[0])
114     } else {
115         Type::struct_(outputs.map(|o| val_ty(*o)), false)
116     };
117
118     let dialect = match ia.dialect {
119         ast::asm_att   => lib::llvm::AD_ATT,
120         ast::asm_intel => lib::llvm::AD_Intel
121     };
122
123     let r = do ia.asm.to_c_str().with_ref |a| {
124         do constraints.to_c_str().with_ref |c| {
125             InlineAsmCall(bcx, a, c, inputs, output, ia.volatile, ia.alignstack, dialect)
126         }
127     };
128
129     // Again, based on how many outputs we have
130     if numOutputs == 1 {
131         let op = PointerCast(bcx, aoutputs[0], val_ty(outputs[0]).ptr_to());
132         Store(bcx, r, op);
133     } else {
134         for (i, o) in aoutputs.iter().enumerate() {
135             let v = ExtractValue(bcx, r, i);
136             let op = PointerCast(bcx, *o, val_ty(outputs[i]).ptr_to());
137             Store(bcx, v, op);
138         }
139     }
140
141     return bcx;
142
143 }
144
145 // Default per-arch clobbers
146 // Basically what clang does
147
148 #[cfg(target_arch = "arm")]
149 #[cfg(target_arch = "mips")]
150 fn getClobbers() -> ~str {
151     ~""
152 }
153
154 #[cfg(target_arch = "x86")]
155 #[cfg(target_arch = "x86_64")]
156 fn getClobbers() -> ~str {
157     ~"~{dirflag},~{fpsr},~{flags}"
158 }