]> git.lizzy.rs Git - rust.git/commitdiff
Add proper support for indirect output constraints in inline asm
authorAmanieu d'Antras <amanieu@gmail.com>
Fri, 6 Nov 2015 13:31:02 +0000 (13:31 +0000)
committerAmanieu d'Antras <amanieu@gmail.com>
Sat, 5 Dec 2015 08:18:30 +0000 (08:18 +0000)
17 files changed:
src/librustc/middle/cfg/construct.rs
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/liveness.rs
src/librustc_front/fold.rs
src/librustc_front/hir.rs
src/librustc_front/intravisit.rs
src/librustc_front/lowering.rs
src/librustc_front/print/pprust.rs
src/librustc_trans/trans/asm.rs
src/librustc_trans/trans/debuginfo/create_scope_map.rs
src/librustc_typeck/check/mod.rs
src/libsyntax/ast.rs
src/libsyntax/ext/asm.rs
src/libsyntax/fold.rs
src/libsyntax/print/pprust.rs
src/libsyntax/visit.rs
src/test/run-pass/asm-indirect-memory.rs

index 5b931857decca24fa75c0338cd65efeec25d9d1b..de540e5cfb388f1e793eb4e1756ef5d63ba82434 100644 (file)
@@ -368,7 +368,7 @@ fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) -> CFGIndex {
                 }), 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])
index ce8d74bf191c784d4d1edd18714a3e94684d7380..316b49e1de408116133f908f11c9a403e0d781eb 100644 (file)
@@ -458,9 +458,13 @@ pub fn walk_expr(&mut self, expr: &hir::Expr) {
                     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 });
+                    }
                 }
             }
 
index 2a8b1b83d224cde88e17e5beefc24cd4c98c5eac..5170b37732420cd64dbb1906458fee10ab9f4031 100644 (file)
@@ -1166,12 +1166,18 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
 
           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)
@@ -1416,8 +1422,10 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
         }
 
         // 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);
         }
 
index 5f39376d156032d642b7ea06560482c0929b0c3c..c9a09989f04413dc7b7e5d21c152224ad8187ea8 100644 (file)
@@ -1127,7 +1127,9 @@ pub fn noop_fold_expr<T: Folder>(Expr { id, node, span, attrs }: Expr, folder: &
                 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,
index beb7059d73cd2914ad817dd313ace033d8b61e70..bc95599fb7a7042a0a9965348bbd7ddbcc2f751c 100644 (file)
@@ -891,7 +891,7 @@ pub enum Ty_ {
 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,
index 3a43feb8ba74bc1899e8fce343f999af39055004..d0f2a9dca17fdc562b3a66e08b62b223b68aefb1 100644 (file)
@@ -803,7 +803,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             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)
             }
         }
index e8c4a6484e2a2a95d97ee366c68f8b207f357355..e5ea737f621ade1bd5d9dfb6fd60104d7bba741b 100644 (file)
@@ -1202,8 +1202,8 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
                               .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(),
index e059a4ed5f69dd7148c2b41234671f9bd109b0f9..c87750002686c8445a5e3ab01dc1c26a13e127db 100644 (file)
@@ -1502,7 +1502,7 @@ pub fn print_expr(&mut self, expr: &hir::Expr) -> io::Result<()> {
                 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))
index c59237e307849a30c701c0c229314f4b1fb30cde..efa34fbcbdcf87dbdbbbb30817e6d67635963aa8 100644 (file)
@@ -39,27 +39,39 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
     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());
 
index 0c424de9e10b89ee6657c1b1b5fd84c9f77febcf..c8a66fb611d533bcce268f59e8c08e912b0f6516 100644 (file)
@@ -480,7 +480,7 @@ fn walk_expr(cx: &CrateContext,
                 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);
             }
         }
index ed8bb6a962509eae4858cc8df34fae9074ee5d83..722273ee0f8525a0611098f99243f93fec2f649f 100644 (file)
@@ -3393,7 +3393,7 @@ fn check_expr_struct<'a, 'tcx>(fcx: &FnCtxt<'a,'tcx>,
           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);
index f11291fc0f7e7a005124589df7fd3332e0605eba..ac3e26d033582d8c366a3c9b23635fd7b32bdb8c 100644 (file)
@@ -1462,7 +1462,7 @@ pub enum AsmDialect {
 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,
index d968858f634eb60f20267808233d1cb90f0604ce..f643f0be276854216c290584caf7ff886fec9f38 100644 (file)
@@ -125,7 +125,8 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                     };
 
                     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 => {
@@ -139,9 +140,9 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
 
                     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 '+'");
                     }
 
index 73f2c51b246222a90bae743f392410e1a049ef33..8619c3c0bdb7920b318be654b0ada9d8602a745a 100644 (file)
@@ -1303,8 +1303,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
                 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,
index aa55cb847faffabb882abf25587011ba38168959..a0b7df3e2e9ea25ae35ccc392e42c0128f63a5b9 100644 (file)
@@ -2221,7 +2221,7 @@ fn print_expr_outer_attr_style(&mut self,
                 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),
index cdc11fb2c1cb0262cef3e0ce563290ee0d2b737c..5ede6596e8f99a2d4d515f96a180d55c444b7a5e 100644 (file)
@@ -786,7 +786,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             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)
             }
         }
index 80fd548dfe3540bbd3341e63969f149d425d9ce1..d1873afb3a9b76fb842d40e61cfcd204d742cfc9 100644 (file)
@@ -22,17 +22,29 @@ fn read(ptr: &u32) -> u32 {
 #[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")))]