Skip to content

Commit 7ab0b0c

Browse files
committed
Handle inline asm outputs as write-only in liveness, borrowck and trans.
1 parent 737413d commit 7ab0b0c

File tree

10 files changed

+193
-50
lines changed

10 files changed

+193
-50
lines changed

src/librustc/middle/borrowck/check_loans.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -839,6 +839,11 @@ fn check_loans_in_expr<'a>(this: &mut CheckLoanCtxt<'a>,
839839
expr.span,
840840
[]);
841841
}
842+
ast::ExprInlineAsm(ref ia) => {
843+
for &(_, out) in ia.outputs.iter() {
844+
this.check_assignment(out);
845+
}
846+
}
842847
_ => { }
843848
}
844849
}

src/librustc/middle/borrowck/gather_loans/mod.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -309,6 +309,23 @@ fn gather_loans_in_expr(this: &mut GatherLoanCtxt,
309309
visit::walk_expr(this, ex, ());
310310
}
311311

312+
ast::ExprInlineAsm(ref ia) => {
313+
for &(_, out) in ia.outputs.iter() {
314+
let out_cmt = this.bccx.cat_expr(out);
315+
match opt_loan_path(out_cmt) {
316+
Some(out_lp) => {
317+
gather_moves::gather_assignment(this.bccx, this.move_data,
318+
ex.id, ex.span,
319+
out_lp, out.id);
320+
}
321+
None => {
322+
// See the comment for ExprAssign.
323+
}
324+
}
325+
}
326+
visit::walk_expr(this, ex, ());
327+
}
328+
312329
_ => {
313330
visit::walk_expr(this, ex, ());
314331
}

src/librustc/middle/liveness.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -1227,12 +1227,15 @@ impl Liveness {
12271227
self.propagate_through_expr(e, succ)
12281228
}
12291229

