Skip to content
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

Inline asm cleanup #5593

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions src/librustc/middle/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1346,11 +1346,11 @@ pub impl Liveness {
self.propagate_through_expr(e, succ)
}

expr_inline_asm(_, ref ins, ref outs, _, _, _) =>{
let succ = do ins.foldr(succ) |&(_, expr), succ| {
expr_inline_asm(ref ia) =>{
let succ = do ia.inputs.foldr(succ) |&(_, expr), succ| {
self.propagate_through_expr(expr, succ)
};
do outs.foldr(succ) |&(_, expr), succ| {
do ia.outputs.foldr(succ) |&(_, expr), succ| {
self.propagate_through_expr(expr, succ)
}
}
Expand Down Expand Up @@ -1620,14 +1620,19 @@ fn check_expr(expr: @expr, &&self: @Liveness, vt: vt<@Liveness>) {
visit::visit_expr(expr, self, vt);
}

expr_inline_asm(_, ref ins, ref outs, _, _, _) => {
for ins.each |&(_, in)| {
expr_inline_asm(ref ia) => {
for ia.inputs.each |&(_, in)| {
(vt.visit_expr)(in, self, vt);
}

// Output operands must be lvalues
for outs.each |&(_, out)| {
self.check_lvalue(out, vt);
for ia.outputs.each |&(_, out)| {
match out.node {
expr_addr_of(_, inner) => {
self.check_lvalue(inner, vt);
}
_ => {}
}
(vt.visit_expr)(out, self, vt);
}

Expand Down
154 changes: 154 additions & 0 deletions src/librustc/middle/trans/asm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
# Translation of inline assembly.
*/

use core::prelude::*;

use lib;
use middle::trans::build::*;
use middle::trans::callee;
use middle::trans::common::*;
use middle::ty;

use syntax::ast;

// Take an inline assembly expression and splat it out via LLVM
pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block {

let mut bcx = bcx;
let mut constraints = ~[];
let mut cleanups = ~[];
let mut aoutputs = ~[];

// Prepare the output operands
let outputs = do ia.outputs.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.clear();

// Now the input operands
let inputs = do ia.inputs.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, ",");

let mut clobbers = getClobbers();
if *ia.clobbers != ~"" && clobbers != ~"" {
clobbers = *ia.clobbers + ~"," + clobbers;
} else {
clobbers += *ia.clobbers;
};

// Add the clobbers to our constraints list
if clobbers != ~"" && constraints != ~"" {
constraints += ~"," + clobbers;
} else {
constraints += clobbers;
}

debug!("Asm Constraints: %?", constraints);

let numOutputs = outputs.len();

// Depending on how many outputs we have, the return type is different
let output = if numOutputs == 0 {
T_void()
} else if numOutputs == 1 {
val_ty(outputs[0])
} else {
T_struct(outputs.map(|o| val_ty(*o)))
};

let dialect = match ia.dialect {
ast::asm_att => lib::llvm::AD_ATT,
ast::asm_intel => lib::llvm::AD_Intel
};

let r = do str::as_c_str(*ia.asm) |a| {
do str::as_c_str(constraints) |c| {
InlineAsmCall(bcx, a, c, inputs, output, ia.volatile, ia.alignstack, dialect)
}
};

// Again, based on how many outputs we have
if numOutputs == 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;

}

// Default per-arch clobbers
// Basically what clang does

#[cfg(target_arch = "arm")]
#[cfg(target_arch = "mips")]
fn getClobbers() -> ~str {
~""
}

#[cfg(target_arch = "x86")]
#[cfg(target_arch = "x86_64")]
fn getClobbers() -> ~str {
~"~{dirflag},~{fpsr},~{flags}"
}
105 changes: 3 additions & 102 deletions src/librustc/middle/trans/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ use lib::llvm::{ValueRef, TypeRef, llvm, True};
use middle::borrowck::root_map_key;
use middle::trans::_match;
use middle::trans::adt;
use middle::trans::asm;
use middle::trans::base;
use middle::trans::base::*;
use middle::trans::build::*;
Expand Down Expand Up @@ -557,108 +558,8 @@ 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;
ast::expr_inline_asm(ref a) => {
return asm::trans_inline_asm(bcx, a);
}
_ => {
bcx.tcx().sess.span_bug(
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/middle/trans/type_use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,11 +360,11 @@ 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)| {
expr_inline_asm(ref ia) => {
for ia.inputs.each |&(_, in)| {
node_type_needs(cx, use_repr, in.id);
}
for outs.each |&(_, out)| {
for ia.outputs.each |&(_, out)| {
node_type_needs(cx, use_repr, out.id);
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2332,13 +2332,13 @@ 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(_, ref ins, ref outs, _, _, _) => {
ast::expr_inline_asm(ref ia) => {
fcx.require_unsafe(expr.span, ~"use of inline assembly");

for ins.each |&(_, in)| {
for ia.inputs.each |&(_, in)| {
check_expr(fcx, in);
}
for outs.each |&(_, out)| {
for ia.outputs.each |&(_, out)| {
check_expr(fcx, out);
}
fcx.write_nil(id);
Expand Down
1 change: 1 addition & 0 deletions src/librustc/rustc.rc
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ pub mod middle {
pub mod reachable;
pub mod machine;
pub mod adt;
pub mod asm;
}
pub mod ty;
pub mod resolve;
Expand Down
26 changes: 22 additions & 4 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,10 +600,7 @@ pub enum expr_ {
expr_ret(Option<@expr>),
expr_log(log_level, @expr, @expr),

expr_inline_asm(@~str, // asm
~[(@~str, @expr)], // inputs
~[(@~str, @expr)], // outputs
@~str, bool, bool), // clobbers, volatile, align stack
expr_inline_asm(inline_asm),

expr_mac(mac),

Expand Down Expand Up @@ -937,6 +934,27 @@ impl to_bytes::IterBytes for Ty {
}
}

#[auto_encode]
#[auto_decode]
#[deriving(Eq)]
pub enum asm_dialect {
asm_att,
asm_intel
}

#[auto_encode]
#[auto_decode]
#[deriving(Eq)]
pub struct inline_asm {
asm: @~str,
clobbers: @~str,
inputs: ~[(@~str, @expr)],
outputs: ~[(@~str, @expr)],
volatile: bool,
alignstack: bool,
dialect: asm_dialect
}

#[auto_encode]
#[auto_decode]
#[deriving(Eq)]
Expand Down
Loading