Skip to content

Commit 9d7b113

Browse files
committed
Add proper support for indirect output constraints in inline asm
1 parent 3e2ebaa commit 9d7b113

File tree

17 files changed

+78
-39
lines changed

17 files changed

+78
-39
lines changed

src/librustc/middle/cfg/construct.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
368368
}), pred);
369369
let post_outputs = self.exprs(outputs.map(|a| {
370370
debug!("cfg::construct InlineAsm id:{} output:{:?}", expr.id, a);
371-
let &(_, ref expr, _) = a;
371+
let &(_, ref expr, _, _) = a;
372372
&**expr
373373
}), post_inputs);
374374
self.add_ast_node(expr.id, &[post_outputs])

src/librustc/middle/expr_use_visitor.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,9 +458,13 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
458458
self.consume_expr(&**input);
459459
}
460460

461-
for &(_, ref output, is_rw) in &ia.outputs {
462-
self.mutate_expr(expr, &**output,
461+
for &(_, ref output, is_rw, is_indirect) in &ia.outputs {
462+
if is_indirect {
463+
self.consume_expr(&**output);
464+
} else {
465+
self.mutate_expr(expr, &**output,
463466
if is_rw { WriteAndRead } else { JustWrite });
467+
}
464468
}
465469
}
466470

src/librustc/middle/liveness.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1166,12 +1166,18 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
11661166

11671167
hir::ExprInlineAsm(ref ia) => {
11681168

1169-
let succ = ia.outputs.iter().rev().fold(succ, |succ, &(_, ref expr, _)| {
1170-
// see comment on lvalues
1171-
// in propagate_through_lvalue_components()
1172-
let succ = self.write_lvalue(&**expr, succ, ACC_WRITE);
1173-
self.propagate_through_lvalue_components(&**expr, succ)
1174-
});
1169+
let succ = ia.outputs.iter().rev().fold(succ,
1170+
|succ, &(_, ref expr, _, is_indirect)| {
1171+
// see comment on lvalues
1172+
// in propagate_through_lvalue_components()
1173+
if is_indirect {
1174+
self.propagate_through_expr(&**expr, succ)
1175+
} else {
1176+
let succ = self.write_lvalue(&**expr, succ, ACC_WRITE);
1177+
self.propagate_through_lvalue_components(&**expr, succ)
1178+
}
1179+
}
1180+
);
11751181
// Inputs are executed first. Propagate last because of rev order
11761182
ia.inputs.iter().rev().fold(succ, |succ, &(_, ref expr)| {
11771183
self.propagate_through_expr(&**expr, succ)
@@ -1416,8 +1422,10 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
14161422
}
14171423

14181424
// Output operands must be lvalues
1419-
for &(_, ref out, _) in &ia.outputs {
1420-
this.check_lvalue(&**out);
1425+
for &(_, ref out, _, is_indirect) in &ia.outputs {
1426+
if !is_indirect {
1427+
this.check_lvalue(&**out);
1428+
}
14211429
this.visit_expr(&**out);
14221430
}
14231431

src/librustc_front/fold.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1127,7 +1127,9 @@ pub fn noop_fold_expr<T: Folder>(Expr { id, node, span, attrs }: Expr, folder: &
11271127
expn_id,
11281128
}) => ExprInlineAsm(InlineAsm {
11291129
inputs: inputs.move_map(|(c, input)| (c, folder.fold_expr(input))),
1130-
outputs: outputs.move_map(|(c, out, is_rw)| (c, folder.fold_expr(out), is_rw)),
1130+
outputs: outputs.move_map(|(c, out, is_rw, is_indirect)| {
1131+
(c, folder.fold_expr(out), is_rw, is_indirect)
1132+
}),
11311133
asm: asm,
11321134
asm_str_style: asm_str_style,
11331135
clobbers: clobbers,

src/librustc_front/hir.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -891,7 +891,7 @@ pub enum Ty_ {
891891
pub struct InlineAsm {
892892
pub asm: InternedString,
893893
pub asm_str_style: StrStyle,
894-
pub outputs: Vec<(InternedString, P<Expr>, bool)>,
894+
pub outputs: Vec<(InternedString, P<Expr>, bool, bool)>,
895895
pub inputs: Vec<(InternedString, P<Expr>)>,
896896
pub clobbers: Vec<InternedString>,
897897
pub volatile: bool,

src/librustc_front/intravisit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -803,7 +803,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
803803
for &(_, ref input) in &ia.inputs {
804804
visitor.visit_expr(&input)
805805
}
806-
for &(_, ref output, _) in &ia.outputs {
806+
for &(_, ref output, _, _) in &ia.outputs {
807807
visitor.visit_expr(&output)
808808
}
809809
}

src/librustc_front/lowering.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,8 +1202,8 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
12021202
.map(|&(ref c, ref input)| (c.clone(), lower_expr(lctx, input)))
12031203
.collect(),
12041204
outputs: outputs.iter()
1205-
.map(|&(ref c, ref out, ref is_rw)| {
1206-
(c.clone(), lower_expr(lctx, out), *is_rw)
1205+
.map(|&(ref c, ref out, is_rw, is_indirect)| {
1206+
(c.clone(), lower_expr(lctx, out), is_rw, is_indirect)
12071207
})
12081208
.collect(),
12091209
asm: asm.clone(),

src/librustc_front/print/pprust.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1502,7 +1502,7 @@ impl<'a> State<'a> {
15021502
try!(self.print_string(&a.asm, a.asm_str_style));
15031503
try!(self.word_space(":"));
15041504

1505-
try!(self.commasep(Inconsistent, &a.outputs, |s, &(ref co, ref o, is_rw)| {
1505+
try!(self.commasep(Inconsistent, &a.outputs, |s, &(ref co, ref o, is_rw, _)| {
15061506
match co.slice_shift_char() {
15071507
Some(('=', operand)) if is_rw => {
15081508
try!(s.print_string(&format!("+{}", operand), ast::CookedStr))

src/librustc_trans/trans/asm.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,27 +39,39 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
3939
let mut ext_constraints = Vec::new();
4040

4141
// Prepare the output operands
42-
let outputs = ia.outputs.iter().enumerate().map(|(i, &(ref c, ref out, is_rw))| {
42+
let mut outputs = Vec::new();
43+
let mut inputs = Vec::new();
44+
for (i, &(ref c, ref out, is_rw, is_indirect)) in ia.outputs.iter().enumerate() {
4345
constraints.push((*c).clone());
4446

4547
let out_datum = unpack_datum!(bcx, expr::trans(bcx, &**out));
46-
output_types.push(type_of::type_of(bcx.ccx(), out_datum.ty));
47-
let val = out_datum.val;
48-
if is_rw {
48+
if is_indirect {
4949
bcx = callee::trans_arg_datum(bcx,
5050
expr_ty(bcx, &**out),
5151
out_datum,
5252
cleanup::CustomScope(temp_scope),
5353
callee::DontAutorefArg,
54-
&mut ext_inputs);
55-
ext_constraints.push(i.to_string());
54+
&mut inputs);
55+
if is_rw {
56+
ext_inputs.push(*inputs.last().unwrap());
57+
ext_constraints.push(i.to_string());
58+
}
59+
} else {
60+
output_types.push(type_of::type_of(bcx.ccx(), out_datum.ty));
61+
outputs.push(out_datum.val);
62+
if is_rw {
63+
bcx = callee::trans_arg_datum(bcx,
64+
expr_ty(bcx, &**out),
65+
out_datum,
66+
cleanup::CustomScope(temp_scope),
67+
callee::DontAutorefArg,
68+
&mut ext_inputs);
69+
ext_constraints.push(i.to_string());
70+
}
5671
}
57-
val
58-
59-
}).collect::<Vec<_>>();
72+
}
6073

6174
// Now the input operands
62-
let mut inputs = Vec::new();
6375
for &(ref c, ref input) in &ia.inputs {
6476
constraints.push((*c).clone());
6577

src/librustc_trans/trans/debuginfo/create_scope_map.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ fn walk_expr(cx: &CrateContext,
480480
walk_expr(cx, &**exp, scope_stack, scope_map);
481481
}
482482

483-
for &(_, ref exp, _) in outputs {
483+
for &(_, ref exp, _, _) in outputs {
484484
walk_expr(cx, &**exp, scope_stack, scope_map);
485485
}
486486
}

src/librustc_typeck/check/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3393,7 +3393,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
33933393
for &(_, ref input) in &ia.inputs {
33943394
check_expr(fcx, &**input);
33953395
}
3396-
for &(_, ref out, _) in &ia.outputs {
3396+
for &(_, ref out, _, _) in &ia.outputs {
33973397
check_expr(fcx, &**out);
33983398
}
33993399
fcx.write_nil(id);

src/libsyntax/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1462,7 +1462,7 @@ pub enum AsmDialect {
14621462
pub struct InlineAsm {
14631463
pub asm: InternedString,
14641464
pub asm_str_style: StrStyle,
1465-
pub outputs: Vec<(InternedString, P<Expr>, bool)>,
1465+
pub outputs: Vec<(InternedString, P<Expr>, bool, bool)>,
14661466
pub inputs: Vec<(InternedString, P<Expr>)>,
14671467
pub clobbers: Vec<InternedString>,
14681468
pub volatile: bool,

src/libsyntax/ext/asm.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
125125
};
126126

127127
let is_rw = output.is_some();
128-
outputs.push((output.unwrap_or(constraint), out, is_rw));
128+
let is_indirect = constraint.contains("*");
129+
outputs.push((output.unwrap_or(constraint), out, is_rw, is_indirect));
129130
}
130131
}
131132
Inputs => {
@@ -139,9 +140,9 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
139140

140141
let (constraint, _str_style) = panictry!(p.parse_str());
141142

142-
if constraint.starts_with("=") && !constraint.contains("*") {
143+
if constraint.starts_with("=") {
143144
cx.span_err(p.last_span, "input operand constraint contains '='");
144-
} else if constraint.starts_with("+") && !constraint.contains("*") {
145+
} else if constraint.starts_with("+") {
145146
cx.span_err(p.last_span, "input operand constraint contains '+'");
146147
}
147148

src/libsyntax/fold.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,8 +1303,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
13031303
inputs: inputs.move_map(|(c, input)| {
13041304
(c, folder.fold_expr(input))
13051305
}),
1306-
outputs: outputs.move_map(|(c, out, is_rw)| {
1307-
(c, folder.fold_expr(out), is_rw)
1306+
outputs: outputs.move_map(|(c, out, is_rw, is_indirect)| {
1307+
(c, folder.fold_expr(out), is_rw, is_indirect)
13081308
}),
13091309
asm: asm,
13101310
asm_str_style: asm_str_style,

src/libsyntax/print/pprust.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2221,7 +2221,7 @@ impl<'a> State<'a> {
22212221
try!(self.word_space(":"));
22222222

22232223
try!(self.commasep(Inconsistent, &a.outputs,
2224-
|s, &(ref co, ref o, is_rw)| {
2224+
|s, &(ref co, ref o, is_rw, _)| {
22252225
match co.slice_shift_char() {
22262226
Some(('=', operand)) if is_rw => {
22272227
try!(s.print_string(&format!("+{}", operand),

src/libsyntax/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
786786
for &(_, ref input) in &ia.inputs {
787787
visitor.visit_expr(&input)
788788
}
789-
for &(_, ref output, _) in &ia.outputs {
789+
for &(_, ref output, _, _) in &ia.outputs {
790790
visitor.visit_expr(&output)
791791
}
792792
}

src/test/run-pass/asm-indirect-memory.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,29 @@ fn read(ptr: &u32) -> u32 {
2222
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
2323
fn write(ptr: &mut u32, val: u32) {
2424
unsafe {
25-
asm!("mov $1, $0" :: "=*m" (ptr), "r" (val));
25+
asm!("mov $1, $0" : "=*m" (ptr) : "r" (val));
2626
}
2727
}
2828

29+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
30+
fn replace(ptr: &mut u32, val: u32) -> u32 {
31+
let out: u32;
32+
unsafe {
33+
asm!("mov $0, $1; mov $2, $0" : "+*m" (ptr), "=&r" (out) : "r" (val));
34+
}
35+
out
36+
}
37+
2938
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
3039
pub fn main() {
3140
let a = 1;
32-
let mut b = 2;
3341
assert_eq!(read(&a), 1);
42+
let mut b = 2;
3443
write(&mut b, 3);
3544
assert_eq!(b, 3);
45+
let mut c = 4;
46+
assert_eq!(replace(&mut c, 5), 4);
47+
assert_eq!(c, 5);
3648
}
3749

3850
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]

0 commit comments

Comments
 (0)