self.straightline(expr, pred, Some(&**e).into_iter())
}
- hir::ExprInlineAsm(ref inline_asm) => {
- let inputs = inline_asm.inputs.iter();
- let outputs = inline_asm.outputs.iter();
- let post_inputs = self.exprs(inputs.map(|a| {
- debug!("cfg::construct InlineAsm id:{} input:{:?}", expr.id, a);
- let &(_, ref expr) = a;
- &**expr
- }), pred);
- let post_outputs = self.exprs(outputs.map(|a| {
- debug!("cfg::construct InlineAsm id:{} output:{:?}", expr.id, a);
- &*a.expr
- }), post_inputs);
- self.add_ast_node(expr.id, &[post_outputs])
+ hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
+ let post_outputs = self.exprs(outputs.iter().map(|e| &**e), pred);
+ let post_inputs = self.exprs(inputs.iter().map(|e| &**e), post_outputs);
+ self.add_ast_node(expr.id, &[post_inputs])
}
hir::ExprClosure(..) |
}
}
- hir::ExprInlineAsm(ref ia) => {
- for &(_, ref input) in &ia.inputs {
- self.consume_expr(&input);
- }
-
- for output in &ia.outputs {
- if output.is_indirect {
- self.consume_expr(&output.expr);
+ hir::ExprInlineAsm(ref ia, ref outputs, ref inputs) => {
+ for (o, output) in ia.outputs.iter().zip(outputs) {
+ if o.is_indirect {
+ self.consume_expr(output);
} else {
- self.mutate_expr(expr, &output.expr,
- if output.is_rw {
+ self.mutate_expr(expr, output,
+ if o.is_rw {
MutateMode::WriteAndRead
} else {
MutateMode::JustWrite
});
}
}
+ self.consume_exprs(inputs);
}
hir::ExprBreak(..) |
self.propagate_through_expr(&e, succ)
}
- hir::ExprInlineAsm(ref ia) => {
-
- let succ = ia.outputs.iter().rev().fold(succ,
- |succ, out| {
- // see comment on lvalues
- // in propagate_through_lvalue_components()
- if out.is_indirect {
- self.propagate_through_expr(&out.expr, succ)
- } else {
- let acc = if out.is_rw { ACC_WRITE|ACC_READ } else { ACC_WRITE };
- let succ = self.write_lvalue(&out.expr, succ, acc);
- self.propagate_through_lvalue_components(&out.expr, succ)
- }
+ hir::ExprInlineAsm(ref ia, ref outputs, ref inputs) => {
+ let succ = ia.outputs.iter().zip(outputs).rev().fold(succ, |succ, (o, output)| {
+ // see comment on lvalues
+ // in propagate_through_lvalue_components()
+ if o.is_indirect {
+ self.propagate_through_expr(output, succ)
+ } else {
+ let acc = if o.is_rw { ACC_WRITE|ACC_READ } else { ACC_WRITE };
+ let succ = self.write_lvalue(output, succ, acc);
+ self.propagate_through_lvalue_components(output, succ)
}
- );
+ });
+
// Inputs are executed first. Propagate last because of rev order
- ia.inputs.iter().rev().fold(succ, |succ, &(_, ref expr)| {
- self.propagate_through_expr(&expr, succ)
- })
+ self.propagate_through_exprs(inputs, succ)
}
hir::ExprLit(..) => {
intravisit::walk_expr(this, expr);
}
- hir::ExprInlineAsm(ref ia) => {
- for &(_, ref input) in &ia.inputs {
- this.visit_expr(&input);
+ hir::ExprInlineAsm(ref ia, ref outputs, ref inputs) => {
+ for input in inputs {
+ this.visit_expr(input);
}
// Output operands must be lvalues
- for out in &ia.outputs {
- if !out.is_indirect {
- this.check_lvalue(&out.expr);
+ for (o, output) in ia.outputs.iter().zip(outputs) {
+ if !o.is_indirect {
+ this.check_lvalue(output);
}
- this.visit_expr(&out.expr);
+ this.visit_expr(output);
}
intravisit::walk_expr(this, expr);
from_end: usize,
},
- InlineAsm(InlineAsm),
+ InlineAsm {
+ asm: InlineAsm,
+ outputs: Vec<Lvalue<'tcx>>,
+ inputs: Vec<Operand<'tcx>>
+ }
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
BinaryOp(ref op, ref a, ref b) => write!(fmt, "{:?}({:?}, {:?})", op, a, b),
UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a),
Box(ref t) => write!(fmt, "Box({:?})", t),
- InlineAsm(ref asm) => write!(fmt, "InlineAsm({:?})", asm),
+ InlineAsm { ref asm, ref outputs, ref inputs } => {
+ write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs)
+ }
Slice { ref input, from_start, from_end } =>
write!(fmt, "{:?}[{:?}..-{:?}]", input, from_start, from_end),
}
}
Rvalue::Slice { .. } => None,
- Rvalue::InlineAsm(..) => None
+ Rvalue::InlineAsm { .. } => None
}
}
}
});
}
- Rvalue::InlineAsm(_) => {
+ Rvalue::InlineAsm { ref $($mutability)* outputs,
+ ref $($mutability)* inputs, .. } => {
+ for output in & $($mutability)* outputs[..] {
+ self.visit_lvalue(output, LvalueContext::Store);
+ }
+ for input in & $($mutability)* inputs[..] {
+ self.visit_operand(input);
+ }
}
}
}
ExprBreak(id) => SawExprBreak(id.map(|id| id.node.name.as_str())),
ExprAgain(id) => SawExprAgain(id.map(|id| id.node.name.as_str())),
ExprRet(..) => SawExprRet,
- ExprInlineAsm(ref asm) => SawExprInlineAsm(asm),
+ ExprInlineAsm(ref a,_,_) => SawExprInlineAsm(a),
ExprStruct(..) => SawExprStruct,
ExprRepeat(..) => SawExprRepeat,
}
respan(folder.new_span(label.span), folder.fold_ident(label.node))
})),
ExprRet(e) => ExprRet(e.map(|x| folder.fold_expr(x))),
- ExprInlineAsm(InlineAsm {
- inputs,
- outputs,
- asm,
- asm_str_style,
- clobbers,
- volatile,
- alignstack,
- dialect,
- expn_id,
- }) => ExprInlineAsm(InlineAsm {
- inputs: inputs.move_map(|(c, input)| (c, folder.fold_expr(input))),
- outputs: outputs.move_map(|out| {
- InlineAsmOutput {
- constraint: out.constraint,
- expr: folder.fold_expr(out.expr),
- is_rw: out.is_rw,
- is_indirect: out.is_indirect,
- }
- }),
- asm: asm,
- asm_str_style: asm_str_style,
- clobbers: clobbers,
- volatile: volatile,
- alignstack: alignstack,
- dialect: dialect,
- expn_id: expn_id,
- }),
+ ExprInlineAsm(asm, outputs, inputs) => {
+ ExprInlineAsm(asm,
+ outputs.move_map(|x| folder.fold_expr(x)),
+ inputs.move_map(|x| folder.fold_expr(x)))
+ }
ExprStruct(path, fields, maybe_expr) => {
ExprStruct(folder.fold_path(path),
fields.move_map(|x| folder.fold_field(x)),
/// A `return`, with an optional value to be returned
ExprRet(Option<P<Expr>>),
- /// Output of the `asm!()` macro
- ExprInlineAsm(InlineAsm),
+ /// Inline assembly (from `asm!`), with its outputs and inputs.
+ ExprInlineAsm(InlineAsm, Vec<P<Expr>>, Vec<P<Expr>>),
/// A struct literal expression.
///
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct InlineAsmOutput {
pub constraint: InternedString,
- pub expr: P<Expr>,
pub is_rw: bool,
pub is_indirect: bool,
}
pub asm: InternedString,
pub asm_str_style: StrStyle,
pub outputs: HirVec<InlineAsmOutput>,
- pub inputs: HirVec<(InternedString, P<Expr>)>,
+ pub inputs: HirVec<InternedString>,
pub clobbers: HirVec<InternedString>,
pub volatile: bool,
pub alignstack: bool,
ExprRet(ref optional_expression) => {
walk_list!(visitor, visit_expr, optional_expression);
}
- ExprInlineAsm(ref ia) => {
- for &(_, ref input) in &ia.inputs {
- visitor.visit_expr(&input)
+ ExprInlineAsm(_, ref outputs, ref inputs) => {
+ for output in outputs {
+ visitor.visit_expr(output)
}
- for output in &ia.outputs {
- visitor.visit_expr(&output.expr)
+ for input in inputs {
+ visitor.visit_expr(input)
}
}
}
dialect,
expn_id,
}) => hir::ExprInlineAsm(hir::InlineAsm {
- inputs: inputs.iter()
- .map(|&(ref c, ref input)| (c.clone(), lower_expr(lctx, input)))
- .collect(),
+ inputs: inputs.iter().map(|&(ref c, _)| c.clone()).collect(),
outputs: outputs.iter()
.map(|out| {
hir::InlineAsmOutput {
constraint: out.constraint.clone(),
- expr: lower_expr(lctx, &out.expr),
is_rw: out.is_rw,
is_indirect: out.is_indirect,
}
alignstack: alignstack,
dialect: dialect,
expn_id: expn_id,
- }),
+ }, outputs.iter().map(|out| lower_expr(lctx, &out.expr)).collect(),
+ inputs.iter().map(|&(_, ref input)| lower_expr(lctx, input)).collect()),
ExprKind::Struct(ref path, ref fields, ref maybe_expr) => {
hir::ExprStruct(lower_path(lctx, path),
fields.iter().map(|x| lower_field(lctx, x)).collect(),
_ => (),
}
}
- hir::ExprInlineAsm(ref a) => {
+ hir::ExprInlineAsm(ref a, ref outputs, ref inputs) => {
try!(word(&mut self.s, "asm!"));
try!(self.popen());
try!(self.print_string(&a.asm, a.asm_str_style));
try!(self.word_space(":"));
+ let mut out_idx = 0;
try!(self.commasep(Inconsistent, &a.outputs, |s, out| {
match out.constraint.slice_shift_char() {
Some(('=', operand)) if out.is_rw => {
_ => try!(s.print_string(&out.constraint, ast::StrStyle::Cooked)),
}
try!(s.popen());
- try!(s.print_expr(&out.expr));
+ try!(s.print_expr(&outputs[out_idx]));
try!(s.pclose());
+ out_idx += 1;
Ok(())
}));
try!(space(&mut self.s));
try!(self.word_space(":"));
- try!(self.commasep(Inconsistent, &a.inputs, |s, &(ref co, ref o)| {
+ let mut in_idx = 0;
+ try!(self.commasep(Inconsistent, &a.inputs, |s, co| {
try!(s.print_string(&co, ast::StrStyle::Cooked));
try!(s.popen());
- try!(s.print_expr(&o));
+ try!(s.print_expr(&inputs[in_idx]));
try!(s.pclose());
+ in_idx += 1;
Ok(())
}));
try!(space(&mut self.s));
ExprKind::Scope { extent, value } => {
this.in_scope(extent, block, |this| this.as_rvalue(block, value))
}
- ExprKind::InlineAsm { asm } => {
- block.and(Rvalue::InlineAsm(asm.clone()))
+ ExprKind::InlineAsm { asm, outputs, inputs } => {
+ let outputs = outputs.into_iter().map(|output| {
+ unpack!(block = this.as_lvalue(block, output))
+ }).collect();
+
+ let inputs = inputs.into_iter().map(|input| {
+ unpack!(block = this.as_operand(block, input))
+ }).collect();
+
+ block.and(Rvalue::InlineAsm {
+ asm: asm.clone(),
+ outputs: outputs,
+ inputs: inputs
+ })
}
ExprKind::Repeat { value, count } => {
let value_operand = unpack!(block = this.as_operand(block, value));
convert_path_expr(cx, self)
}
- hir::ExprInlineAsm(ref asm) => {
- ExprKind::InlineAsm { asm: asm }
+ hir::ExprInlineAsm(ref asm, ref outputs, ref inputs) => {
+ ExprKind::InlineAsm {
+ asm: asm,
+ outputs: outputs.to_ref(),
+ inputs: inputs.to_ref()
+ }
}
// Now comes the rote stuff:
},
InlineAsm {
asm: &'tcx hir::InlineAsm,
+ outputs: Vec<ExprRef<'tcx>>,
+ inputs: Vec<ExprRef<'tcx>>
},
}
Rvalue::BinaryOp(_, _, _) |
Rvalue::UnaryOp(_, _) |
Rvalue::Slice { input: _, from_start: _, from_end: _ } |
- Rvalue::InlineAsm(_) => {},
+ Rvalue::InlineAsm {..} => {},
Rvalue::Repeat(_, ref mut value) => value.ty = self.tcx.erase_regions(&value.ty),
Rvalue::Ref(ref mut region, _, _) => *region = ty::ReStatic,
// Expressions with side-effects.
hir::ExprAssign(..) |
hir::ExprAssignOp(..) |
- hir::ExprInlineAsm(_) => {
+ hir::ExprInlineAsm(..) => {
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0019,
//! # Translation of inline assembly.
use llvm::{self, ValueRef};
+use trans::base;
use trans::build::*;
use trans::common::*;
-use trans::cleanup;
-use trans::cleanup::CleanupMethods;
-use trans::datum::{Datum, Expr};
-use trans::expr;
+use trans::datum::{Datum, Lvalue};
use trans::type_of;
use trans::type_::Type;
use libc::{c_uint, c_char};
// Take an inline assembly expression and splat it out via LLVM
-pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
- -> Block<'blk, 'tcx> {
- let fcx = bcx.fcx;
- let mut bcx = bcx;
- let mut constraints = Vec::new();
- let mut output_types = Vec::new();
-
- let temp_scope = fcx.push_custom_cleanup_scope();
-
- let take_datum = |mut bcx: Block<'blk, 'tcx>,
- arg_datum: Datum<'tcx, Expr>,
- llargs: &mut Vec<ValueRef>|
- -> Block<'blk, 'tcx> {
- // Make this an rvalue, since we are going to be
- // passing ownership.
- let arg_datum = unpack_datum!(
- bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
-
- // Now that arg_datum is owned, get it into the appropriate
- // mode (ref vs value).
- let arg_datum = unpack_datum!(
- bcx, arg_datum.to_appropriate_datum(bcx));
-
- // Technically, ownership of val passes to the callee.
- // However, we must cleanup should we panic before the
- // callee is actually invoked.
- let val = arg_datum.add_clean(bcx.fcx,
- cleanup::CustomScope(temp_scope));
- llargs.push(val);
- bcx
- };
-
- let mut ext_inputs = Vec::new();
- let mut ext_constraints = Vec::new();
+pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ ia: &ast::InlineAsm,
+ outputs: Vec<Datum<'tcx, Lvalue>>,
+ mut inputs: Vec<ValueRef>) {
+ let mut ext_constraints = vec![];
+ let mut output_types = vec![];
// Prepare the output operands
- let mut outputs = Vec::new();
- let mut inputs = Vec::new();
- for (i, out) in ia.outputs.iter().enumerate() {
- constraints.push(out.constraint.clone());
-
- let out_datum = unpack_datum!(bcx, expr::trans(bcx, &out.expr));
+ let mut indirect_outputs = vec![];
+ for (i, (out, out_datum)) in ia.outputs.iter().zip(&outputs).enumerate() {
+ let val = if out.is_rw || out.is_indirect {
+ Some(base::load_ty(bcx, out_datum.val, out_datum.ty))
+ } else {
+ None
+ };
+ if out.is_rw {
+ inputs.push(val.unwrap());
+ ext_constraints.push(i.to_string());
+ }
if out.is_indirect {
- bcx = take_datum(bcx, out_datum, &mut inputs);
- if out.is_rw {
- ext_inputs.push(*inputs.last().unwrap());
- ext_constraints.push(i.to_string());
- }
+ indirect_outputs.push(val.unwrap());
} else {
output_types.push(type_of::type_of(bcx.ccx(), out_datum.ty));
- outputs.push(out_datum.val);
- if out.is_rw {
- bcx = take_datum(bcx, out_datum, &mut ext_inputs);
- ext_constraints.push(i.to_string());
- }
}
}
-
- // Now the input operands
- for &(ref c, ref input) in &ia.inputs {
- constraints.push((*c).clone());
-
- let in_datum = unpack_datum!(bcx, expr::trans(bcx, &input));
- bcx = take_datum(bcx, in_datum, &mut inputs);
+ if !indirect_outputs.is_empty() {
+ indirect_outputs.extend_from_slice(&inputs);
+ inputs = indirect_outputs;
}
- inputs.extend_from_slice(&ext_inputs[..]);
-
- // no failure occurred preparing operands, no need to cleanup
- fcx.pop_custom_cleanup_scope(temp_scope);
let clobbers = ia.clobbers.iter()
.map(|s| format!("~{{{}}}", &s));
_ => Vec::new()
};
- let all_constraints= constraints.iter()
- .map(|s| s.to_string())
- .chain(ext_constraints)
- .chain(clobbers)
- .chain(arch_clobbers.iter()
- .map(|s| s.to_string()))
- .collect::<Vec<String>>()
- .join(",");
+ let all_constraints =
+ ia.outputs.iter().map(|out| out.constraint.to_string())
+ .chain(ia.inputs.iter().map(|s| s.to_string()))
+ .chain(ext_constraints)
+ .chain(clobbers)
+ .chain(arch_clobbers.iter().map(|s| s.to_string()))
+ .collect::<Vec<String>>().join(",");
debug!("Asm Constraints: {}", &all_constraints[..]);
// Depending on how many outputs we have, the return type is different
- let num_outputs = outputs.len();
+ let num_outputs = output_types.len();
let output_type = match num_outputs {
0 => Type::void(bcx.ccx()),
1 => output_types[0],
dialect);
// Again, based on how many outputs we have
- if num_outputs == 1 {
- Store(bcx, r, outputs[0]);
- } else {
- for (i, o) in outputs.iter().enumerate() {
- let v = ExtractValue(bcx, r, i);
- Store(bcx, v, *o);
- }
+ let outputs = ia.outputs.iter().zip(&outputs).filter(|&(ref o, _)| !o.is_indirect);
+ for (i, (_, datum)) in outputs.enumerate() {
+ let v = if num_outputs == 1 { r } else { ExtractValue(bcx, r, i) };
+ Store(bcx, v, datum.val);
}
// Store expn_id in a metadata node so we can map LLVM errors
llvm::LLVMSetMetadata(r, kind,
llvm::LLVMMDNodeInContext(bcx.ccx().llcx(), &val, 1));
}
-
- return bcx;
-
}
}
}
- hir::ExprInlineAsm(hir::InlineAsm { ref inputs,
- ref outputs,
- .. }) => {
- // inputs, outputs: Vec<(String, P<Expr>)>
- for &(_, ref exp) in inputs {
- walk_expr(cx, &exp, scope_stack, scope_map);
+ hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
+ for output in outputs {
+ walk_expr(cx, output, scope_stack, scope_map);
}
- for out in outputs {
- walk_expr(cx, &out.expr, scope_stack, scope_map);
+ for input in inputs {
+ walk_expr(cx, input, scope_stack, scope_map);
}
}
}
trans_assign_op(bcx, expr, op, &dst, &src)
}
}
- hir::ExprInlineAsm(ref a) => {
- asm::trans_inline_asm(bcx, a)
+ hir::ExprInlineAsm(ref a, ref outputs, ref inputs) => {
+ let outputs = outputs.iter().map(|output| {
+ let out_datum = unpack_datum!(bcx, trans(bcx, output));
+ unpack_datum!(bcx, out_datum.to_lvalue_datum(bcx, "out", expr.id))
+ }).collect();
+ let inputs = inputs.iter().map(|input| {
+ let input = unpack_datum!(bcx, trans(bcx, input));
+ let input = unpack_datum!(bcx, input.to_rvalue_datum(bcx, "in"));
+ input.to_llscalarish(bcx)
+ }).collect();
+ asm::trans_inline_asm(bcx, a, outputs, inputs);
+ bcx
}
_ => {
bcx.tcx().sess.span_bug(
use trans::base;
use trans::callee::Callee;
use trans::common::{self, C_uint, BlockAndBuilder, Result};
+use trans::datum::{Datum, Lvalue};
use trans::debuginfo::DebugLoc;
use trans::declare;
use trans::adt;
bcx
}
- mir::Rvalue::InlineAsm(ref inline_asm) => {
- bcx.map_block(|bcx| {
- asm::trans_inline_asm(bcx, inline_asm)
- })
+ mir::Rvalue::InlineAsm { ref asm, ref outputs, ref inputs } => {
+ let outputs = outputs.iter().map(|output| {
+ let lvalue = self.trans_lvalue(&bcx, output);
+ Datum::new(lvalue.llval, lvalue.ty.to_ty(bcx.tcx()),
+ Lvalue::new("out"))
+ }).collect();
+
+ let input_vals = inputs.iter().map(|input| {
+ self.trans_operand(&bcx, input).immediate()
+ }).collect();
+
+ bcx.with_block(|bcx| {
+ asm::trans_inline_asm(bcx, asm, outputs, input_vals);
+ });
+
+ for input in inputs {
+ self.set_operand_dropped(&bcx, input);
+ }
+ bcx
}
_ => {
mir::Rvalue::Repeat(..) |
mir::Rvalue::Aggregate(..) |
mir::Rvalue::Slice { .. } |
- mir::Rvalue::InlineAsm(..) => {
+ mir::Rvalue::InlineAsm { .. } => {
bcx.tcx().sess.bug(&format!("cannot generate operand from rvalue {:?}", rvalue));
}
}
mir::Rvalue::Repeat(..) |
mir::Rvalue::Aggregate(..) |
mir::Rvalue::Slice { .. } |
- mir::Rvalue::InlineAsm(..) =>
+ mir::Rvalue::InlineAsm { .. } =>
false,
}
fcx.add_wf_bounds(&item_substs.substs, expr);
});
}
- hir::ExprInlineAsm(ref ia) => {
- for &(_, ref input) in &ia.inputs {
- check_expr(fcx, &input);
+ hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
+ for output in outputs {
+ check_expr(fcx, output);
}
- for out in &ia.outputs {
- check_expr(fcx, &out.expr);
+ for input in inputs {
+ check_expr(fcx, input);
}
fcx.write_nil(id);
}