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.
This commit is contained in:
commit
dc5ad5070d
@ -1347,7 +1347,15 @@ pub impl Liveness {
|
||||
self.propagate_through_expr(e, succ)
|
||||
}
|
||||
|
||||
expr_inline_asm(*) |
|
||||
expr_inline_asm(_, ins, outs, _, _, _) =>{
|
||||
let succ = do ins.foldr(succ) |&(_, expr), succ| {
|
||||
self.propagate_through_expr(expr, succ)
|
||||
};
|
||||
do outs.foldr(succ) |&(_, expr), succ| {
|
||||
self.propagate_through_expr(expr, succ)
|
||||
}
|
||||
}
|
||||
|
||||
expr_lit(*) => {
|
||||
succ
|
||||
}
|
||||
@ -1613,6 +1621,20 @@ fn check_expr(expr: @expr, &&self: @Liveness, vt: vt<@Liveness>) {
|
||||
visit::visit_expr(expr, self, vt);
|
||||
}
|
||||
|
||||
expr_inline_asm(_, ins, outs, _, _, _) => {
|
||||
for ins.each |&(_, in)| {
|
||||
(vt.visit_expr)(in, self, vt);
|
||||
}
|
||||
|
||||
// Output operands must be lvalues
|
||||
for outs.each |&(_, out)| {
|
||||
self.check_lvalue(out, vt);
|
||||
(vt.visit_expr)(out, self, vt);
|
||||
}
|
||||
|
||||
visit::visit_expr(expr, self, vt);
|
||||
}
|
||||
|
||||
// no correctness conditions related to liveness
|
||||
expr_call(*) | expr_method_call(*) | expr_if(*) | expr_match(*) |
|
||||
expr_while(*) | expr_loop(*) | expr_index(*) | expr_field(*) |
|
||||
@ -1621,7 +1643,7 @@ fn check_expr(expr: @expr, &&self: @Liveness, vt: vt<@Liveness>) {
|
||||
expr_cast(*) | expr_unary(*) | expr_ret(*) | expr_break(*) |
|
||||
expr_again(*) | expr_lit(_) | expr_block(*) | expr_swap(*) |
|
||||
expr_mac(*) | expr_addr_of(*) | expr_struct(*) | expr_repeat(*) |
|
||||
expr_paren(*) | expr_inline_asm(*) => {
|
||||
expr_paren(*) => {
|
||||
visit::visit_expr(expr, self, vt);
|
||||
}
|
||||
}
|
||||
|
@ -558,10 +558,10 @@ pub impl VisitContext {
|
||||
self.use_expr(base, Read, visitor);
|
||||
}
|
||||
|
||||
expr_inline_asm(*) |
|
||||
expr_break(*) |
|
||||
expr_again(*) |
|
||||
expr_lit(*) |
|
||||
expr_inline_asm(*) => {}
|
||||
expr_lit(*) => {}
|
||||
|
||||
expr_loop(ref blk, _) => {
|
||||
self.consume_block(blk, visitor);
|
||||
|
@ -873,6 +873,7 @@ pub fn add_comment(bcx: block, text: &str) {
|
||||
}
|
||||
|
||||
pub fn InlineAsmCall(cx: block, asm: *c_char, cons: *c_char,
|
||||
inputs: &[ValueRef], output: TypeRef,
|
||||
volatile: bool, alignstack: bool,
|
||||
dia: AsmDialect) -> ValueRef {
|
||||
unsafe {
|
||||
@ -883,11 +884,17 @@ pub fn InlineAsmCall(cx: block, asm: *c_char, cons: *c_char,
|
||||
let alignstack = if alignstack { lib::llvm::True }
|
||||
else { lib::llvm::False };
|
||||
|
||||
let llfty = T_fn(~[], T_void());
|
||||
let argtys = do inputs.map |v| {
|
||||
debug!("Asm Input Type: %?", val_str(cx.ccx().tn, *v));
|
||||
val_ty(*v)
|
||||
};
|
||||
|
||||
debug!("Asm Output Type: %?", ty_str(cx.ccx().tn, output));
|
||||
let llfty = T_fn(argtys, output);
|
||||
let v = llvm::LLVMInlineAsm(llfty, asm, cons, volatile,
|
||||
alignstack, dia as c_uint);
|
||||
|
||||
Call(cx, v, ~[])
|
||||
Call(cx, v, inputs)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -557,6 +557,109 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block {
|
||||
ast::expr_paren(a) => {
|
||||
return trans_rvalue_stmt_unadjusted(bcx, a);
|
||||
}
|
||||
ast::expr_inline_asm(asm, ref ins, ref outs,
|
||||
clobs, volatile, alignstack) => {
|
||||
let mut constraints = ~[];
|
||||
let mut cleanups = ~[];
|
||||
let mut aoutputs = ~[];
|
||||
|
||||
let outputs = do outs.map |&(c, out)| {
|
||||
constraints.push(copy *c);
|
||||
|
||||
let aoutty = ty::arg {
|
||||
mode: ast::expl(ast::by_copy),
|
||||
ty: expr_ty(bcx, out)
|
||||
};
|
||||
aoutputs.push(unpack_result!(bcx, {
|
||||
callee::trans_arg_expr(bcx, aoutty, out, &mut cleanups,
|
||||
None, callee::DontAutorefArg)
|
||||
}));
|
||||
|
||||
let e = match out.node {
|
||||
ast::expr_addr_of(_, e) => e,
|
||||
_ => fail!(~"Expression must be addr of")
|
||||
};
|
||||
|
||||
let outty = ty::arg {
|
||||
mode: ast::expl(ast::by_copy),
|
||||
ty: expr_ty(bcx, e)
|
||||
};
|
||||
|
||||
unpack_result!(bcx, {
|
||||
callee::trans_arg_expr(bcx, outty, e, &mut cleanups,
|
||||
None, callee::DontAutorefArg)
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
for cleanups.each |c| {
|
||||
revoke_clean(bcx, *c);
|
||||
}
|
||||
cleanups = ~[];
|
||||
|
||||
let inputs = do ins.map |&(c, in)| {
|
||||
constraints.push(copy *c);
|
||||
|
||||
let inty = ty::arg {
|
||||
mode: ast::expl(ast::by_copy),
|
||||
ty: expr_ty(bcx, in)
|
||||
};
|
||||
|
||||
unpack_result!(bcx, {
|
||||
callee::trans_arg_expr(bcx, inty, in, &mut cleanups,
|
||||
None, callee::DontAutorefArg)
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
for cleanups.each |c| {
|
||||
revoke_clean(bcx, *c);
|
||||
}
|
||||
|
||||
let mut constraints = str::connect(constraints, ",");
|
||||
|
||||
// Add the clobbers
|
||||
if *clobs != ~"" {
|
||||
if constraints == ~"" {
|
||||
constraints += *clobs;
|
||||
} else {
|
||||
constraints += ~"," + *clobs;
|
||||
}
|
||||
} else {
|
||||
constraints += *clobs;
|
||||
}
|
||||
|
||||
debug!("Asm Constraints: %?", constraints);
|
||||
|
||||
let output = if outputs.len() == 0 {
|
||||
T_void()
|
||||
} else if outputs.len() == 1 {
|
||||
val_ty(outputs[0])
|
||||
} else {
|
||||
T_struct(outputs.map(|o| val_ty(*o)))
|
||||
};
|
||||
|
||||
let r = do str::as_c_str(*asm) |a| {
|
||||
do str::as_c_str(constraints) |c| {
|
||||
InlineAsmCall(bcx, a, c, inputs, output, volatile,
|
||||
alignstack, lib::llvm::AD_ATT)
|
||||
}
|
||||
};
|
||||
|
||||
if outputs.len() == 1 {
|
||||
let op = PointerCast(bcx, aoutputs[0],
|
||||
T_ptr(val_ty(outputs[0])));
|
||||
Store(bcx, r, op);
|
||||
} else {
|
||||
for aoutputs.eachi |i, o| {
|
||||
let v = ExtractValue(bcx, r, i);
|
||||
let op = PointerCast(bcx, *o, T_ptr(val_ty(outputs[i])));
|
||||
Store(bcx, v, op);
|
||||
}
|
||||
}
|
||||
|
||||
return bcx;
|
||||
}
|
||||
_ => {
|
||||
bcx.tcx().sess.span_bug(
|
||||
expr.span,
|
||||
@ -691,17 +794,6 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
|
||||
ast::expr_assign_op(op, dst, src) => {
|
||||
return trans_assign_op(bcx, expr, op, dst, src);
|
||||
}
|
||||
ast::expr_inline_asm(asm, cons, volatile, alignstack) => {
|
||||
// XXX: cons doesn't actual contain ALL the stuff we should
|
||||
// be passing since the constraints for in/outputs aren't included
|
||||
do str::as_c_str(*asm) |a| {
|
||||
do str::as_c_str(*cons) |c| {
|
||||
InlineAsmCall(bcx, a, c, volatile, alignstack,
|
||||
lib::llvm::AD_ATT);
|
||||
}
|
||||
}
|
||||
return bcx;
|
||||
}
|
||||
_ => {
|
||||
bcx.tcx().sess.span_bug(
|
||||
expr.span,
|
||||
|
@ -348,12 +348,22 @@ pub fn mark_for_expr(cx: Context, e: @expr) {
|
||||
}
|
||||
mark_for_method_call(cx, e.id, e.callee_id);
|
||||
}
|
||||
|
||||
expr_inline_asm(_, ref ins, ref outs, _, _, _) => {
|
||||
for ins.each |&(_, in)| {
|
||||
node_type_needs(cx, use_repr, in.id);
|
||||
}
|
||||
for outs.each |&(_, out)| {
|
||||
node_type_needs(cx, use_repr, out.id);
|
||||
}
|
||||
}
|
||||
|
||||
expr_paren(e) => mark_for_expr(cx, e),
|
||||
|
||||
expr_match(*) | expr_block(_) | expr_if(*) | expr_while(*) |
|
||||
expr_break(_) | expr_again(_) | expr_unary(_, _) | expr_lit(_) |
|
||||
expr_mac(_) | expr_addr_of(_, _) | expr_ret(_) | expr_loop(_, _) |
|
||||
expr_loop_body(_) | expr_do_body(_) | expr_inline_asm(*) => ()
|
||||
expr_loop_body(_) | expr_do_body(_) => ()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3102,7 +3102,6 @@ pub fn expr_kind(tcx: ctxt,
|
||||
ast::expr_block(*) |
|
||||
ast::expr_copy(*) |
|
||||
ast::expr_repeat(*) |
|
||||
ast::expr_inline_asm(*) |
|
||||
ast::expr_lit(@codemap::spanned {node: lit_str(_), _}) |
|
||||
ast::expr_vstore(_, ast::expr_vstore_slice) |
|
||||
ast::expr_vstore(_, ast::expr_vstore_mut_slice) |
|
||||
@ -3145,6 +3144,7 @@ pub fn expr_kind(tcx: ctxt,
|
||||
ast::expr_loop(*) |
|
||||
ast::expr_assign(*) |
|
||||
ast::expr_swap(*) |
|
||||
ast::expr_inline_asm(*) |
|
||||
ast::expr_assign_op(*) => {
|
||||
RvalueStmtExpr
|
||||
}
|
||||
|
@ -2317,8 +2317,15 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
|
||||
let region_lb = ty::re_scope(expr.id);
|
||||
instantiate_path(fcx, pth, tpt, expr.span, expr.id, region_lb);
|
||||
}
|
||||
ast::expr_inline_asm(*) => {
|
||||
ast::expr_inline_asm(_, ins, outs, _, _, _) => {
|
||||
fcx.require_unsafe(expr.span, ~"use of inline assembly");
|
||||
|
||||
for ins.each |&(_, in)| {
|
||||
check_expr(fcx, in);
|
||||
}
|
||||
for outs.each |&(_, out)| {
|
||||
check_expr(fcx, out);
|
||||
}
|
||||
fcx.write_nil(id);
|
||||
}
|
||||
ast::expr_mac(_) => tcx.sess.bug(~"unexpanded macro"),
|
||||
|
@ -601,8 +601,10 @@ pub enum expr_ {
|
||||
expr_ret(Option<@expr>),
|
||||
expr_log(log_level, @expr, @expr),
|
||||
|
||||
/* asm, clobbers + constraints, volatile, align stack */
|
||||
expr_inline_asm(@~str, @~str, bool, bool),
|
||||
expr_inline_asm(@~str, // asm
|
||||
~[(@~str, @expr)], // inputs
|
||||
~[(@~str, @expr)], // outputs
|
||||
@~str, bool, bool), // clobbers, volatile, align stack
|
||||
|
||||
expr_mac(mac),
|
||||
|
||||
|
@ -75,6 +75,13 @@ pub fn expand_asm(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
|
||||
let out = p.parse_expr();
|
||||
p.expect(&token::RPAREN);
|
||||
|
||||
let out = @ast::expr {
|
||||
id: cx.next_id(),
|
||||
callee_id: cx.next_id(),
|
||||
span: out.span,
|
||||
node: ast::expr_addr_of(ast::m_mutbl, out)
|
||||
};
|
||||
|
||||
outputs.push((constraint, out));
|
||||
}
|
||||
}
|
||||
@ -156,7 +163,8 @@ pub fn expand_asm(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
|
||||
MRExpr(@ast::expr {
|
||||
id: cx.next_id(),
|
||||
callee_id: cx.next_id(),
|
||||
node: ast::expr_inline_asm(@asm, @cons, volatile, alignstack),
|
||||
node: ast::expr_inline_asm(@asm, inputs, outputs,
|
||||
@cons, volatile, alignstack),
|
||||
span: sp
|
||||
})
|
||||
}
|
||||
|
@ -560,7 +560,14 @@ pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ {
|
||||
fld.fold_expr(e)
|
||||
)
|
||||
}
|
||||
expr_inline_asm(*) => copy *e,
|
||||
expr_inline_asm(asm, ins, outs, c, v, a) => {
|
||||
expr_inline_asm(
|
||||
asm,
|
||||
ins.map(|&(c, in)| (c, fld.fold_expr(in))),
|
||||
outs.map(|&(c, out)| (c, fld.fold_expr(out))),
|
||||
c, v, a
|
||||
)
|
||||
}
|
||||
expr_mac(ref mac) => expr_mac(fold_mac((*mac))),
|
||||
expr_struct(path, ref fields, maybe_expr) => {
|
||||
expr_struct(
|
||||
|
@ -1403,7 +1403,7 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) {
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::expr_inline_asm(a, c, v, _) => {
|
||||
ast::expr_inline_asm(a, in, out, c, v, _) => {
|
||||
if v {
|
||||
word(s.s, ~"__volatile__ asm!");
|
||||
} else {
|
||||
@ -1411,7 +1411,23 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) {
|
||||
}
|
||||
popen(s);
|
||||
print_string(s, *a);
|
||||
word_space(s, ~",");
|
||||
word_space(s, ~":");
|
||||
for out.each |&(co, o)| {
|
||||
print_string(s, *co);
|
||||
popen(s);
|
||||
print_expr(s, o);
|
||||
pclose(s);
|
||||
word_space(s, ~",");
|
||||
}
|
||||
word_space(s, ~":");
|
||||
for in.each |&(co, o)| {
|
||||
print_string(s, *co);
|
||||
popen(s);
|
||||
print_expr(s, o);
|
||||
pclose(s);
|
||||
word_space(s, ~",");
|
||||
}
|
||||
word_space(s, ~":");
|
||||
print_string(s, *c);
|
||||
pclose(s);
|
||||
}
|
||||
|
@ -562,7 +562,14 @@ pub fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
|
||||
}
|
||||
expr_mac(ref mac) => visit_mac((*mac), e, v),
|
||||
expr_paren(x) => (v.visit_expr)(x, e, v),
|
||||
expr_inline_asm(*) => (),
|
||||
expr_inline_asm(_, ins, outs, _, _, _) => {
|
||||
for ins.each |&(_, in)| {
|
||||
(v.visit_expr)(in, e, v);
|
||||
}
|
||||
for outs.each |&(_, out)| {
|
||||
(v.visit_expr)(out, e, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
(v.visit_expr_post)(ex, e, v);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user