Skip to content

Commit e8f5955

Browse files
committed
Add !nonnull metadata to loads from fat pointers
The data pointer inside a safe fat pointer is never null. The same is true for the vtable pointer inside a fat pointer for a trait object. Wrapping loads/stores of the components of a fat pointer in functions allows to easily make sure that we emit the appropriate metadata and allow LLVM to perform better optimizations.
1 parent 9090420 commit e8f5955

File tree

11 files changed

+94
-68
lines changed

11 files changed

+94
-68
lines changed

src/librustc/middle/ty.rs

+9
Original file line numberDiff line numberDiff line change
@@ -3850,6 +3850,15 @@ impl<'tcx> TyS<'tcx> {
38503850
}
38513851
}
38523852

3853+
pub fn pointee_type(&self, cx: &ctxt<'tcx>) -> Ty<'tcx> {
3854+
match self.sty {
3855+
ty::TyBox(inner) |
3856+
ty::TyRef(_, ty::TypeAndMut { ty: inner, .. }) |
3857+
ty::TyRawPtr(ty::TypeAndMut { ty: inner, .. }) => inner,
3858+
_ => cx.sess.bug(&format!("pointee_type called on non-pointer value: {}", self))
3859+
}
3860+
}
3861+
38533862
pub fn sequence_element_type(&self, cx: &ctxt<'tcx>) -> Ty<'tcx> {
38543863
match self.sty {
38553864
TyArray(ty, _) | TySlice(ty) => ty,

src/librustc_trans/trans/_match.rs

+17-18
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,6 @@ pub use self::TransBindingMode::*;
188188
use self::Opt::*;
189189
use self::FailureHandler::*;
190190

191-
use back::abi;
192191
use llvm::{ValueRef, BasicBlockRef};
193192
use middle::check_match::StaticInliner;
194193
use middle::check_match;
@@ -678,9 +677,8 @@ fn bind_subslice_pat(bcx: Block,
678677
let slice_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReStatic),
679678
bcx.tcx().mk_slice(unit_ty));
680679
let scratch = rvalue_scratch_datum(bcx, slice_ty, "");
681-
Store(bcx, slice_begin,
682-
GEPi(bcx, scratch.val, &[0, abi::FAT_PTR_ADDR]));
683-
Store(bcx, slice_len, GEPi(bcx, scratch.val, &[0, abi::FAT_PTR_EXTRA]));
680+
store_addr(bcx, slice_begin, scratch.val);
681+
store_extra(bcx, slice_len, scratch.val);
684682
scratch.val
685683
}
686684

@@ -833,10 +831,11 @@ fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
833831
None,
834832
&format!("comparison of `{}`", rhs_t),
835833
StrEqFnLangItem);
836-
let lhs_data = Load(cx, expr::get_dataptr(cx, lhs));
837-
let lhs_len = Load(cx, expr::get_len(cx, lhs));
838-
let rhs_data = Load(cx, expr::get_dataptr(cx, rhs));
839-
let rhs_len = Load(cx, expr::get_len(cx, rhs));
834+
let str_ty = cx.tcx().mk_str();
835+
let lhs_data = load_addr(cx, lhs);
836+
let lhs_len = load_extra(cx, lhs, str_ty);
837+
let rhs_data = load_addr(cx, rhs);
838+
let rhs_len = load_extra(cx, rhs, str_ty);
840839
callee::trans_lang_call(cx, did, &[lhs_data, lhs_len, rhs_data, rhs_len], None, debug_loc)
841840
}
842841

@@ -857,15 +856,15 @@ fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
857856
let ty_str_slice = cx.tcx().mk_static_str();
858857

859858
let rhs_str = alloc_ty(cx, ty_str_slice, "rhs_str");
860-
Store(cx, GEPi(cx, rhs, &[0, 0]), expr::get_dataptr(cx, rhs_str));
861-
Store(cx, C_uint(cx.ccx(), pat_len), expr::get_len(cx, rhs_str));
859+
store_addr(cx, GEPi(cx, rhs, &[0, 0]), rhs_str);
860+
store_extra(cx, C_uint(cx.ccx(), pat_len), rhs_str);
862861

