Skip to content

Commit dc5ad50

Browse files
committed
auto merge of #5359 : luqmana/rust/inline-asm, r=pcwalton
Continuation of #5317. Actually use operands properly now, including any number of output operands. Which means you can do things like call printf: ```Rust fn main() { unsafe { do str::as_c_str(~"The answer is %d.\n") |c| { let a = 42; asm!("mov $0, %rdi\n\t\ mov $1, %rsi\n\t\ xorl %eax, %eax\n\t\ call _printf" : : "r"(c), "r"(a) : "rdi", "rsi", "eax" : "volatile","alignstack" ); } } } ``` ``` % rustc foo.rs % ./foo The answer is 42. ``` Or just add 2 numbers: ```Rust fn add(a: int, b: int) -> int { let mut c = 0; unsafe { asm!("add $2, $0" : "=r"(c) : "0"(a), "r"(b) ); } c } fn main() { io::println(fmt!("%d", add(1, 2))); } ``` ``` % rustc foo.rs % ./foo 3 ``` Multiple outputs! ```Rust fn addsub(a: int, b: int) -> (int, int) { let mut c = 0; let mut d = 0; unsafe { asm!("add $4, $0\n\t\ sub $4, $1" : "=r"(c), "=r"(d) : "0"(a), "1"(a), "r"(b) ); } (c, d) } fn main() { io::println(fmt!("%?", addsub(5, 1))); } ``` ``` % rustc foo.rs % ./foo (6, 4) ``` This also classifies inline asm as RvalueStmtExpr instead of the somewhat arbitrary kind I made it initially. There are a few XXX's regarding what to do in the liveness and move passes.
2 parents 6f1e8ef + 83f2d4a commit dc5ad50

File tree

12 files changed

+205
-27
lines changed

12 files changed

+205
-27
lines changed

src/librustc/middle/liveness.rs

+24-2
Original file line numberDiff line numberDiff line change
@@ -1347,7 +1347,15 @@ pub impl Liveness {
13471347
self.propagate_through_expr(e, succ)
13481348
}
13491349
1350-
expr_inline_asm(*) |
1350+
expr_inline_asm(_, ins, outs, _, _, _) =>{
1351+
let succ = do ins.foldr(succ) |&(_, expr), succ| {
1352+
self.propagate_through_expr(expr, succ)
1353+
};
1354+
do outs.foldr(succ) |&(_, expr), succ| {
1355+
self.propagate_through_expr(expr, succ)
1356+
}
1357+
}
1358+
13511359
expr_lit(*) => {
13521360
succ
13531361
}
@@ -1613,6 +1621,20 @@ fn check_expr(expr: @expr, &&self: @Liveness, vt: vt<@Liveness>) {
16131621
visit::visit_expr(expr, self, vt);
16141622
}
16151623

