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