863862
let lhs_str;
864863
if val_ty(lhs) == val_ty(rhs) {
865864
// Both the discriminant and the pattern are thin pointers
866865
lhs_str = alloc_ty(cx, ty_str_slice, "lhs_str");
867-
Store(cx, GEPi(cx, lhs, &[0, 0]), expr::get_dataptr(cx, lhs_str));
868-
Store(cx, C_uint(cx.ccx(), pat_len), expr::get_len(cx, lhs_str));
866+
store_addr(cx, GEPi(cx, lhs, &[0, 0]), lhs_str);
867+
store_extra(cx, C_uint(cx.ccx(), pat_len), lhs_str);
869868
}
870869
else {
871870
// The discriminant is a fat pointer
@@ -1016,7 +1015,7 @@ fn compile_submatch<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
10161015
let binfo = *data.bindings_map.get(ident).unwrap();
10171016
call_lifetime_start(bcx, binfo.llmatch);
10181017
if binfo.trmode == TrByRef && type_is_fat_ptr(bcx.tcx(), binfo.ty) {
1019-
expr::copy_fat_ptr(bcx, *value_ptr, binfo.llmatch);
1018+
expr::copy_fat_ptr(bcx, *value_ptr, binfo.llmatch, binfo.ty);
10201019
}
10211020
else {
10221021
Store(bcx, *value_ptr, binfo.llmatch);
@@ -1080,7 +1079,7 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
10801079
// the last field specially: instead of simply passing a
10811080
// ValueRef pointing to that field, as with all the others,
10821081
// we skip it and instead construct a 'fat ptr' below.
1083-
(arg_count - 1, Load(bcx, expr::get_dataptr(bcx, val)))
1082+
(arg_count - 1, load_addr(bcx, val))
10841083
};
10851084
let mut field_vals: Vec<ValueRef> = (0..arg_count).map(|ix|
10861085
adt::trans_field_ptr(bcx, &*repr, struct_val, 0, ix)
@@ -1099,9 +1098,9 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
10991098
let llty = type_of::type_of(bcx.ccx(), unsized_ty);
11001099
let scratch = alloca_no_lifetime(bcx, llty, "__struct_field_fat_ptr");
11011100
let data = adt::trans_field_ptr(bcx, &*repr, struct_val, 0, arg_count);
1102-
let len = Load(bcx, expr::get_len(bcx, val));
1103-
Store(bcx, data, expr::get_dataptr(bcx, scratch));
1104-
Store(bcx, len, expr::get_len(bcx, scratch));
1101+
let len = load_extra(bcx, val, left_ty);
1102+
store_addr(bcx, data, scratch);
1103+
store_extra(bcx, len, scratch);
11051104
field_vals.push(scratch);
11061105
}
11071106
_ => {}
@@ -1681,7 +1680,7 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
16811680
// By ref binding: the value of the variable
16821681
// is the pointer `val` itself or fat pointer referenced by `val`
16831682
if type_is_fat_ptr(bcx.tcx(), ty) {
1684-
expr::copy_fat_ptr(bcx, val, llval);
1683+
expr::copy_fat_ptr(bcx, val, llval, ty);
16851684
}
16861685
else {
16871686
Store(bcx, val, llval);

src/librustc_trans/trans/base.rs

+32-13
Original file line numberDiff line numberDiff line change
@@ -408,9 +408,7 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
408408
let (data_ptr, info) = if common::type_is_sized(cx.tcx(), t) {
409409
(av, None)
410410
} else {
411-
let data = GEPi(cx, av, &[0, abi::FAT_PTR_ADDR]);
412-
let info = GEPi(cx, av, &[0, abi::FAT_PTR_EXTRA]);
413-
(Load(cx, data), Some(Load(cx, info)))
411+
(load_addr(cx, av), Some(load_extra(cx, av, t)))
414412
};
415413

416414
let mut cx = cx;
@@ -426,8 +424,8 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
426424
llfld_a
427425
} else {
428426
let scratch = datum::rvalue_scratch_datum(cx, field_ty, "__fat_ptr_iter");
429-
Store(cx, llfld_a, GEPi(cx, scratch.val, &[0, abi::FAT_PTR_ADDR]));
430-
Store(cx, info.unwrap(), GEPi(cx, scratch.val, &[0, abi::FAT_PTR_EXTRA]));
427+
store_addr(cx, llfld_a, scratch.val);
428+
store_extra(cx, info.unwrap(), scratch.val);
431429
scratch.val
432430
};
433431
cx = f(cx, val, field_ty);
@@ -777,6 +775,27 @@ pub fn load_if_immediate<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
777775
return v;
778776
}
779777

