}), pred);
let post_outputs = self.exprs(outputs.map(|a| {
debug!("cfg::construct InlineAsm id:{} output:{:?}", expr.id, a);
- let &(_, ref expr, _) = a;
+ let &(_, ref expr, _, _) = a;
&**expr
}), post_inputs);
self.add_ast_node(expr.id, &[post_outputs])
self.consume_expr(&**input);
}
- for &(_, ref output, is_rw) in &ia.outputs {
- self.mutate_expr(expr, &**output,
+ for &(_, ref output, is_rw, is_indirect) in &ia.outputs {
+ if is_indirect {
+ self.consume_expr(&**output);
+ } else {
+ self.mutate_expr(expr, &**output,
if is_rw { WriteAndRead } else { JustWrite });
+ }
}
}
hir::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 = self.write_lvalue(&**expr, succ, ACC_WRITE);
- self.propagate_through_lvalue_components(&**expr, succ)
- });
+ let succ = ia.outputs.iter().rev().fold(succ,
+ |succ, &(_, ref expr, _, is_indirect)| {
+ // see comment on lvalues
+ // in propagate_through_lvalue_components()
+ if is_indirect {
+ self.propagate_through_expr(&**expr, succ)
+ } else {
+ let succ = self.write_lvalue(&**expr, succ, ACC_WRITE);
+ self.propagate_through_lvalue_components(&**expr, succ)
+ }
+ }
+ );
// Inputs are executed first. Propagate last because of rev order
ia.inputs.iter().rev().fold(succ, |succ, &(_, ref expr)| {
self.propagate_through_expr(&**expr, succ)
}
// Output operands must be lvalues
- for &(_, ref out, _) in &ia.outputs {
- this.check_lvalue(&**out);
+ for &(_, ref out, _, is_indirect) in &ia.outputs {
+ if !is_indirect {
+ this.check_lvalue(&**out);
+ }
this.visit_expr(&**out);
}
expn_id,
}) => ExprInlineAsm(InlineAsm {
inputs: inputs.move_map(|(c, input)| (c, folder.fold_expr(input))),
- outputs: outputs.move_map(|(c, out, is_rw)| (c, folder.fold_expr(out), is_rw)),
+ outputs: outputs.move_map(|(c, out, is_rw, is_indirect)| {
+ (c, folder.fold_expr(out), is_rw, is_indirect)
+ }),
asm: asm,
asm_str_style: asm_str_style,
clobbers: clobbers,
pub struct InlineAsm {
pub asm: InternedString,
pub asm_str_style: StrStyle,
- pub outputs: Vec<(InternedString, P<Expr>, bool)>,
+ pub outputs: Vec<(InternedString, P<Expr>, bool, bool)>,
pub inputs: Vec<(InternedString, P<Expr>)>,
pub clobbers: Vec<InternedString>,
pub volatile: bool,
for &(_, ref input) in &ia.inputs {
visitor.visit_expr(&input)
}
- for &(_, ref output, _) in &ia.outputs {
+ for &(_, ref output, _, _) in &ia.outputs {
visitor.visit_expr(&output)
}
}
.map(|&(ref c, ref input)| (c.clone(), lower_expr(lctx, input)))
.collect(),
outputs: outputs.iter()
- .map(|&(ref c, ref out, ref is_rw)| {
- (c.clone(), lower_expr(lctx, out), *is_rw)
+ .map(|&(ref c, ref out, is_rw, is_indirect)| {
+ (c.clone(), lower_expr(lctx, out), is_rw, is_indirect)
})
.collect(),
asm: asm.clone(),
try!(self.print_string(&a.asm, a.asm_str_style));
try!(self.word_space(":"));
- try!(self.commasep(Inconsistent, &a.outputs, |s, &(ref co, ref o, is_rw)| {
+ try!(self.commasep(Inconsistent, &a.outputs, |s, &(ref co, ref o, is_rw, _)| {
match co.slice_shift_char() {
Some(('=', operand)) if is_rw => {
try!(s.print_string(&format!("+{}", operand), ast::CookedStr))
let mut ext_constraints = Vec::new();
// Prepare the output operands
- let outputs = ia.outputs.iter().enumerate().map(|(i, &(ref c, ref out, is_rw))| {
+ let mut outputs = Vec::new();
+ let mut inputs = Vec::new();
+ for (i, &(ref c, ref out, is_rw, is_indirect)) in ia.outputs.iter().enumerate() {
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));
- let val = out_datum.val;
- if is_rw {
+ if is_indirect {
bcx = callee::trans_arg_datum(bcx,
expr_ty(bcx, &**out),
out_datum,
cleanup::CustomScope(temp_scope),
callee::DontAutorefArg,
- &mut ext_inputs);
- ext_constraints.push(i.to_string());
+ &mut inputs);
+ if is_rw {
+ ext_inputs.push(*inputs.last().unwrap());
+ ext_constraints.push(i.to_string());
+ }
+ } else {
+ output_types.push(type_of::type_of(bcx.ccx(), out_datum.ty));
+ outputs.push(out_datum.val);
+ if is_rw {
+ bcx = callee::trans_arg_datum(bcx,
+ expr_ty(bcx, &**out),
+ out_datum,
+ cleanup::CustomScope(temp_scope),
+ callee::DontAutorefArg,
+ &mut ext_inputs);
+ ext_constraints.push(i.to_string());
+ }
}
- val
-
- }).collect::<Vec<_>>();
+ }
// Now the input operands
- let mut inputs = Vec::new();
for &(ref c, ref input) in &ia.inputs {
constraints.push((*c).clone());
walk_expr(cx, &**exp, scope_stack, scope_map);
}
- for &(_, ref exp, _) in outputs {
+ for &(_, ref exp, _, _) in outputs {
walk_expr(cx, &**exp, scope_stack, scope_map);
}
}
for &(_, ref input) in &ia.inputs {
check_expr(fcx, &**input);
}
- for &(_, ref out, _) in &ia.outputs {
+ for &(_, ref out, _, _) in &ia.outputs {
check_expr(fcx, &**out);
}
fcx.write_nil(id);
pub struct InlineAsm {
pub asm: InternedString,
pub asm_str_style: StrStyle,
- pub outputs: Vec<(InternedString, P<Expr>, bool)>,
+ pub outputs: Vec<(InternedString, P<Expr>, bool, bool)>,
pub inputs: Vec<(InternedString, P<Expr>)>,
pub clobbers: Vec<InternedString>,
pub volatile: bool,
};
let is_rw = output.is_some();
- outputs.push((output.unwrap_or(constraint), out, is_rw));
+ let is_indirect = constraint.contains("*");
+ outputs.push((output.unwrap_or(constraint), out, is_rw, is_indirect));
}
}
Inputs => {
let (constraint, _str_style) = panictry!(p.parse_str());
- if constraint.starts_with("=") && !constraint.contains("*") {
+ if constraint.starts_with("=") {
cx.span_err(p.last_span, "input operand constraint contains '='");
- } else if constraint.starts_with("+") && !constraint.contains("*") {
+ } else if constraint.starts_with("+") {
cx.span_err(p.last_span, "input operand constraint contains '+'");
}
inputs: inputs.move_map(|(c, input)| {
(c, folder.fold_expr(input))
}),
- outputs: outputs.move_map(|(c, out, is_rw)| {
- (c, folder.fold_expr(out), is_rw)
+ outputs: outputs.move_map(|(c, out, is_rw, is_indirect)| {
+ (c, folder.fold_expr(out), is_rw, is_indirect)
}),
asm: asm,
asm_str_style: asm_str_style,
try!(self.word_space(":"));
try!(self.commasep(Inconsistent, &a.outputs,
- |s, &(ref co, ref o, is_rw)| {
+ |s, &(ref co, ref o, is_rw, _)| {
match co.slice_shift_char() {
Some(('=', operand)) if is_rw => {
try!(s.print_string(&format!("+{}", operand),
for &(_, ref input) in &ia.inputs {
visitor.visit_expr(&input)
}
- for &(_, ref output, _) in &ia.outputs {
+ for &(_, ref output, _, _) in &ia.outputs {
visitor.visit_expr(&output)
}
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn write(ptr: &mut u32, val: u32) {
unsafe {
- asm!("mov $1, $0" :: "=*m" (ptr), "r" (val));
+ asm!("mov $1, $0" : "=*m" (ptr) : "r" (val));
}
}
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn replace(ptr: &mut u32, val: u32) -> u32 {
+ let out: u32;
+ unsafe {
+ asm!("mov $0, $1; mov $2, $0" : "+*m" (ptr), "=&r" (out) : "r" (val));
+ }
+ out
+}
+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub fn main() {
let a = 1;
- let mut b = 2;
assert_eq!(read(&a), 1);
+ let mut b = 2;
write(&mut b, 3);
assert_eq!(b, 3);
+ let mut c = 4;
+ assert_eq!(replace(&mut c, 5), 4);
+ assert_eq!(c, 5);
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]