1230-
ExprInlineAsm(ref ia) =>{
1230+
ExprInlineAsm(ref ia) => {
12311231
let succ = do ia.inputs.rev_iter().fold(succ) |succ, &(_, expr)| {
12321232
self.propagate_through_expr(expr, succ)
12331233
};
12341234
do ia.outputs.rev_iter().fold(succ) |succ, &(_, expr)| {
1235-
self.propagate_through_expr(expr, succ)
1235+
// see comment on lvalues in
1236+
// propagate_through_lvalue_components()
1237+
let succ = self.write_lvalue(expr, succ, ACC_WRITE);
1238+
self.propagate_through_lvalue_components(expr, succ)
12361239
}
12371240
}
12381241

@@ -1478,12 +1481,7 @@ fn check_expr(this: &mut Liveness, expr: @Expr) {
14781481

14791482
// Output operands must be lvalues
14801483
for &(_, out) in ia.outputs.iter() {
1481-
match out.node {
1482-
ExprAddrOf(_, inner) => {
1483-
this.check_lvalue(inner);
1484-
}
1485-
_ => {}
1486-
}
1484+
this.check_lvalue(out);
14871485
this.visit_expr(out, ());
14881486
}
14891487

src/librustc/middle/trans/asm.rs

Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ use lib;
1818
use middle::trans::build::*;
1919
use middle::trans::callee;
2020
use middle::trans::common::*;
21+
use middle::trans::expr::*;
22+
use middle::trans::type_of::*;
2123
use middle::ty;
2224

2325
use middle::trans::type_::Type;
@@ -30,34 +32,15 @@ pub fn trans_inline_asm(bcx: @mut Block, ia: &ast::inline_asm) -> @mut Block {
3032
let mut bcx = bcx;
3133
let mut constraints = ~[];
3234
let mut cleanups = ~[];
33-
let mut aoutputs = ~[];
35+
let mut output_types = ~[];
3436

3537
// Prepare the output operands
3638
let outputs = do ia.outputs.map |&(c, out)| {
3739
constraints.push(c);
3840

39-
aoutputs.push(unpack_result!(bcx, {
40-
callee::trans_arg_expr(bcx,
41-
expr_ty(bcx, out),
42-
ty::ByCopy,
43-
out,
44-
&mut cleanups,
45-
callee::DontAutorefArg)
46-
}));
47-
48-
let e = match out.node {
49-
ast::ExprAddrOf(_, e) => e,
50-
_ => fail2!("Expression must be addr of")
51-
};
52-
53-
unpack_result!(bcx, {
54-
callee::trans_arg_expr(bcx,
55-
expr_ty(bcx, e),
56-
ty::ByCopy,
57-
e,
58-
&mut cleanups,
59-
callee::DontAutorefArg)
60-
})
41+
let out_datum = unpack_datum!(bcx, trans_to_datum(bcx, out));
42+
output_types.push(type_of(bcx.ccx(), out_datum.ty));
43+
out_datum.val
6144

6245
};
6346

@@ -92,7 +75,7 @@ pub fn trans_inline_asm(bcx: @mut Block, ia: &ast::inline_asm) -> @mut Block {
9275
clobbers = format!("{},{}", ia.clobbers, clobbers);
9376
} else {
9477
clobbers.push_str(ia.clobbers);
95-
};
78+
}
9679

9780
// Add the clobbers to our constraints list
9881
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 {
10790
let numOutputs = outputs.len();
10891

10992
// Depending on how many outputs we have, the return type is different
110-
let output = if numOutputs == 0 {
93+
let output_type = if numOutputs == 0 {
11194
Type::void()
11295
} else if numOutputs == 1 {
113-
val_ty(outputs[0])
96+
output_types[0]
11497
} else {
115-
Type::struct_(outputs.map(|o| val_ty(*o)), false)
98+
Type::struct_(output_types, false)
11699
};
117100

118101
let dialect = match ia.dialect {
@@ -122,19 +105,17 @@ pub fn trans_inline_asm(bcx: @mut Block, ia: &ast::inline_asm) -> @mut Block {
122105

123106
let r = do ia.asm.with_c_str |a| {
124107
do constraints.with_c_str |c| {
125-
InlineAsmCall(bcx, a, c, inputs, output, ia.volatile, ia.alignstack, dialect)
108+
InlineAsmCall(bcx, a, c, inputs, output_type, ia.volatile, ia.alignstack, dialect)
126109
}
127110
};
128111

129112
// Again, based on how many outputs we have
130113
if numOutputs == 1 {
131-
let op = PointerCast(bcx, aoutputs[0], val_ty(outputs[0]).ptr_to());
132-
Store(bcx, r, op);
114+
Store(bcx, r, outputs[0]);
133115
} else {
134-
for (i, o) in aoutputs.iter().enumerate() {
116+
for (i, o) in outputs.iter().enumerate() {
135117
let v = ExtractValue(bcx, r, i);
136-
let op = PointerCast(bcx, *o, val_ty(outputs[i]).ptr_to());
137-
Store(bcx, v, op);
118+
Store(bcx, v, *o);
138119
}
139120
}
140121

src/libsyntax/ext/asm.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,18 @@ pub fn expand_asm(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree])
7575
}
7676

7777
let (constraint, _str_style) = p.parse_str();
78+
79+
if constraint.starts_with("+") {
80+
cx.span_unimpl(*p.last_span,
81+
"'+' (read+write) output operand constraint modifier");
82+
} else if !constraint.starts_with("=") {
83+
cx.span_err(*p.last_span, "output operand constraint lacks '='");
84+
}
85+
7886
p.expect(&token::LPAREN);
7987
let out = p.parse_expr();
8088
p.expect(&token::RPAREN);
8189

82-
let out = @ast::Expr {
83-
id: ast::DUMMY_NODE_ID,
84-
span: out.span,
85-
node: ast::ExprAddrOf(ast::MutMutable, out)
86-
};
87-
8890
outputs.push((constraint, out));
8991
}
9092
}
@@ -98,6 +100,13 @@ pub fn expand_asm(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree])
98100
}
99101

100102
let (constraint, _str_style) = p.parse_str();
103+
104+
if constraint.starts_with("=") {
105+
cx.span_err(*p.last_span, "input operand constraint contains '='");
106+
} else if constraint.starts_with("+") {
107+
cx.span_err(*p.last_span, "input operand constraint contains '+'");
108+
}
109+
101110
p.expect(&token::LPAREN);
102111
let input = p.parse_expr();
103112
p.expect(&token::RPAREN);
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn foo(x: int) { info2!("{}", x); }
12+
13+
#[cfg(target_arch = "x86")]
14+
#[cfg(target_arch = "x86_64")]
15+
pub fn main() {
16+
let x: int;
17+
let y: int;
18+
unsafe {
19+
asm!("mov $1, $0" : "=r"(x) : "=r"(5u)); //~ ERROR input operand constraint contains '='
20+
asm!("mov $1, $0" : "=r"(y) : "+r"(5u)); //~ ERROR input operand constraint contains '+'
21+
}
22+
foo(x);
23+
foo(y);
24+
}
25+
26+
#[cfg(not(target_arch = "x86"), not(target_arch = "x86_64"))]
27+
pub fn main() {}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn foo(x: int) { info2!("{}", x); }
12+
13+
#[cfg(target_arch = "x86")]
14+
#[cfg(target_arch = "x86_64")]
15+
pub fn main() {
16+
let x: int;
17+
x = 1; //~ NOTE prior assignment occurs here
18+
foo(x);
19+
unsafe {
20+
asm!("mov $1, $0" : "=r"(x) : "r"(5u)); //~ ERROR re-assignment of immutable variable `x`
21+
}
22+
foo(x);
23+
}
24+
25+
#[cfg(not(target_arch = "x86"), not(target_arch = "x86_64"))]
26+
pub fn main() {}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn foo(x: int) { info2!("{}", x); }
12+
13+
#[cfg(target_arch = "x86")]
14+
#[cfg(target_arch = "x86_64")]
15+
pub fn main() {
16+
let x: int;
17+
unsafe {
18+
asm!("mov $1, $0" : "r"(x) : "r"(5u)); //~ ERROR output operand constraint lacks '='
19+
}
20+
foo(x);
21+
}
22+
23+
#[cfg(not(target_arch = "x86"), not(target_arch = "x86_64"))]
24+
pub fn main() {}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn foo(x: int) { info2!("{}", x); }
12+
13+
#[cfg(target_arch = "x86")]
14+
#[cfg(target_arch = "x86_64")]
15+
pub fn main() {
16+
let x: int;
17+
unsafe {
18+
asm!("mov $1, $0" : "=r"(x) : "r"(x)); //~ ERROR use of possibly uninitialized value: `x`
19+
}
20+
foo(x);
21+
}
22+
23+
#[cfg(not(target_arch = "x86"), not(target_arch = "x86_64"))]
24+
pub fn main() {}

src/test/run-pass/asm-out-assign.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[cfg(target_arch = "x86")]
12+
#[cfg(target_arch = "x86_64")]
13+
pub fn main() {
14+
let x: int;
15+
unsafe {
16+
// Treat the output as initialization.
17+
asm!("mov $1, $0" : "=r"(x) : "r"(5u));
18+
}
19+
assert_eq!(x, 5);
20+
21+
let mut x = x + 1;
22+
assert_eq!(x, 6);
23+
24+
unsafe {
25+
// Assignment to mutable.
26+
asm!("mov $1, $0" : "=r"(x) : "r"(x + 7));
27+
}
28+
assert_eq!(x, 13);
29+
}
30+
31+
#[cfg(not(target_arch = "x86"), not(target_arch = "x86_64"))]
32+
pub fn main() {}

0 commit comments

Comments
 (0)