1624+
expr_inline_asm(_, ins, outs, _, _, _) => {
1625+
for ins.each |&(_, in)| {
1626+
(vt.visit_expr)(in, self, vt);
1627+
}
1628+
1629+
// Output operands must be lvalues
1630+
for outs.each |&(_, out)| {
1631+
self.check_lvalue(out, vt);
1632+
(vt.visit_expr)(out, self, vt);
1633+
}
1634+
1635+
visit::visit_expr(expr, self, vt);
1636+
}
1637+
16161638
// no correctness conditions related to liveness
16171639
expr_call(*) | expr_method_call(*) | expr_if(*) | expr_match(*) |
16181640
expr_while(*) | expr_loop(*) | expr_index(*) | expr_field(*) |
@@ -1621,7 +1643,7 @@ fn check_expr(expr: @expr, &&self: @Liveness, vt: vt<@Liveness>) {
16211643
expr_cast(*) | expr_unary(*) | expr_ret(*) | expr_break(*) |
16221644
expr_again(*) | expr_lit(_) | expr_block(*) | expr_swap(*) |
16231645
expr_mac(*) | expr_addr_of(*) | expr_struct(*) | expr_repeat(*) |
1624-
expr_paren(*) | expr_inline_asm(*) => {
1646+
expr_paren(*) => {
16251647
visit::visit_expr(expr, self, vt);
16261648
}
16271649
}

src/librustc/middle/moves.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -558,10 +558,10 @@ pub impl VisitContext {
558558
self.use_expr(base, Read, visitor);
559559
}
560560

561+
expr_inline_asm(*) |
561562
expr_break(*) |
562563
expr_again(*) |
563-
expr_lit(*) |
564-
expr_inline_asm(*) => {}
564+
expr_lit(*) => {}
565565

566566
expr_loop(ref blk, _) => {
567567
self.consume_block(blk, visitor);

src/librustc/middle/trans/build.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,7 @@ pub fn add_comment(bcx: block, text: &str) {
873873
}
874874
875875
pub fn InlineAsmCall(cx: block, asm: *c_char, cons: *c_char,
876+
inputs: &[ValueRef], output: TypeRef,
876877
volatile: bool, alignstack: bool,
877878
dia: AsmDialect) -> ValueRef {
878879
unsafe {
@@ -883,11 +884,17 @@ pub fn InlineAsmCall(cx: block, asm: *c_char, cons: *c_char,
883884
let alignstack = if alignstack { lib::llvm::True }
884885
else { lib::llvm::False };
885886
886-
let llfty = T_fn(~[], T_void());
887+
let argtys = do inputs.map |v| {
888+
debug!("Asm Input Type: %?", val_str(cx.ccx().tn, *v));
889+
val_ty(*v)
890+
};
891+
892+
debug!("Asm Output Type: %?", ty_str(cx.ccx().tn, output));
893+
let llfty = T_fn(argtys, output);
887894
let v = llvm::LLVMInlineAsm(llfty, asm, cons, volatile,
888895
alignstack, dia as c_uint);
889896
890-
Call(cx, v, ~[])
897+
Call(cx, v, inputs)
891898
}
892899
}
893900

src/librustc/middle/trans/expr.rs

+103-11
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,109 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block {
557557
ast::expr_paren(a) => {
558558
return trans_rvalue_stmt_unadjusted(bcx, a);
559559
}
560+
ast::expr_inline_asm(asm, ref ins, ref outs,
561+
clobs, volatile, alignstack) => {
562+
let mut constraints = ~[];
563+
let mut cleanups = ~[];
564+
let mut aoutputs = ~[];
565+
566+
let outputs = do outs.map |&(c, out)| {
567+
constraints.push(copy *c);
568+
569+
let aoutty = ty::arg {
570+
mode: ast::expl(ast::by_copy),
571+
ty: expr_ty(bcx, out)
572+
};
573+
aoutputs.push(unpack_result!(bcx, {
574+
callee::trans_arg_expr(bcx, aoutty, out, &mut cleanups,
575+
None, callee::DontAutorefArg)
576+
}));
577+
578+
let e = match out.node {
579+
ast::expr_addr_of(_, e) => e,
580+
_ => fail!(~"Expression must be addr of")
581+
};
582+
583+
let outty = ty::arg {
584+
mode: ast::expl(ast::by_copy),
585+
ty: expr_ty(bcx, e)
586+
};
587+
588+
unpack_result!(bcx, {
589+
callee::trans_arg_expr(bcx, outty, e, &mut cleanups,
590+
None, callee::DontAutorefArg)
591+
})
592+
593+
};
594+
595+
for cleanups.each |c| {
596+
revoke_clean(bcx, *c);
597+
}
598+
cleanups = ~[];
599+
600+
let inputs = do ins.map |&(c, in)| {
601+
constraints.push(copy *c);
602+
603+
let inty = ty::arg {
604+
mode: ast::expl(ast::by_copy),
605+
ty: expr_ty(bcx, in)
606+
};
607+
608+
unpack_result!(bcx, {
609+
callee::trans_arg_expr(bcx, inty, in, &mut cleanups,
610+
None, callee::DontAutorefArg)
611+
})
612+
613+
};
614+
615+
for cleanups.each |c| {
616+
revoke_clean(bcx, *c);
617+
}
618+
619+
let mut constraints = str::connect(constraints, ",");
620+
621+
// Add the clobbers
622+
if *clobs != ~"" {
623+
if constraints == ~"" {
624+
constraints += *clobs;
625+
} else {
626+
constraints += ~"," + *clobs;
627+
}
628+
} else {
629+
constraints += *clobs;
630+
}
631+
632+
debug!("Asm Constraints: %?", constraints);
633+
634+
let output = if outputs.len() == 0 {
635+
T_void()
636+
} else if outputs.len() == 1 {
637+
val_ty(outputs[0])
638+
} else {
639+
T_struct(outputs.map(|o| val_ty(*o)))
640+
};
641+
642+
let r = do str::as_c_str(*asm) |a| {
643+
do str::as_c_str(constraints) |c| {
644+
InlineAsmCall(bcx, a, c, inputs, output, volatile,
645+
alignstack, lib::llvm::AD_ATT)
646+
}
647+
};
648+
649+
if outputs.len() == 1 {
650+
let op = PointerCast(bcx, aoutputs[0],
651+
T_ptr(val_ty(outputs[0])));
652+
Store(bcx, r, op);
653+
} else {
654+
for aoutputs.eachi |i, o| {
655+
let v = ExtractValue(bcx, r, i);
656+
let op = PointerCast(bcx, *o, T_ptr(val_ty(outputs[i])));
657+
Store(bcx, v, op);
658+
}
659+
}
660+
661+
return bcx;
662+
}
560663
_ => {
561664
bcx.tcx().sess.span_bug(
562665
expr.span,
@@ -691,17 +794,6 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
691794
ast::expr_assign_op(op, dst, src) => {
692795
return trans_assign_op(bcx, expr, op, dst, src);
693796
}
694-
ast::expr_inline_asm(asm, cons, volatile, alignstack) => {
695-
// XXX: cons doesn't actual contain ALL the stuff we should
696-
// be passing since the constraints for in/outputs aren't included
697-
do str::as_c_str(*asm) |a| {
698-
do str::as_c_str(*cons) |c| {
699-
InlineAsmCall(bcx, a, c, volatile, alignstack,
700-
lib::llvm::AD_ATT);
701-
}
702-
}
703-
return bcx;
704-
}
705797
_ => {
706798
bcx.tcx().sess.span_bug(
707799
expr.span,

src/librustc/middle/trans/type_use.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -348,12 +348,22 @@ pub fn mark_for_expr(cx: Context, e: @expr) {
348348
}
349349
mark_for_method_call(cx, e.id, e.callee_id);
350350
}
351+
352+
expr_inline_asm(_, ref ins, ref outs, _, _, _) => {
353+
for ins.each |&(_, in)| {
354+
node_type_needs(cx, use_repr, in.id);
355+
}
356+
for outs.each |&(_, out)| {
357+
node_type_needs(cx, use_repr, out.id);
358+
}
359+
}
360+
351361
expr_paren(e) => mark_for_expr(cx, e),
352362

353363
expr_match(*) | expr_block(_) | expr_if(*) | expr_while(*) |
354364
expr_break(_) | expr_again(_) | expr_unary(_, _) | expr_lit(_) |
355365
expr_mac(_) | expr_addr_of(_, _) | expr_ret(_) | expr_loop(_, _) |
356-
expr_loop_body(_) | expr_do_body(_) | expr_inline_asm(*) => ()
366+
expr_loop_body(_) | expr_do_body(_) => ()
357367
}
358368
}
359369

src/librustc/middle/ty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3102,7 +3102,6 @@ pub fn expr_kind(tcx: ctxt,
31023102
ast::expr_block(*) |
31033103
ast::expr_copy(*) |
31043104
ast::expr_repeat(*) |
3105-
ast::expr_inline_asm(*) |
31063105
ast::expr_lit(@codemap::spanned {node: lit_str(_), _}) |
31073106
ast::expr_vstore(_, ast::expr_vstore_slice) |
31083107
ast::expr_vstore(_, ast::expr_vstore_mut_slice) |
@@ -3145,6 +3144,7 @@ pub fn expr_kind(tcx: ctxt,
31453144
ast::expr_loop(*) |
31463145
ast::expr_assign(*) |
31473146
ast::expr_swap(*) |
3147+
ast::expr_inline_asm(*) |
31483148
ast::expr_assign_op(*) => {
31493149
RvalueStmtExpr
31503150
}

src/librustc/middle/typeck/check/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -2317,8 +2317,15 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
23172317
let region_lb = ty::re_scope(expr.id);
23182318
instantiate_path(fcx, pth, tpt, expr.span, expr.id, region_lb);
23192319
}
2320-
ast::expr_inline_asm(*) => {
2320+
ast::expr_inline_asm(_, ins, outs, _, _, _) => {
23212321
fcx.require_unsafe(expr.span, ~"use of inline assembly");
2322+
2323+
for ins.each |&(_, in)| {
2324+
check_expr(fcx, in);
2325+
}
2326+
for outs.each |&(_, out)| {
2327+
check_expr(fcx, out);
2328+
}
23222329
fcx.write_nil(id);
23232330
}
23242331
ast::expr_mac(_) => tcx.sess.bug(~"unexpanded macro"),

src/libsyntax/ast.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -601,8 +601,10 @@ pub enum expr_ {
601601
expr_ret(Option<@expr>),
602602
expr_log(log_level, @expr, @expr),
603603
604-
/* asm, clobbers + constraints, volatile, align stack */
605-
expr_inline_asm(@~str, @~str, bool, bool),
604+
expr_inline_asm(@~str, // asm
605+
~[(@~str, @expr)], // inputs
606+
~[(@~str, @expr)], // outputs
607+
@~str, bool, bool), // clobbers, volatile, align stack
606608
607609
expr_mac(mac),
608610

src/libsyntax/ext/asm.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ pub fn expand_asm(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
7575
let out = p.parse_expr();
7676
p.expect(&token::RPAREN);
7777

78+
let out = @ast::expr {
79+
id: cx.next_id(),
80+
callee_id: cx.next_id(),
81+
span: out.span,
82+
node: ast::expr_addr_of(ast::m_mutbl, out)
83+
};
84+
7885
outputs.push((constraint, out));
7986
}
8087
}
@@ -156,7 +163,8 @@ pub fn expand_asm(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
156163
MRExpr(@ast::expr {
157164
id: cx.next_id(),
158165
callee_id: cx.next_id(),
159-
node: ast::expr_inline_asm(@asm, @cons, volatile, alignstack),
166+
node: ast::expr_inline_asm(@asm, inputs, outputs,
167+
@cons, volatile, alignstack),
160168
span: sp
161169
})
162170
}

src/libsyntax/fold.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,14 @@ pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ {
560560
fld.fold_expr(e)
561561
)
562562
}
563-
expr_inline_asm(*) => copy *e,
563+
expr_inline_asm(asm, ins, outs, c, v, a) => {
564+
expr_inline_asm(
565+
asm,
566+
ins.map(|&(c, in)| (c, fld.fold_expr(in))),
567+
outs.map(|&(c, out)| (c, fld.fold_expr(out))),
568+
c, v, a
569+
)
570+
}
564571
expr_mac(ref mac) => expr_mac(fold_mac((*mac))),
565572
expr_struct(path, ref fields, maybe_expr) => {
566573
expr_struct(

src/libsyntax/print/pprust.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -1403,15 +1403,31 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) {
14031403
}
14041404
}
14051405
}
1406-
ast::expr_inline_asm(a, c, v, _) => {
1406+
ast::expr_inline_asm(a, in, out, c, v, _) => {
14071407
if v {
14081408
word(s.s, ~"__volatile__ asm!");
14091409
} else {
14101410
word(s.s, ~"asm!");
14111411
}
14121412
popen(s);
14131413
print_string(s, *a);
1414-
word_space(s, ~",");
1414+
word_space(s, ~":");
1415+
for out.each |&(co, o)| {
1416+
print_string(s, *co);
1417+
popen(s);
1418+
print_expr(s, o);
1419+
pclose(s);
1420+
word_space(s, ~",");
1421+
}
1422+
word_space(s, ~":");
1423+
for in.each |&(co, o)| {
1424+
print_string(s, *co);
1425+
popen(s);
1426+
print_expr(s, o);
1427+
pclose(s);
1428+
word_space(s, ~",");
1429+
}
1430+
word_space(s, ~":");
14151431
print_string(s, *c);
14161432
pclose(s);
14171433
}

src/libsyntax/visit.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,14 @@ pub fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
562562
}
563563
expr_mac(ref mac) => visit_mac((*mac), e, v),
564564
expr_paren(x) => (v.visit_expr)(x, e, v),
565-
expr_inline_asm(*) => (),
565+
expr_inline_asm(_, ins, outs, _, _, _) => {
566+
for ins.each |&(_, in)| {
567+
(v.visit_expr)(in, e, v);
568+
}
569+
for outs.each |&(_, out)| {
570+
(v.visit_expr)(out, e, v);
571+
}
572+
}
566573
}
567574
(v.visit_expr_post)(ex, e, v);
568575
}

0 commit comments

Comments
 (0)