Skip to content

Commit

Permalink
Make spreading use Option<Local>
Browse files Browse the repository at this point in the history
  • Loading branch information
jonas-schievink committed Sep 26, 2016
1 parent 894c083 commit 3b0c318
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 54 deletions.
8 changes: 4 additions & 4 deletions src/librustc/mir/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,11 @@ pub struct Mir<'tcx> {
/// the first argument is either the closure or a reference to it.
pub upvar_decls: Vec<UpvarDecl>,

/// A boolean indicating whether the last argument (which must be a tuple)
/// is passed as its individual components at the LLVM level.
/// Mark an argument local (which must be a tuple) as getting passed as
/// its individual components at the LLVM level.
///
/// This is used for the "rust-call" ABI.
pub spread_last_arg: bool,
pub spread_arg: Option<Local>,

/// A span representing this MIR, for error reporting
pub span: Span,
Expand Down Expand Up @@ -134,7 +134,7 @@ impl<'tcx> Mir<'tcx> {
local_decls: local_decls,
arg_count: arg_count,
upvar_decls: upvar_decls,
spread_last_arg: false,
spread_arg: None,
span: span,
cache: Cache::new()
}
Expand Down
6 changes: 3 additions & 3 deletions src/librustc_mir/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,11 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
}));
assert_eq!(block, builder.return_block());

let mut spread_last_arg = false;
let mut spread_arg = None;
match tcx.node_id_to_type(fn_id).sty {
ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => {
// RustCall pseudo-ABI untuples the last argument.
spread_last_arg = true;
spread_arg = Some(Local::new(arguments.len()));
}
_ => {}
}
Expand Down Expand Up @@ -221,7 +221,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
});

let (mut mir, aux) = builder.finish(upvar_decls, return_ty);
mir.spread_last_arg = spread_last_arg;
mir.spread_arg = spread_arg;
(mir, aux)
}

Expand Down
97 changes: 50 additions & 47 deletions src/librustc_trans/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,57 +359,60 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
mir.arg_iter().enumerate().map(|(arg_index, local)| {
let arg_decl = &mir.local_decls[local];
let arg_ty = bcx.monomorphize(&arg_decl.ty);
if mir.spread_last_arg && arg_index == mir.arg_count - 1 {
// This argument (e.g. the last argument in the "rust-call" ABI)
// is a tuple that was spread at the ABI level and now we have
// to reconstruct it into a tuple local variable, from multiple
// individual LLVM function arguments.

let tupled_arg_tys = match arg_ty.sty {
ty::TyTuple(ref tys) => tys,
_ => bug!("spread argument isn't a tuple?!")
};

let lltuplety = type_of::type_of(bcx.ccx(), arg_ty);
let lltemp = bcx.with_block(|bcx| {
base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index))
});
for (i, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() {
let dst = bcx.struct_gep(lltemp, i);
let arg = &fcx.fn_ty.args[idx];
idx += 1;
if common::type_is_fat_ptr(tcx, tupled_arg_ty) {
// We pass fat pointers as two words, but inside the tuple
// they are the two sub-fields of a single aggregate field.
let meta = &fcx.fn_ty.args[idx];
if let Some(spread_local) = mir.spread_arg {
if local == spread_local {
// This argument (e.g. the last argument in the "rust-call" ABI)
// is a tuple that was spread at the ABI level and now we have
// to reconstruct it into a tuple local variable, from multiple
// individual LLVM function arguments.

let tupled_arg_tys = match arg_ty.sty {
ty::TyTuple(ref tys) => tys,
_ => bug!("spread argument isn't a tuple?!")
};

let lltuplety = type_of::type_of(bcx.ccx(), arg_ty);
let lltemp = bcx.with_block(|bcx| {
base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index))
});
for (i, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() {
let dst = bcx.struct_gep(lltemp, i);
let arg = &fcx.fn_ty.args[idx];
idx += 1;
arg.store_fn_arg(bcx, &mut llarg_idx, get_dataptr(bcx, dst));
meta.store_fn_arg(bcx, &mut llarg_idx, get_meta(bcx, dst));
} else {
arg.store_fn_arg(bcx, &mut llarg_idx, dst);
}
if common::type_is_fat_ptr(tcx, tupled_arg_ty) {
// We pass fat pointers as two words, but inside the tuple
// they are the two sub-fields of a single aggregate field.
let meta = &fcx.fn_ty.args[idx];
idx += 1;
arg.store_fn_arg(bcx, &mut llarg_idx, get_dataptr(bcx, dst));
meta.store_fn_arg(bcx, &mut llarg_idx, get_meta(bcx, dst));
} else {
arg.store_fn_arg(bcx, &mut llarg_idx, dst);
}

bcx.with_block(|bcx| arg_scope.map(|scope| {
let byte_offset_of_var_in_tuple =
machine::llelement_offset(bcx.ccx(), lltuplety, i);

let ops = unsafe {
[llvm::LLVMRustDIBuilderCreateOpDeref(),
llvm::LLVMRustDIBuilderCreateOpPlus(),
byte_offset_of_var_in_tuple as i64]
};

let variable_access = VariableAccess::IndirectVariable {
alloca: lltemp,
address_operations: &ops
};
declare_local(bcx, keywords::Invalid.name(),
tupled_arg_ty, scope, variable_access,
VariableKind::ArgumentVariable(arg_index + i + 1),
bcx.fcx().span.unwrap_or(DUMMY_SP));
}));
bcx.with_block(|bcx| arg_scope.map(|scope| {
let byte_offset_of_var_in_tuple =
machine::llelement_offset(bcx.ccx(), lltuplety, i);

let ops = unsafe {
[llvm::LLVMRustDIBuilderCreateOpDeref(),
llvm::LLVMRustDIBuilderCreateOpPlus(),
byte_offset_of_var_in_tuple as i64]
};

let variable_access = VariableAccess::IndirectVariable {
alloca: lltemp,
address_operations: &ops
};
declare_local(bcx, keywords::Invalid.name(),
tupled_arg_ty, scope, variable_access,
VariableKind::ArgumentVariable(arg_index + i + 1),
bcx.fcx().span.unwrap_or(DUMMY_SP));
}));
}
return LocalRef::Lvalue(LvalueRef::new_sized(lltemp, LvalueTy::from_ty(arg_ty)));
}
return LocalRef::Lvalue(LvalueRef::new_sized(lltemp, LvalueTy::from_ty(arg_ty)));
}

let arg = &fcx.fn_ty.args[idx];
Expand Down

0 comments on commit 3b0c318

Please sign in to comment.