ast::ExprInlineAsm(ref inline_asm) => {
let inputs = inline_asm.inputs.iter();
let outputs = inline_asm.outputs.iter();
- fn extract_expr<A>(&(_, expr): &(A, Gc<ast::Expr>)) -> Gc<ast::Expr> { expr }
let post_inputs = self.exprs(inputs.map(|a| {
debug!("cfg::construct InlineAsm id:{} input:{:?}", expr.id, a);
- extract_expr(a)
+ let &(_, expr) = a;
+ expr
}), pred);
let post_outputs = self.exprs(outputs.map(|a| {
debug!("cfg::construct InlineAsm id:{} output:{:?}", expr.id, a);
- extract_expr(a)
+ let &(_, expr, _) = a;
+ expr
}), post_inputs);
self.add_node(expr.id, [post_outputs])
}
self.consume_expr(&**input);
}
- for &(_, ref output) in ia.outputs.iter() {
- self.mutate_expr(expr, &**output, JustWrite);
+ for &(_, ref output, is_rw) in ia.outputs.iter() {
+ self.mutate_expr(expr, &**output,
+ if is_rw { WriteAndRead } else { JustWrite });
}
}
}
ExprInlineAsm(ref ia) => {
- let succ = ia.outputs.iter().rev().fold(succ, |succ, &(_, ref expr)| {
- // see comment on lvalues in
- // propagate_through_lvalue_components()
+
+ let succ = ia.outputs.iter().rev().fold(succ, |succ, &(_, ref expr, _)| {
+ // see comment on lvalues
+ // in propagate_through_lvalue_components()
let succ = self.write_lvalue(&**expr, succ, ACC_WRITE);
self.propagate_through_lvalue_components(&**expr, succ)
});
}
// Output operands must be lvalues
- for &(_, ref out) in ia.outputs.iter() {
+ for &(_, ref out, _) in ia.outputs.iter() {
this.check_lvalue(&**out);
this.visit_expr(&**out, ());
}
let temp_scope = fcx.push_custom_cleanup_scope();
+ let mut ext_inputs = Vec::new();
+ let mut ext_constraints = Vec::new();
+
// Prepare the output operands
- let outputs = ia.outputs.iter().map(|&(ref c, ref out)| {
+ let outputs = ia.outputs.iter().enumerate().map(|(i, &(ref c, ref out, is_rw))| {
constraints.push((*c).clone());
let out_datum = unpack_datum!(bcx, expr::trans(bcx, &**out));
output_types.push(type_of::type_of(bcx.ccx(), out_datum.ty));
- out_datum.val
+ let val = out_datum.val;
+ if is_rw {
+ ext_inputs.push(unpack_result!(bcx, {
+ callee::trans_arg_datum(bcx,
+ expr_ty(bcx, &**out),
+ out_datum,
+ cleanup::CustomScope(temp_scope),
+ callee::DontAutorefArg)
+ }));
+ ext_constraints.push(i.to_string());
+ }
+ val
}).collect::<Vec<_>>();
cleanup::CustomScope(temp_scope),
callee::DontAutorefArg)
})
- }).collect::<Vec<_>>();
+ }).collect::<Vec<_>>().append(ext_inputs.as_slice());
// no failure occurred preparing operands, no need to cleanup
fcx.pop_custom_cleanup_scope(temp_scope);
let mut constraints =
String::from_str(constraints.iter()
.map(|s| s.get().to_string())
+ .chain(ext_constraints.move_iter())
.collect::<Vec<String>>()
.connect(",")
.as_slice());
walk_expr(cx, &**exp, scope_stack, scope_map);
}
- for &(_, ref exp) in outputs.iter() {
+ for &(_, ref exp, _) in outputs.iter() {
walk_expr(cx, &**exp, scope_stack, scope_map);
}
}
for &(_, ref input) in ia.inputs.iter() {
check_expr(fcx, &**input);
}
- for &(_, ref out) in ia.outputs.iter() {
+ for &(_, ref out, _) in ia.outputs.iter() {
check_expr(fcx, &**out);
}
fcx.write_nil(id);
pub struct InlineAsm {
pub asm: InternedString,
pub asm_str_style: StrStyle,
- pub clobbers: InternedString,
+ pub outputs: Vec<(InternedString, Gc<Expr>, bool)>,
pub inputs: Vec<(InternedString, Gc<Expr>)>,
- pub outputs: Vec<(InternedString, Gc<Expr>)>,
+ pub clobbers: InternedString,
pub volatile: bool,
pub alignstack: bool,
pub dialect: AsmDialect
let mut state = Asm;
- let mut read_write_operands = Vec::new();
-
'statement: loop {
match state {
Asm => {
let output = match constraint.get().slice_shift_char() {
(Some('='), _) => None,
(Some('+'), operand) => {
- // Save a reference to the output
- read_write_operands.push((outputs.len(), out));
Some(token::intern_and_get_ident(format!(
"={}",
operand).as_slice()))
}
};
- outputs.push((output.unwrap_or(constraint), out));
+ let is_rw = output.is_some();
+ outputs.push((output.unwrap_or(constraint), out, is_rw));
}
}
Inputs => {
}
}
- // Append an input operand, with the form of ("0", expr)
- // that links to an output operand.
- for &(i, out) in read_write_operands.iter() {
- inputs.push((token::intern_and_get_ident(i.to_string().as_slice()),
- out));
- }
-
MacExpr::new(box(GC) ast::Expr {
id: ast::DUMMY_NODE_ID,
node: ast::ExprInlineAsm(ast::InlineAsm {
asm: token::intern_and_get_ident(asm.get()),
asm_str_style: asm_str_style.unwrap(),
- clobbers: token::intern_and_get_ident(cons.as_slice()),
- inputs: inputs,
outputs: outputs,
+ inputs: inputs,
+ clobbers: token::intern_and_get_ident(cons.as_slice()),
volatile: volatile,
alignstack: alignstack,
dialect: dialect
inputs: a.inputs.iter().map(|&(ref c, input)| {
((*c).clone(), folder.fold_expr(input))
}).collect(),
- outputs: a.outputs.iter().map(|&(ref c, out)| {
- ((*c).clone(), folder.fold_expr(out))
+ outputs: a.outputs.iter().map(|&(ref c, out, is_rw)| {
+ ((*c).clone(), folder.fold_expr(out), is_rw)
}).collect(),
.. (*a).clone()
})
try!(self.word_space(":"));
try!(self.commasep(Inconsistent, a.outputs.as_slice(),
- |s, &(ref co, ref o)| {
- try!(s.print_string(co.get(), ast::CookedStr));
+ |s, &(ref co, ref o, is_rw)| {
+ match co.get().slice_shift_char() {
+ (Some('='), operand) if is_rw => {
+ try!(s.print_string(format!("+{}", operand).as_slice(),
+ ast::CookedStr))
+ }
+ _ => try!(s.print_string(co.get(), ast::CookedStr))
+ }
try!(s.popen());
try!(s.print_expr(&**o));
try!(s.pclose());
ExprParen(ref subexpression) => {
visitor.visit_expr(&**subexpression, env.clone())
}
- ExprInlineAsm(ref assembler) => {
- for &(_, ref input) in assembler.inputs.iter() {
+ ExprInlineAsm(ref ia) => {
+ for &(_, ref input) in ia.inputs.iter() {
visitor.visit_expr(&**input, env.clone())
}
- for &(_, ref output) in assembler.outputs.iter() {
+ for &(_, ref output, _) in ia.outputs.iter() {
visitor.visit_expr(&**output, env.clone())
}
}
--- /dev/null
+// Copyright 2012-2014 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.
+
+#![feature(asm, macro_rules)]
+
+type History = Vec<&'static str>;
+
+fn wrap<A>(x:A, which: &'static str, history: &mut History) -> A {
+ history.push(which);
+ x
+}
+
+macro_rules! demo {
+ ( $output_constraint:tt ) => {
+ {
+ let mut x: int = 0;
+ let y: int = 1;
+
+ let mut history: History = vec!();
+ unsafe {
+ asm!("mov ($1), $0"
+ : $output_constraint (*wrap(&mut x, "out", &mut history))
+ : "r"(&wrap(y, "in", &mut history)));
+ }
+ assert_eq!((x,y), (1,1));
+ assert_eq!(history.as_slice(), &["out", "in"]);
+ }
+ }
+}
+
+#[cfg(target_arch = "x86")]
+#[cfg(target_arch = "x86_64")]
+fn main() {
+ fn out_write_only_expr_then_in_expr() {
+ demo!("=r")
+ }
+
+ fn out_read_write_expr_then_in_expr() {
+ demo!("+r")
+ }
+
+ out_write_only_expr_then_in_expr();
+ out_read_write_expr_then_in_expr();
+}
+
+#[cfg(not(target_arch = "x86"), not(target_arch = "x86_64"))]
+pub fn main() {}