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