--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+# Translation of inline assembly.
+*/
+
+use core::prelude::*;
+
+use lib;
+use middle::trans::build::*;
+use middle::trans::callee;
+use middle::trans::common::*;
+use middle::ty;
+
+use syntax::ast;
+use syntax::ast::*;
+
+// Take an inline assembly expression and splat it out via LLVM
+pub fn trans_inline_asm(bcx: block, asm: @~str, ins: &[(@~str, @expr)], outs: &[(@~str, @expr)],
+ clobs: @~str, volatile: bool, alignstack: bool) -> block {
+
+ let mut bcx = bcx;
+ let mut constraints = ~[];
+ let mut cleanups = ~[];
+ let mut aoutputs = ~[];
+
+ // Prepare the output operands
+ let outputs = do outs.map |&(c, out)| {
+ constraints.push(copy *c);
+
+ let aoutty = ty::arg {
+ mode: ast::expl(ast::by_copy),
+ ty: expr_ty(bcx, out)
+ };
+ aoutputs.push(unpack_result!(bcx, {
+ callee::trans_arg_expr(bcx, aoutty, out, &mut cleanups, None, callee::DontAutorefArg)
+ }));
+
+ let e = match out.node {
+ ast::expr_addr_of(_, e) => e,
+ _ => fail!(~"Expression must be addr of")
+ };
+
+ let outty = ty::arg {
+ mode: ast::expl(ast::by_copy),
+ ty: expr_ty(bcx, e)
+ };
+
+ unpack_result!(bcx, {
+ callee::trans_arg_expr(bcx, outty, e, &mut cleanups, None, callee::DontAutorefArg)
+ })
+
+ };
+
+ for cleanups.each |c| {
+ revoke_clean(bcx, *c);
+ }
+ cleanups.clear();
+
+ // Now the input operands
+ let inputs = do ins.map |&(c, in)| {
+ constraints.push(copy *c);
+
+ let inty = ty::arg {
+ mode: ast::expl(ast::by_copy),
+ ty: expr_ty(bcx, in)
+ };
+
+ unpack_result!(bcx, {
+ callee::trans_arg_expr(bcx, inty, in, &mut cleanups, None, callee::DontAutorefArg)
+ })
+
+ };
+
+ for cleanups.each |c| {
+ revoke_clean(bcx, *c);
+ }
+
+ let mut constraints = str::connect(constraints, ",");
+
+ // Add the clobbers to our constraints list
+ if *clobs != ~"" && constraints != ~"" {
+ constraints += ~"," + *clobs;
+ } else {
+ constraints += *clobs;
+ }
+
+ debug!("Asm Constraints: %?", constraints);
+
+ let numOutputs = outputs.len();
+
+ // Depending on how many outputs we have, the return type is different
+ let output = if numOutputs == 0 {
+ T_void()
+ } else if numOutputs == 1 {
+ val_ty(outputs[0])
+ } else {
+ T_struct(outputs.map(|o| val_ty(*o)))
+ };
+
+ let r = do str::as_c_str(*asm) |a| {
+ do str::as_c_str(constraints) |c| {
+ // XXX: Allow selection of at&t or intel
+ InlineAsmCall(bcx, a, c, inputs, output, volatile, alignstack, lib::llvm::AD_ATT)
+ }
+ };
+
+ // Again, based on how many outputs we have
+ if numOutputs == 1 {
+ let op = PointerCast(bcx, aoutputs[0], T_ptr(val_ty(outputs[0])));
+ Store(bcx, r, op);
+ } else {
+ for aoutputs.eachi |i, o| {
+ let v = ExtractValue(bcx, r, i);
+ let op = PointerCast(bcx, *o, T_ptr(val_ty(outputs[i])));
+ Store(bcx, v, op);
+ }
+ }
+
+ return bcx;
+
+}
use middle::borrowck::root_map_key;
use middle::trans::_match;
use middle::trans::adt;
+use middle::trans::asm;
use middle::trans::base;
use middle::trans::base::*;
use middle::trans::build::*;
}
ast::expr_inline_asm(asm, ref ins, ref outs,
clobs, volatile, alignstack) => {
- let mut constraints = ~[];
- let mut cleanups = ~[];
- let mut aoutputs = ~[];
-
- let outputs = do outs.map |&(c, out)| {
- constraints.push(copy *c);
-
- let aoutty = ty::arg {
- mode: ast::expl(ast::by_copy),
- ty: expr_ty(bcx, out)
- };
- aoutputs.push(unpack_result!(bcx, {
- callee::trans_arg_expr(bcx, aoutty, out, &mut cleanups,
- None, callee::DontAutorefArg)
- }));
-
- let e = match out.node {
- ast::expr_addr_of(_, e) => e,
- _ => fail!(~"Expression must be addr of")
- };
-
- let outty = ty::arg {
- mode: ast::expl(ast::by_copy),
- ty: expr_ty(bcx, e)
- };
-
- unpack_result!(bcx, {
- callee::trans_arg_expr(bcx, outty, e, &mut cleanups,
- None, callee::DontAutorefArg)
- })
-
- };
-
- for cleanups.each |c| {
- revoke_clean(bcx, *c);
- }
- cleanups = ~[];
-
- let inputs = do ins.map |&(c, in)| {
- constraints.push(copy *c);
-
- let inty = ty::arg {
- mode: ast::expl(ast::by_copy),
- ty: expr_ty(bcx, in)
- };
-
- unpack_result!(bcx, {
- callee::trans_arg_expr(bcx, inty, in, &mut cleanups,
- None, callee::DontAutorefArg)
- })
-
- };
-
- for cleanups.each |c| {
- revoke_clean(bcx, *c);
- }
-
- let mut constraints = str::connect(constraints, ",");
-
- // Add the clobbers
- if *clobs != ~"" {
- if constraints == ~"" {
- constraints += *clobs;
- } else {
- constraints += ~"," + *clobs;
- }
- } else {
- constraints += *clobs;
- }
-
- debug!("Asm Constraints: %?", constraints);
-
- let output = if outputs.len() == 0 {
- T_void()
- } else if outputs.len() == 1 {
- val_ty(outputs[0])
- } else {
- T_struct(outputs.map(|o| val_ty(*o)))
- };
-
- let r = do str::as_c_str(*asm) |a| {
- do str::as_c_str(constraints) |c| {
- InlineAsmCall(bcx, a, c, inputs, output, volatile,
- alignstack, lib::llvm::AD_ATT)
- }
- };
-
- if outputs.len() == 1 {
- let op = PointerCast(bcx, aoutputs[0],
- T_ptr(val_ty(outputs[0])));
- Store(bcx, r, op);
- } else {
- for aoutputs.eachi |i, o| {
- let v = ExtractValue(bcx, r, i);
- let op = PointerCast(bcx, *o, T_ptr(val_ty(outputs[i])));
- Store(bcx, v, op);
- }
- }
-
- return bcx;
+ return asm::trans_inline_asm(bcx, asm, *ins, *outs, clobs, volatile, alignstack);
}
_ => {
bcx.tcx().sess.span_bug(