Skip to content

Commit 1983e3d

Browse files
committed
Make + mode by-value if the type is immediate, by-ref otherwise
Fixes #3523
1 parent 6e9f997 commit 1983e3d

File tree

9 files changed

+199
-92
lines changed

9 files changed

+199
-92
lines changed

src/libcore/to_bytes.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,15 @@ trait IterBytes {
3737
pure fn iter_bytes(lsb0: bool, f: Cb);
3838
}
3939

40+
impl bool: IterBytes {
41+
#[inline(always)]
42+
pure fn iter_bytes(_lsb0: bool, f: Cb) {
43+
f([
44+
self as u8
45+
]);
46+
}
47+
}
48+
4049
impl u8: IterBytes {
4150
#[inline(always)]
4251
pure fn iter_bytes(_lsb0: bool, f: Cb) {

src/rustc/middle/trans/base.rs

Lines changed: 58 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,10 +1437,9 @@ fn new_fn_ctxt(ccx: @crate_ctxt, path: path, llfndecl: ValueRef,
14371437
// field of the fn_ctxt with
14381438
fn create_llargs_for_fn_args(cx: fn_ctxt,
14391439
ty_self: self_arg,
1440-
args: ~[ast::arg]) {
1440+
args: ~[ast::arg]) -> ~[ValueRef] {
14411441
let _icx = cx.insn_ctxt("create_llargs_for_fn_args");
1442-
// Skip the implicit arguments 0, and 1.
1443-
let mut arg_n = first_real_arg;
1442+
14441443
match ty_self {
14451444
impl_self(tt) => {
14461445
cx.llself = Some(ValSelfData {
@@ -1459,28 +1458,22 @@ fn create_llargs_for_fn_args(cx: fn_ctxt,
14591458
no_self => ()
14601459
}
14611460

1462-
// Populate the llargs field of the function context with the ValueRefs
1463-
// that we get from llvm::LLVMGetParam for each argument.
1464-
for vec::each(args) |arg| {
1465-
let llarg = llvm::LLVMGetParam(cx.llfn, arg_n as c_uint);
1466-
assert (llarg as int != 0);
1467-
// Note that this uses local_mem even for things passed by value.
1468-
// copy_args_to_allocas will overwrite the table entry with local_imm
1469-
// before it's actually used.
1470-
cx.llargs.insert(arg.id, local_mem(llarg));
1471-
arg_n += 1u;
1472-
}
1461+
// Return an array containing the ValueRefs that we get from
1462+
// llvm::LLVMGetParam for each argument.
1463+
vec::from_fn(args.len(), |i| {
1464+
let arg_n = first_real_arg + i;
1465+
llvm::LLVMGetParam(cx.llfn, arg_n as c_uint)
1466+
})
14731467
}
14741468

1475-
fn copy_args_to_allocas(fcx: fn_ctxt, bcx: block, args: ~[ast::arg],
1476-
arg_tys: ~[ty::arg]) -> block {
1469+
fn copy_args_to_allocas(fcx: fn_ctxt,
1470+
bcx: block,
1471+
args: &[ast::arg],
1472+
raw_llargs: &[ValueRef],
1473+
arg_tys: &[ty::arg]) -> block {
14771474
let _icx = fcx.insn_ctxt("copy_args_to_allocas");
14781475
let tcx = bcx.tcx();
1479-
let mut arg_n: uint = 0u, bcx = bcx;
1480-
let epic_fail = fn@() -> ! {
1481-
tcx.sess.bug(~"someone forgot\
1482-
to document an invariant in copy_args_to_allocas!");
1483-
};
1476+
let mut bcx = bcx;
14841477

14851478
match fcx.llself {
14861479
Some(copy slf) => {
@@ -1496,31 +1489,50 @@ fn copy_args_to_allocas(fcx: fn_ctxt, bcx: block, args: ~[ast::arg],
14961489
_ => {}
14971490
}
14981491

1499-
for vec::each(arg_tys) |arg| {
1500-
let id = args[arg_n].id;
1501-
let argval = match fcx.llargs.get(id) {
1502-
local_mem(v) => v,
1503-
_ => epic_fail()
1504-
};
1505-
match ty::resolved_mode(tcx, arg.mode) {
1506-
ast::by_mutbl_ref => (),
1507-
ast::by_move | ast::by_copy => add_clean(bcx, argval, arg.ty),
1508-
ast::by_val => {
1509-
if !ty::type_is_immediate(arg.ty) {
1510-
let alloc = alloc_ty(bcx, arg.ty);
1511-
Store(bcx, argval, alloc);
1512-
fcx.llargs.insert(id, local_mem(alloc));
1513-
} else {
1514-
fcx.llargs.insert(id, local_imm(argval));
1492+
for uint::range(0, arg_tys.len()) |arg_n| {
1493+
let arg_ty = &arg_tys[arg_n];
1494+
let raw_llarg = raw_llargs[arg_n];
1495+
let arg_id = args[arg_n].id;
1496+
1497+
// For certain mode/type combinations, the raw llarg values are passed
1498+
// by value. However, within the fn body itself, we want to always
1499+
// have all locals and argumenst be by-ref so that we can cancel the
1500+
// cleanup and for better interaction with LLVM's debug info. So, if
1501+
// the argument would be passed by value, we store it into an alloca.
1502+
// This alloca should be optimized away by LLVM's mem-to-reg pass in
1503+
// the event it's not truly needed.
1504+
let llarg;
1505+
match ty::resolved_mode(tcx, arg_ty.mode) {
1506+
ast::by_ref | ast::by_mutbl_ref => {
1507+
llarg = raw_llarg;
1508+
}
1509+
ast::by_move | ast::by_copy => {
1510+
// only by value if immediate:
1511+
if datum::appropriate_mode(arg_ty.ty).is_by_value() {
1512+
let alloc = alloc_ty(bcx, arg_ty.ty);
1513+
Store(bcx, raw_llarg, alloc);
1514+
llarg = alloc;
1515+
} else {
1516+
llarg = raw_llarg;
1517+
}
1518+
1519+
add_clean(bcx, llarg, arg_ty.ty);
1520+
}
1521+
ast::by_val => {
1522+
// always by value, also not owned, so don't add a cleanup:
1523+
let alloc = alloc_ty(bcx, arg_ty.ty);
1524+
Store(bcx, raw_llarg, alloc);
1525+
llarg = alloc;
15151526
}
1516-
}
1517-
ast::by_ref => ()
15181527
}
1528+
1529+
fcx.llargs.insert(arg_id, local_mem(llarg));
1530+
15191531
if fcx.ccx.sess.opts.extra_debuginfo {
15201532
debuginfo::create_arg(bcx, args[arg_n], args[arg_n].ty.span);
15211533
}
1522-
arg_n += 1u;
15231534
}
1535+
15241536
return bcx;
15251537
}
15261538

@@ -1558,7 +1570,7 @@ fn trans_closure(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
15581570
// Set up arguments to the function.
15591571
let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, id, param_substs,
15601572
Some(body.span));
1561-
create_llargs_for_fn_args(fcx, ty_self, decl.inputs);
1573+
let raw_llargs = create_llargs_for_fn_args(fcx, ty_self, decl.inputs);
15621574

15631575
// Set GC for function.
15641576
if ccx.sess.opts.gc {
@@ -1576,7 +1588,7 @@ fn trans_closure(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
15761588
let block_ty = node_id_type(bcx, body.node.id);
15771589

15781590
let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
1579-
bcx = copy_args_to_allocas(fcx, bcx, decl.inputs, arg_tys);
1591+
bcx = copy_args_to_allocas(fcx, bcx, decl.inputs, raw_llargs, arg_tys);
15801592

15811593
maybe_load_env(fcx);
15821594

@@ -1648,14 +1660,14 @@ fn trans_enum_variant(ccx: @crate_ctxt,
16481660
id: varg.id});
16491661
let fcx = new_fn_ctxt_w_id(ccx, ~[], llfndecl, variant.node.id,
16501662
param_substs, None);
1651-
create_llargs_for_fn_args(fcx, no_self, fn_args);
1663+
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
16521664
let ty_param_substs = match param_substs {
16531665
Some(substs) => substs.tys,
16541666
None => ~[]
16551667
};
16561668
let bcx = top_scope_block(fcx, None), lltop = bcx.llbb;
16571669
let arg_tys = ty::ty_fn_args(node_id_type(bcx, variant.node.id));
1658-
let bcx = copy_args_to_allocas(fcx, bcx, fn_args, arg_tys);
1670+
let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
16591671

16601672
// Cast the enum to a type we can GEP into.
16611673
let llblobptr = if is_degen {
@@ -1705,11 +1717,11 @@ fn trans_class_ctor(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
17051717
// Make the fn context
17061718
let fcx = new_fn_ctxt_w_id(ccx, path, llctor_decl, ctor_id,
17071719
Some(psubsts), Some(sp));
1708-
create_llargs_for_fn_args(fcx, no_self, decl.inputs);
1720+
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, decl.inputs);
17091721
let mut bcx_top = top_scope_block(fcx, body.info());
17101722
let lltop = bcx_top.llbb;
17111723
let arg_tys = ty::ty_fn_args(node_id_type(bcx_top, ctor_id));
1712-
bcx_top = copy_args_to_allocas(fcx, bcx_top, decl.inputs, arg_tys);
1724+
bcx_top = copy_args_to_allocas(fcx, bcx_top, decl.inputs, raw_llargs, arg_tys);
17131725

17141726
// Create a temporary for `self` that we will return at the end
17151727
let selfdatum = datum::scratch_datum(bcx_top, rslt_ty, true);

src/rustc/middle/trans/callee.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,7 @@ fn trans_arg_expr(bcx: block,
548548
let llformal_ty = type_of::type_of(ccx, formal_ty.ty);
549549
val = llvm::LLVMGetUndef(llformal_ty);
550550
} else {
551+
// FIXME(#3548) use the adjustments table
551552
match autoref_arg {
552553
DoAutorefArg => { val = arg_datum.to_ref_llval(bcx); }
553554
DontAutorefArg => {
@@ -583,8 +584,16 @@ fn trans_arg_expr(bcx: block,
583584
// callee is actually invoked.
584585
scratch.add_clean(bcx);
585586
vec::push(*temp_cleanups, scratch.val);
586-
val = scratch.val;
587-
}
587+
588+
match arg_datum.appropriate_mode() {
589+
ByValue => {
590+
val = Load(bcx, scratch.val);
591+
}
592+
ByRef => {
593+
val = scratch.val;
594+
}
595+
}
596+
}
588597
}
589598
}
590599
}

src/rustc/middle/trans/common.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,7 +1125,10 @@ fn get_param(fndecl: ValueRef, param: uint) -> ValueRef {
11251125
enum mono_param_id {
11261126
mono_precise(ty::t, Option<~[mono_id]>),
11271127
mono_any,
1128-
mono_repr(uint /* size */, uint /* align */),
1128+
mono_repr(uint /* size */,
1129+
uint /* align */,
1130+
bool /* is_float */,
1131+
datum::DatumMode),
11291132
}
11301133
11311134
type mono_id_ = {def: ast::def_id, params: ~[mono_param_id]};
@@ -1140,8 +1143,10 @@ impl mono_param_id: cmp::Eq {
11401143
ty_a == ty_b && ids_a == ids_b
11411144
}
11421145
(mono_any, mono_any) => true,
1143-
(mono_repr(size_a, align_a), mono_repr(size_b, align_b)) => {
1144-
size_a == size_b && align_a == align_b
1146+
(mono_repr(size_a, align_a, is_float_a, mode_a),
1147+
mono_repr(size_b, align_b, is_float_b, mode_b)) => {
1148+
size_a == size_b && align_a == align_b &&
1149+
is_float_a == is_float_b && mode_a == mode_b
11451150
}
11461151
(mono_precise(*), _) => false,
11471152
(mono_any, _) => false,
@@ -1159,8 +1164,10 @@ impl mono_param_id : cmp::Eq {
11591164
ty_a == ty_b && ids_a == ids_b
11601165
}
11611166
(mono_any, mono_any) => true,
1162-
(mono_repr(size_a, align_a), mono_repr(size_b, align_b)) => {
1163-
size_a == size_b && align_a == align_b
1167+
(mono_repr(size_a, align_a, is_float_a, mode_a),
1168+
mono_repr(size_b, align_b, is_float_b, mode_b)) => {
1169+
size_a == size_b && align_a == align_b &&
1170+
is_float_a == is_float_b && mode_a == mode_b
11641171
}
11651172
(mono_precise(*), _) => false,
11661173
(mono_any, _) => false,
@@ -1194,8 +1201,8 @@ impl mono_param_id : to_bytes::IterBytes {
11941201
11951202
mono_any => 1u8.iter_bytes(lsb0, f),
11961203
1197-
mono_repr(a,b) =>
1198-
to_bytes::iter_bytes_3(&2u8, &a, &b, lsb0, f)
1204+
mono_repr(ref a, ref b, ref c, ref d) =>
1205+
to_bytes::iter_bytes_5(&2u8, a, b, c, d, lsb0, f)
11991206
}
12001207
}
12011208
}

src/rustc/middle/trans/datum.rs

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,29 @@ impl DatumMode {
138138
}
139139
}
140140

141+
#[cfg(stage0)]
142+
impl DatumMode: cmp::Eq {
143+
pure fn eq(&&other: DatumMode) -> bool {
144+
(self as uint) == (other as uint)
145+
}
146+
pure fn ne(&&other: DatumMode) -> bool { !self.eq(other) }
147+
}
148+
149+
#[cfg(stage1)]
150+
#[cfg(stage2)]
151+
impl DatumMode: cmp::Eq {
152+
pure fn eq(other: &DatumMode) -> bool {
153+
self as uint == (*other as uint)
154+
}
155+
pure fn ne(other: &DatumMode) -> bool { !self.eq(other) }
156+
}
157+
158+
impl DatumMode: to_bytes::IterBytes {
159+
pure fn iter_bytes(lsb0: bool, f: to_bytes::Cb) {
160+
(self as uint).iter_bytes(lsb0, f)
161+
}
162+
}
163+
141164
/// See `Datum Sources` section at the head of this module.
142165
enum DatumSource {
143166
FromRvalue,
@@ -186,6 +209,22 @@ fn scratch_datum(bcx: block, ty: ty::t, zero: bool) -> Datum {
186209
Datum { val: scratch, ty: ty, mode: ByRef, source: FromRvalue }
187210
}
188211

212+
fn appropriate_mode(ty: ty::t) -> DatumMode {
213+
/*!
214+
*
215+
* Indicates the "appropriate" mode for this value,
216+
* which is either by ref or by value, depending
217+
* on whether type is iimmediate or what. */
218+
219+
if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
220+
ByValue
221+
} else if ty::type_is_immediate(ty) {
222+
ByValue
223+
} else {
224+
ByRef
225+
}
226+
}
227+
189228
impl Datum {
190229
fn store_will_move() -> bool {
191230
match self.source {
@@ -446,19 +485,9 @@ impl Datum {
446485
}
447486

448487
fn appropriate_mode() -> DatumMode {
449-
/*!
450-
*
451-
* Indicates the "appropriate" mode for this value,
452-
* which is either by ref or by value, depending
453-
* on whether type is iimmediate or what. */
488+
/*! See the `appropriate_mode()` function */
454489

455-
if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) {
456-
ByValue
457-
} else if ty::type_is_immediate(self.ty) {
458-
ByValue
459-
} else {
460-
ByRef
461-
}
490+
appropriate_mode(self.ty)
462491
}
463492

464493
fn to_appropriate_llval(bcx: block) -> ValueRef {

src/rustc/middle/trans/foreign.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -877,16 +877,28 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
877877
fcx.llretptr);
878878
}
879879
~"move_val" => {
880+
// Create a datum reflecting the value being moved:
881+
//
882+
// - the datum will be by ref if the value is non-immediate;
883+
//
884+
// - the datum has a FromRvalue source because, that way,
885+
// the `move_to()` method does not feel compelled to
886+
// zero out the memory where the datum resides. Zeroing
887+
// is not necessary since, for intrinsics, there is no
888+
// cleanup to concern ourselves with.
880889
let tp_ty = substs.tys[0];
890+
let mode = appropriate_mode(tp_ty);
881891
let src = Datum {val: get_param(decl, first_real_arg + 1u),
882-
ty: tp_ty, mode: ByRef, source: FromLvalue};
892+
ty: tp_ty, mode: mode, source: FromRvalue};
883893
bcx = src.move_to(bcx, DROP_EXISTING,
884894
get_param(decl, first_real_arg));
885895
}
886896
~"move_val_init" => {
897+
// See comments for `"move_val"`.
887898
let tp_ty = substs.tys[0];
899+
let mode = appropriate_mode(tp_ty);
888900
let src = Datum {val: get_param(decl, first_real_arg + 1u),
889-
ty: tp_ty, mode: ByRef, source: FromLvalue};
901+
ty: tp_ty, mode: mode, source: FromRvalue};
890902
bcx = src.move_to(bcx, INIT, get_param(decl, first_real_arg));
891903
}
892904
~"min_align_of" => {

0 commit comments

Comments
 (0)