Handle inline asm outputs as write-only in liveness, borrowck and trans.

This commit is contained in:
Eduard Burtescu 2013-10-17 21:24:41 +03:00
parent 737413d72a
commit 7ab0b0cd41
10 changed files with 193 additions and 50 deletions

View File

@ -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);
}
}
_ => { }
}
}

View File

@ -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, ());
}

View File

@ -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, ());
}

View File

@ -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);
}
}

View File

@ -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);

View 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() {}

View 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() {}

View 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() {}

View 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() {}

View 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() {}