about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-11-04 20:39:49 +0000
committerbors <bors@rust-lang.org>2015-11-04 20:39:49 +0000
commiteffcd29652bbf16981d9cd0d8a578681b2ed55bb (patch)
tree0c5991d752c859eb48c499d3850b6ed7419ad718 /src
parent4ee11cd210ccb9a9be04ccab731cdaac5f4dea4c (diff)
parent59c5191c211711c8f51daa4911b1b734393a4011 (diff)
downloadrust-effcd29652bbf16981d9cd0d8a578681b2ed55bb.tar.gz
rust-effcd29652bbf16981d9cd0d8a578681b2ed55bb.zip
Auto merge of #29543 - Amanieu:asm_mem_constraint, r=alexcrichton
The "m" memory constraint in inline assembly is broken (generates incorrect code or triggers LLVM asserts) and should not be used. Instead, indirect memory operands should be used with "\*m", "=\*m" and "+\*m".

Clang does this transparently by transforming "m" constraints into "\*m" indirect constraints, but for now just being able to use "\*m" directly is enough since asm! isn't stable.

While "\*m" works fine as an input operand, "=\*m" and "+\*m" need to be specified as input operands because they take a pointer value as an input. This PR relaxes the constraint checker to allow constraints starting with "=" or "+" if the constraint string contains a "\*", which indicates an indirect operand.

This (indirectly) fixes these issues: #29382, #16383 and #13366. The code will need to be changed to use "\*m" instead of "m".
Diffstat (limited to 'src')
-rw-r--r--src/libsyntax/ext/asm.rs4
-rw-r--r--src/test/run-pass/asm-indirect-memory.rs39
2 files changed, 41 insertions, 2 deletions
diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs
index 984e73f85f6..bdfbb7a4933 100644
--- a/src/libsyntax/ext/asm.rs
+++ b/src/libsyntax/ext/asm.rs
@@ -139,9 +139,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("=") {
+                    if constraint.starts_with("=") && !constraint.contains("*") {
                         cx.span_err(p.last_span, "input operand constraint contains '='");
-                    } else if constraint.starts_with("+") {
+                    } else if constraint.starts_with("+") && !constraint.contains("*") {
                         cx.span_err(p.last_span, "input operand constraint contains '+'");
                     }
 
diff --git a/src/test/run-pass/asm-indirect-memory.rs b/src/test/run-pass/asm-indirect-memory.rs
new file mode 100644
index 00000000000..80fd548dfe3
--- /dev/null
+++ b/src/test/run-pass/asm-indirect-memory.rs
@@ -0,0 +1,39 @@
+// Copyright 2015 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)]
+
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn read(ptr: &u32) -> u32 {
+    let out: u32;
+    unsafe {
+        asm!("mov $1, $0" : "=r" (out) : "*m" (ptr));
+    }
+    out
+}
+
+#[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));
+    }
+}
+
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub fn main() {
+    let a = 1;
+    let mut b = 2;
+    assert_eq!(read(&a), 1);
+    write(&mut b, 3);
+    assert_eq!(b, 3);
+}
+
+#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+pub fn main() {}