Handle inline asm outputs as write-only in liveness, borrowck and trans.
This commit is contained in:
parent
737413d72a
commit
7ab0b0cd41
@ -1,4 +1,4 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
@ -839,6 +839,11 @@ fn check_loans_in_expr<'a>(this: &mut CheckLoanCtxt<'a>,
|
||||
expr.span,
|
||||
[]);
|
||||
}
|
||||
ast::ExprInlineAsm(ref ia) => {
|
||||
for &(_, out) in ia.outputs.iter() {
|
||||
this.check_assignment(out);
|
||||
}
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
@ -309,6 +309,23 @@ fn gather_loans_in_expr(this: &mut GatherLoanCtxt,
|
||||
visit::walk_expr(this, ex, ());
|
||||
}
|
||||
|
||||
ast::ExprInlineAsm(ref ia) => {
|
||||
for &(_, out) in ia.outputs.iter() {
|
||||
let out_cmt = this.bccx.cat_expr(out);
|
||||
match opt_loan_path(out_cmt) {
|
||||
Some(out_lp) => {
|
||||
gather_moves::gather_assignment(this.bccx, this.move_data,
|
||||
ex.id, ex.span,
|
||||
out_lp, out.id);
|
||||
}
|
||||
None => {
|
||||
// See the comment for ExprAssign.
|
||||
}
|
||||
}
|
||||
}
|
||||
visit::walk_expr(this, ex, ());
|
||||
}
|
||||
|
||||
_ => {
|
||||
visit::walk_expr(this, ex, ());
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
@ -1227,12 +1227,15 @@ impl Liveness {
|
||||
self.propagate_through_expr(e, succ)
|
||||
}
|
||||
|
||||
ExprInlineAsm(ref ia) =>{
|
||||
ExprInlineAsm(ref ia) => {
|
||||
let succ = do ia.inputs.rev_iter().fold(succ) |succ, &(_, expr)| {
|
||||
self.propagate_through_expr(expr, succ)
|
||||
};
|
||||
do ia.outputs.rev_iter().fold(succ) |succ, &(_, expr)| {
|
||||
self.propagate_through_expr(expr, succ)
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1478,12 +1481,7 @@ fn check_expr(this: &mut Liveness, expr: @Expr) {
|
||||
|
||||
// Output operands must be lvalues
|
||||
for &(_, out) in ia.outputs.iter() {
|
||||
match out.node {
|
||||
ExprAddrOf(_, inner) => {
|
||||
this.check_lvalue(inner);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
this.check_lvalue(out);
|
||||
this.visit_expr(out, ());
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,8 @@ use lib;
|
||||
use middle::trans::build::*;
|
||||
use middle::trans::callee;
|
||||
use middle::trans::common::*;
|
||||
use middle::trans::expr::*;
|
||||
use middle::trans::type_of::*;
|
||||
use middle::ty;
|
||||
|
||||
use middle::trans::type_::Type;
|
||||
@ -30,34 +32,15 @@ pub fn trans_inline_asm(bcx: @mut Block, ia: &ast::inline_asm) -> @mut Block {
|
||||
let mut bcx = bcx;
|
||||
let mut constraints = ~[];
|
||||
let mut cleanups = ~[];
|
||||
let mut aoutputs = ~[];
|
||||
let mut output_types = ~[];
|
||||
|
||||
// Prepare the output operands
|
||||
let outputs = do ia.outputs.map |&(c, out)| {
|
||||
constraints.push(c);
|
||||
|
||||
aoutputs.push(unpack_result!(bcx, {
|
||||
callee::trans_arg_expr(bcx,
|
||||
expr_ty(bcx, out),
|
||||
ty::ByCopy,
|
||||
out,
|
||||
&mut cleanups,
|
||||
callee::DontAutorefArg)
|
||||
}));
|
||||
|
||||
let e = match out.node {
|
||||
ast::ExprAddrOf(_, e) => e,
|
||||
_ => fail2!("Expression must be addr of")
|
||||
};
|
||||
|
||||
unpack_result!(bcx, {
|
||||
callee::trans_arg_expr(bcx,
|
||||
expr_ty(bcx, e),
|
||||
ty::ByCopy,
|
||||
e,
|
||||
&mut cleanups,
|
||||
callee::DontAutorefArg)
|
||||
})
|
||||
let out_datum = unpack_datum!(bcx, trans_to_datum(bcx, out));
|
||||
output_types.push(type_of(bcx.ccx(), out_datum.ty));
|
||||
out_datum.val
|
||||
|
||||
};
|
||||
|
||||
@ -92,7 +75,7 @@ pub fn trans_inline_asm(bcx: @mut Block, ia: &ast::inline_asm) -> @mut Block {
|
||||
clobbers = format!("{},{}", ia.clobbers, clobbers);
|
||||
} else {
|
||||
clobbers.push_str(ia.clobbers);
|
||||
};
|
||||
}
|
||||
|
||||
// Add the clobbers to our constraints list
|
||||
if clobbers.len() != 0 && constraints.len() != 0 {
|
||||
@ -107,12 +90,12 @@ pub fn trans_inline_asm(bcx: @mut Block, ia: &ast::inline_asm) -> @mut Block {
|
||||
let numOutputs = outputs.len();
|
||||
|
||||
// Depending on how many outputs we have, the return type is different
|
||||
let output = if numOutputs == 0 {
|
||||
let output_type = if numOutputs == 0 {
|
||||
Type::void()
|
||||
} else if numOutputs == 1 {
|
||||
val_ty(outputs[0])
|
||||
output_types[0]
|
||||
} else {
|
||||
Type::struct_(outputs.map(|o| val_ty(*o)), false)
|
||||
Type::struct_(output_types, false)
|
||||
};
|
||||
|
||||
let dialect = match ia.dialect {
|
||||
@ -122,19 +105,17 @@ pub fn trans_inline_asm(bcx: @mut Block, ia: &ast::inline_asm) -> @mut Block {
|
||||
|
||||
let r = do ia.asm.with_c_str |a| {
|
||||
do constraints.with_c_str |c| {
|
||||
InlineAsmCall(bcx, a, c, inputs, output, ia.volatile, ia.alignstack, dialect)
|
||||
InlineAsmCall(bcx, a, c, inputs, output_type, ia.volatile, ia.alignstack, dialect)
|
||||
}
|
||||
};
|
||||
|
||||
// Again, based on how many outputs we have
|
||||
if numOutputs == 1 {
|
||||
let op = PointerCast(bcx, aoutputs[0], val_ty(outputs[0]).ptr_to());
|
||||
Store(bcx, r, op);
|
||||
Store(bcx, r, outputs[0]);
|
||||
} else {
|
||||
for (i, o) in aoutputs.iter().enumerate() {
|
||||
for (i, o) in outputs.iter().enumerate() {
|
||||
let v = ExtractValue(bcx, r, i);
|
||||
let op = PointerCast(bcx, *o, val_ty(outputs[i]).ptr_to());
|
||||
Store(bcx, v, op);
|
||||
Store(bcx, v, *o);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,16 +75,18 @@ pub fn expand_asm(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree])
|
||||
}
|
||||
|
||||
let (constraint, _str_style) = p.parse_str();
|
||||
|
||||
if constraint.starts_with("+") {
|
||||
cx.span_unimpl(*p.last_span,
|
||||
"'+' (read+write) output operand constraint modifier");
|
||||
} else if !constraint.starts_with("=") {
|
||||
cx.span_err(*p.last_span, "output operand constraint lacks '='");
|
||||
}
|
||||
|
||||
p.expect(&token::LPAREN);
|
||||
let out = p.parse_expr();
|
||||
p.expect(&token::RPAREN);
|
||||
|
||||
let out = @ast::Expr {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: out.span,
|
||||
node: ast::ExprAddrOf(ast::MutMutable, out)
|
||||
};
|
||||
|
||||
outputs.push((constraint, out));
|
||||
}
|
||||
}
|
||||
@ -98,6 +100,13 @@ pub fn expand_asm(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree])
|
||||
}
|
||||
|
||||
let (constraint, _str_style) = p.parse_str();
|
||||
|
||||
if constraint.starts_with("=") {
|
||||
cx.span_err(*p.last_span, "input operand constraint contains '='");
|
||||
} else if constraint.starts_with("+") {
|
||||
cx.span_err(*p.last_span, "input operand constraint contains '+'");
|
||||
}
|
||||
|
||||
p.expect(&token::LPAREN);
|
||||
let input = p.parse_expr();
|
||||
p.expect(&token::RPAREN);
|
||||
|
27
src/test/compile-fail/asm-in-bad-modifier.rs
Normal file
27
src/test/compile-fail/asm-in-bad-modifier.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2012-2013 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.
|
||||
|
||||
fn foo(x: int) { info2!("{}", x); }
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn main() {
|
||||
let x: int;
|
||||
let y: int;
|
||||
unsafe {
|
||||
asm!("mov $1, $0" : "=r"(x) : "=r"(5u)); //~ ERROR input operand constraint contains '='
|
||||
asm!("mov $1, $0" : "=r"(y) : "+r"(5u)); //~ ERROR input operand constraint contains '+'
|
||||
}
|
||||
foo(x);
|
||||
foo(y);
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "x86"), not(target_arch = "x86_64"))]
|
||||
pub fn main() {}
|
26
src/test/compile-fail/asm-out-assign-imm.rs
Normal file
26
src/test/compile-fail/asm-out-assign-imm.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2012-2013 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.
|
||||
|
||||
fn foo(x: int) { info2!("{}", x); }
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn main() {
|
||||
let x: int;
|
||||
x = 1; //~ NOTE prior assignment occurs here
|
||||
foo(x);
|
||||
unsafe {
|
||||
asm!("mov $1, $0" : "=r"(x) : "r"(5u)); //~ ERROR re-assignment of immutable variable `x`
|
||||
}
|
||||
foo(x);
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "x86"), not(target_arch = "x86_64"))]
|
||||
pub fn main() {}
|
24
src/test/compile-fail/asm-out-no-modifier.rs
Normal file
24
src/test/compile-fail/asm-out-no-modifier.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2012-2013 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.
|
||||
|
||||
fn foo(x: int) { info2!("{}", x); }
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn main() {
|
||||
let x: int;
|
||||
unsafe {
|
||||
asm!("mov $1, $0" : "r"(x) : "r"(5u)); //~ ERROR output operand constraint lacks '='
|
||||
}
|
||||
foo(x);
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "x86"), not(target_arch = "x86_64"))]
|
||||
pub fn main() {}
|
24
src/test/compile-fail/asm-out-read-uninit.rs
Normal file
24
src/test/compile-fail/asm-out-read-uninit.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2012-2013 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.
|
||||
|
||||
fn foo(x: int) { info2!("{}", x); }
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn main() {
|
||||
let x: int;
|
||||
unsafe {
|
||||
asm!("mov $1, $0" : "=r"(x) : "r"(x)); //~ ERROR use of possibly uninitialized value: `x`
|
||||
}
|
||||
foo(x);
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "x86"), not(target_arch = "x86_64"))]
|
||||
pub fn main() {}
|
32
src/test/run-pass/asm-out-assign.rs
Normal file
32
src/test/run-pass/asm-out-assign.rs
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2012-2013 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.
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn main() {
|
||||
let x: int;
|
||||
unsafe {
|
||||
// Treat the output as initialization.
|
||||
asm!("mov $1, $0" : "=r"(x) : "r"(5u));
|
||||
}
|
||||
assert_eq!(x, 5);
|
||||
|
||||
let mut x = x + 1;
|
||||
assert_eq!(x, 6);
|
||||
|
||||
unsafe {
|
||||
// Assignment to mutable.
|
||||
asm!("mov $1, $0" : "=r"(x) : "r"(x + 7));
|
||||
}
|
||||
assert_eq!(x, 13);
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "x86"), not(target_arch = "x86_64"))]
|
||||
pub fn main() {}
|
Loading…
Reference in New Issue
Block a user