778+
pub fn load_addr(bcx: Block, fatptr: ValueRef) -> ValueRef {
779+
LoadNonNull(bcx, expr::get_dataptr(bcx, fatptr))
780+
}
781+
782+
pub fn store_addr(bcx: Block, addr: ValueRef, fatptr: ValueRef) -> ValueRef {
783+
Store(bcx, addr, expr::get_dataptr(bcx, fatptr))
784+
}
785+
786+
pub fn load_extra<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, fatptr: ValueRef, ty: Ty<'tcx>) -> ValueRef {
787+
assert!(!common::type_is_sized(bcx.tcx(), ty));
788+
if ty.is_trait() {
789+
LoadNonNull(bcx, expr::get_len(bcx, fatptr))
790+
} else {
791+
Load(bcx, expr::get_len(bcx, fatptr))
792+
}
793+
}
794+
795+
pub fn store_extra(bcx: Block, extra: ValueRef, fatptr: ValueRef) -> ValueRef {
796+
Store(bcx, extra, expr::get_len(bcx, fatptr))
797+
}
798+
780799
/// Helper for loading values from memory. Does the necessary conversion if the in-memory type
781800
/// differs from the type used for SSA values. Also handles various special cases where the type
782801
/// gives us better information about what we are loading.
@@ -835,8 +854,8 @@ pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t
835854
}
836855

