Skip to content

Commit 6bfecd4

Browse files
committed
Avoid unnecessary allocas for indirect function arguments
The extra alloca was only necessary because it made LLVM implicitly handle the necessary deref to get to the actual value. The same happens for indirect arguments that have the byval attribute. But the Rust ABI does not use the byval attribute and so we need to manually add the deref operation to the debuginfo.
1 parent f6d7514 commit 6bfecd4

File tree

2 files changed

+26
-7
lines changed

2 files changed

+26
-7
lines changed

src/librustc_trans/abi.rs

+4
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ impl ArgAttributes {
113113
self
114114
}
115115

116+
pub fn contains(&self, attr: ArgAttribute) -> bool {
117+
self.regular.contains(attr)
118+
}
119+
116120
pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) {
117121
unsafe {
118122
self.regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn));

src/librustc_trans/mir/mod.rs

+22-7
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use builder::Builder;
2323
use common::{self, CrateContext, Funclet};
2424
use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext};
2525
use monomorphize::Instance;
26-
use abi::FnType;
26+
use abi::{ArgAttribute, FnType};
2727
use type_of;
2828

2929
use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span};
@@ -378,6 +378,10 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
378378
None
379379
};
380380

381+
let deref_op = unsafe {
382+
[llvm::LLVMRustDIBuilderCreateOpDeref()]
383+
};
384+
381385
mir.args_iter().enumerate().map(|(arg_index, local)| {
382386
let arg_decl = &mir.local_decls[local];
383387
let arg_ty = mircx.monomorphize(&arg_decl.ty);
@@ -432,10 +436,9 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
432436

433437
let arg = &mircx.fn_ty.args[idx];
434438
idx += 1;
435-
let llval = if arg.is_indirect() && bcx.sess().opts.debuginfo != FullDebugInfo {
439+
let llval = if arg.is_indirect() {
436440
// Don't copy an indirect argument to an alloca, the caller
437-
// already put it in a temporary alloca and gave it up, unless
438-
// we emit extra-debug-info, which requires local allocas :(.
441+
// already put it in a temporary alloca and gave it up
439442
// FIXME: lifetimes
440443
if arg.pad.is_some() {
441444
llarg_idx += 1;
@@ -444,8 +447,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
444447
llarg_idx += 1;
445448
llarg
446449
} else if !lvalue_locals.contains(local.index()) &&
447-
!arg.is_indirect() && arg.cast.is_none() &&
448-
arg_scope.is_none() {
450+
arg.cast.is_none() && arg_scope.is_none() {
449451
if arg.is_ignore() {
450452
return LocalRef::new_operand(bcx.ccx, arg_ty);
451453
}
@@ -510,13 +512,26 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
510512
arg_scope.map(|scope| {
511513
// Is this a regular argument?
512514
if arg_index > 0 || mir.upvar_decls.is_empty() {
515+
// The Rust ABI passes indirect variables using a pointer and a manual copy, so we
516+
// need to insert a deref here, but the C ABI uses a pointer and a copy using the
517+
// byval attribute, for which LLVM does the deref itself, so we must not add it.
518+
let variable_access = if arg.is_indirect() &&
519+
!arg.attrs.contains(ArgAttribute::ByVal) {
520+
VariableAccess::IndirectVariable {
521+
alloca: llval,
522+
address_operations: &deref_op,
523+
}
524+
} else {
525+
VariableAccess::DirectVariable { alloca: llval }
526+
};
527+
513528
declare_local(
514529
bcx,
515530
&mircx.debug_context,
516531
arg_decl.name.unwrap_or(keywords::Invalid.name()),
517532
arg_ty,
518533
scope,
519-
VariableAccess::DirectVariable { alloca: llval },
534+
variable_access,
520535
VariableKind::ArgumentVariable(arg_index + 1),
521536
DUMMY_SP
522537
);

0 commit comments

Comments
 (0)