Skip to content

Inline assembly, part 2 #5359

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
26 changes: 24 additions & 2 deletions src/librustc/middle/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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(*) |
Expand All @@ -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);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/moves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 9 additions & 2 deletions src/librustc/middle/trans/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
}
}

Expand Down
114 changes: 103 additions & 11 deletions src/librustc/middle/trans/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
12 changes: 11 additions & 1 deletion src/librustc/middle/trans/type_use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(_) => ()
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) |
Expand Down Expand Up @@ -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
}
Expand Down
9 changes: 8 additions & 1 deletion src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down
6 changes: 4 additions & 2 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),

Expand Down
10 changes: 9 additions & 1 deletion src/libsyntax/ext/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
Expand Down Expand Up @@ -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
})
}
Expand Down
9 changes: 8 additions & 1 deletion src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
20 changes: 18 additions & 2 deletions src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1403,15 +1403,31 @@ 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 {
word(s.s, ~"asm!");
}
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);
}
Expand Down
9 changes: 8 additions & 1 deletion src/libsyntax/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down