837856
if common::type_is_fat_ptr(cx.tcx(), t) {
838-
Store(cx, ExtractValue(cx, v, abi::FAT_PTR_ADDR), expr::get_dataptr(cx, dst));
839-
Store(cx, ExtractValue(cx, v, abi::FAT_PTR_EXTRA), expr::get_len(cx, dst));
857+
store_addr(cx, ExtractValue(cx, v, abi::FAT_PTR_ADDR), dst);
858+
store_extra(cx, ExtractValue(cx, v, abi::FAT_PTR_EXTRA), dst);
840859
} else {
841860
let store = Store(cx, from_arg_ty(cx, v, t), to_arg_ty_ptr(cx, dst, t));
842861
unsafe {
@@ -1348,8 +1367,8 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>,
13481367
unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, arg_ty, "",
13491368
arg_scope_id, (data, extra),
13501369
|(data, extra), bcx, dst| {
1351-
Store(bcx, data, expr::get_dataptr(bcx, dst));
1352-
Store(bcx, extra, expr::get_len(bcx, dst));
1370+
store_addr(bcx, data, dst);
1371+
store_extra(bcx, extra, dst);
13531372
bcx
13541373
}))
13551374
} else {
@@ -1379,8 +1398,8 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>,
13791398
if common::type_is_fat_ptr(bcx.tcx(), tupled_arg_ty) {
13801399
let data = get_param(bcx.fcx.llfn, idx);
13811400
let extra = get_param(bcx.fcx.llfn, idx + 1);
1382-
Store(bcx, data, expr::get_dataptr(bcx, lldest));
1383-
Store(bcx, extra, expr::get_len(bcx, lldest));
1401+
store_addr(bcx, data, lldest);
1402+
store_extra(bcx, extra, lldest);
13841403
idx += 2;
13851404
} else {
13861405
let datum = datum::Datum::new(
@@ -1784,8 +1803,8 @@ fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx
17841803
disr,
17851804
i);
17861805
if common::type_is_fat_ptr(bcx.tcx(), arg_ty) {
1787-
Store(bcx, get_param(fcx.llfn, llarg_idx), expr::get_dataptr(bcx, lldestptr));
1788-
Store(bcx, get_param(fcx.llfn, llarg_idx + 1), expr::get_len(bcx, lldestptr));
1806+
store_addr(bcx, get_param(fcx.llfn, llarg_idx), lldestptr);
1807+
store_extra(bcx, get_param(fcx.llfn, llarg_idx + 1), lldestptr);
17891808
llarg_idx += 2;
17901809
} else {
17911810
let arg = get_param(fcx.llfn, llarg_idx);

src/librustc_trans/trans/callee.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1123,8 +1123,9 @@ pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
11231123
debug!("--- trans_arg_datum passing {}", bcx.val_to_string(val));
11241124

11251125
if common::type_is_fat_ptr(bcx.tcx(), formal_arg_ty) {
1126-
llargs.push(Load(bcx, expr::get_dataptr(bcx, val)));
1127-
llargs.push(Load(bcx, expr::get_len(bcx, val)));
1126+
let ty = formal_arg_ty.pointee_type(bcx.tcx());
1127+
llargs.push(load_addr(bcx, val));
1128+
llargs.push(load_extra(bcx, val, ty));
11281129
} else {
11291130
llargs.push(val);
11301131
}

src/librustc_trans/trans/datum.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ pub use self::RvalueMode::*;
9494

9595
use llvm::ValueRef;
9696
use trans::base::*;
97-
use trans::build::Load;
9897
use trans::common::*;
9998
use trans::cleanup;
10099
use trans::cleanup::CleanupMethods;
@@ -524,7 +523,7 @@ impl<'tcx> Datum<'tcx, Lvalue> {
524523
let val = if type_is_sized(bcx.tcx(), self.ty) {
525524
gep(self.val)
526525
} else {
527-
gep(Load(bcx, expr::get_dataptr(bcx, self.val)))
526+
gep(load_addr(bcx, self.val))
528527
};
529528
Datum {
530529
val: val,

src/librustc_trans/trans/expr.rs

+15-11
Original file line numberDiff line numberDiff line change
@@ -290,9 +290,13 @@ pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
290290
GEPi(bcx, fat_ptr, &[0, abi::FAT_PTR_ADDR])
291291
}
292292

293-
pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) {
294-
Store(bcx, Load(bcx, get_dataptr(bcx, src_ptr)), get_dataptr(bcx, dst_ptr));
295-
Store(bcx, Load(bcx, get_len(bcx, src_ptr)), get_len(bcx, dst_ptr));
293+
pub fn copy_fat_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
294+
src_ptr: ValueRef,
295+
dst_ptr: ValueRef,
296+
ty: Ty<'tcx>) {
297+
let pointee_ty = ty.pointee_type(bcx.tcx());
298+
store_addr(bcx, load_addr(bcx, src_ptr), dst_ptr);
299+
store_extra(bcx, load_extra(bcx, src_ptr, pointee_ty), dst_ptr);
296300
}
297301

298302
/// Retrieve the information we are losing (making dynamic) in an unsizing
@@ -453,8 +457,8 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
453457
// to use a different vtable. In that case, we want to
454458
// load out the original data pointer so we can repackage
455459
// it.
456-
(Load(bcx, get_dataptr(bcx, source.val)),
457-
Some(Load(bcx, get_len(bcx, source.val))))
460+
(load_addr(bcx, source.val),
461+
Some(load_extra(bcx, source.val, inner_source)))
458462
} else {
459463
let val = if source.kind.is_by_ref() {
460464
load_ty(bcx, source.val, source.ty)
@@ -472,8 +476,8 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
472476
let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), inner_target).ptr_to();
473477
let base = PointerCast(bcx, base, ptr_ty);
474478

475-
Store(bcx, base, get_dataptr(bcx, target.val));
476-
Store(bcx, info, get_len(bcx, target.val));
479+
store_addr(bcx, base, target.val);
480+
store_extra(bcx, info, target.val);
477481
}
478482

479483
// This can be extended to enums and tuples in the future.
@@ -727,9 +731,9 @@ fn trans_field<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
727731
DatumBlock { datum: d.to_expr_datum(), bcx: bcx }
728732
} else {
729733
let scratch = rvalue_scratch_datum(bcx, d.ty, "");
730-
Store(bcx, d.val, get_dataptr(bcx, scratch.val));
731-
let info = Load(bcx, get_len(bcx, base_datum.val));
732-
Store(bcx, info, get_len(bcx, scratch.val));
734+
store_addr(bcx, d.val, scratch.val);
735+
let info = load_extra(bcx, base_datum.val, d.ty);
736+
store_extra(bcx, info, scratch.val);
733737

734738
// Always generate an lvalue datum, because this pointer doesn't own
735739
// the data and cleanup is scheduled elsewhere.
@@ -2083,7 +2087,7 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
20832087
// Return the address
20842088
return immediate_rvalue_bcx(bcx,
20852089
PointerCast(bcx,
2086-
Load(bcx, get_dataptr(bcx, datum.val)),
2090+
load_addr(bcx, datum.val),
20872091
ll_t_out),
20882092
t_out).to_expr_datumblock();
20892093
}

