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.
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.
12 # Translation of inline assembly.
15 use std::c_str::ToCStr;
18 use middle::trans::build::*;
19 use middle::trans::callee;
20 use middle::trans::common::*;
23 use middle::trans::type_::Type;
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 {
31 let mut constraints = ~[];
32 let mut cleanups = ~[];
33 let mut aoutputs = ~[];
35 // Prepare the output operands
36 let outputs = do ia.outputs.map |&(c, out)| {
39 aoutputs.push(unpack_result!(bcx, {
40 callee::trans_arg_expr(bcx,
45 callee::DontAutorefArg)
48 let e = match out.node {
49 ast::expr_addr_of(_, e) => e,
50 _ => fail!("Expression must be addr of")
54 callee::trans_arg_expr(bcx,
59 callee::DontAutorefArg)
64 for c in cleanups.iter() {
65 revoke_clean(bcx, *c);
69 // Now the input operands
70 let inputs = do ia.inputs.map |&(c, input)| {
74 callee::trans_arg_expr(bcx,
79 callee::DontAutorefArg)
84 for c in cleanups.iter() {
85 revoke_clean(bcx, *c);
88 let mut constraints = constraints.connect(",");
90 let mut clobbers = getClobbers();
91 if !ia.clobbers.is_empty() && !clobbers.is_empty() {
92 clobbers = fmt!("%s,%s", ia.clobbers, clobbers);
94 clobbers.push_str(ia.clobbers);
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);
102 constraints.push_str(clobbers);
105 debug!("Asm Constraints: %?", constraints);
107 let numOutputs = outputs.len();
109 // Depending on how many outputs we have, the return type is different
110 let output = if numOutputs == 0 {
112 } else if numOutputs == 1 {
115 Type::struct_(outputs.map(|o| val_ty(*o)), false)
118 let dialect = match ia.dialect {
119 ast::asm_att => lib::llvm::AD_ATT,
120 ast::asm_intel => lib::llvm::AD_Intel
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)
129 // Again, based on how many outputs we have
131 let op = PointerCast(bcx, aoutputs[0], val_ty(outputs[0]).ptr_to());
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());
145 // Default per-arch clobbers
146 // Basically what clang does
148 #[cfg(target_arch = "arm")]
149 #[cfg(target_arch = "mips")]
150 fn getClobbers() -> ~str {
154 #[cfg(target_arch = "x86")]
155 #[cfg(target_arch = "x86_64")]
156 fn getClobbers() -> ~str {
157 ~"~{dirflag},~{fpsr},~{flags}"