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