src/librustc_trans/trans/foreign.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use trans::cabi;
2222
use trans::common::*;
2323
use trans::debuginfo::DebugLoc;
2424
use trans::declare;
25-
use trans::expr;
2625
use trans::machine;
2726
use trans::monomorphize;
2827
use trans::type_::Type;
@@ -298,8 +297,8 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
298297
type_of::type_of(ccx, passed_arg_tys[i]),
299298
"__arg");
300299
if type_is_fat_ptr(ccx.tcx(), passed_arg_tys[i]) {
301-
Store(bcx, llargs_rust[i + offset], expr::get_dataptr(bcx, scratch));
302-
Store(bcx, llargs_rust[i + offset + 1], expr::get_len(bcx, scratch));
300+
base::store_addr(bcx, llargs_rust[i + offset], scratch);
301+
base::store_extra(bcx, llargs_rust[i + offset + 1], scratch);
303302
offset += 1;
304303
} else {
305304
base::store_ty(bcx, llarg_rust, scratch, passed_arg_tys[i]);

src/librustc_trans/trans/glue.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
// Code relating to drop glue.
1414

1515

16-
use back::abi;
1716
use back::link::*;
1817
use llvm;
1918
use llvm::{ValueRef, get_param};
@@ -374,7 +373,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
374373
let (_, bcx) = if type_is_sized(bcx.tcx(), t) {
375374
invoke(bcx, dtor_addr, &[v0], dtor_ty, DebugLoc::None)
376375
} else {
377-
let args = [Load(bcx, expr::get_dataptr(bcx, v0)), Load(bcx, expr::get_len(bcx, v0))];
376+
let args = [load_addr(bcx, v0), load_extra(bcx, v0, t)];
378377
invoke(bcx, dtor_addr, &args, dtor_ty, DebugLoc::None)
379378
};
380379

@@ -465,15 +464,13 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
465464
// a safe-guard, assert TyBox not used with TyContents.
466465
assert!(!skip_dtor);
467466
if !type_is_sized(bcx.tcx(), content_ty) {
468-
let llval = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
469-
let llbox = Load(bcx, llval);
467+
let llbox = load_addr(bcx, v0);
470468
let llbox_as_usize = PtrToInt(bcx, llbox, Type::int(bcx.ccx()));
471469
let drop_flag_not_dropped_already =
472470
ICmp(bcx, llvm::IntNE, llbox_as_usize, dropped_pattern, DebugLoc::None);
473471
with_cond(bcx, drop_flag_not_dropped_already, |bcx| {
474472
let bcx = drop_ty(bcx, v0, content_ty, DebugLoc::None);
475-
let info = GEPi(bcx, v0, &[0, abi::FAT_PTR_EXTRA]);
476-
let info = Load(bcx, info);
473+
let info = load_extra(bcx, v0, content_ty);
477474
let (llsize, llalign) = size_and_align_of_dst(bcx, content_ty, info);
478475

479476
// `Box<ZeroSizeType>` does not allocate.
@@ -531,12 +528,11 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
531528
// versus without calling Drop::drop. Assert caller is
532529
// okay with always calling the Drop impl, if any.
533530
assert!(!skip_dtor);
534-
let data_ptr = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
535-
let vtable_ptr = Load(bcx, GEPi(bcx, v0, &[0, abi::FAT_PTR_EXTRA]));
531+
let vtable_ptr = load_extra(bcx, v0, t);
536532
let dtor = Load(bcx, vtable_ptr);
537533
Call(bcx,
538534
dtor,
539-
&[PointerCast(bcx, Load(bcx, data_ptr), Type::i8p(bcx.ccx()))],
535+
&[PointerCast(bcx, load_addr(bcx, v0), Type::i8p(bcx.ccx()))],
540536
None,
541537
DebugLoc::None);
542538
bcx

src/librustc_trans/trans/intrinsic.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
397397
llargs[0]
398398
} else {
399399
let scratch = rvalue_scratch_datum(bcx, tp_ty, "tmp");
400-
Store(bcx, llargs[0], expr::get_dataptr(bcx, scratch.val));
401-
Store(bcx, llargs[1], expr::get_len(bcx, scratch.val));
400+
store_addr(bcx, llargs[0], scratch.val);
401+
store_extra(bcx, llargs[1], scratch.val);
402402
fcx.schedule_lifetime_end(cleanup::CustomScope(cleanup_scope), scratch.val);
403403
scratch.val
404404
};

0 commit comments

Comments
 (0)