Skip to content

Commit e153dea

Browse files
committed
Emit correct alignment information for loads/store of small aggregates
Loading from and storing to small aggregates happens by casting the aggregate pointer to an appropriately sized integer pointer to avoid the usage of first class aggregates which would lead to less optimized code. But this means that, for example, a tuple of type (i16, i16) will be loading through an i32 pointer and because we currently don't provide alignment information LLVM assumes that the load should use the ABI alignment for i32 which would usually be 4 byte alignment. But the alignment requirement for the (i16, i16) tuple will usually be just 2 bytes, so we're overestimating alignment, which invokes undefined behaviour. Therefore we must emit appropriate alignment information for stores/loads through such casted pointers. Fixes #23431
1 parent c773442 commit e153dea

File tree

6 files changed

+38
-16
lines changed

6 files changed

+38
-16
lines changed

src/librustc_trans/trans/adt.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -880,7 +880,7 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
880880
CEnum(ity, min, max) => {
881881
assert_discr_in_range(ity, min, max, discr);
882882
Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true),
883-
val)
883+
val);
884884
}
885885
General(ity, ref cases, dtor) => {
886886
if dtor_active(dtor) {
@@ -889,7 +889,7 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
889889
Store(bcx, C_u8(bcx.ccx(), DTOR_NEEDED as usize), ptr);
890890
}
891891
Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true),
892-
GEPi(bcx, val, &[0, 0]))
892+
GEPi(bcx, val, &[0, 0]));
893893
}
894894
Univariant(ref st, dtor) => {
895895
assert_eq!(discr, 0);
@@ -901,14 +901,14 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
901901
RawNullablePointer { nndiscr, nnty, ..} => {
902902
if discr != nndiscr {
903903
let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty);
904-
Store(bcx, C_null(llptrty), val)
904+
Store(bcx, C_null(llptrty), val);
905905
}
906906
}
907907
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
908908
if discr != nndiscr {
909909
let llptrptr = GEPi(bcx, val, &discrfield[..]);
910910
let llptrty = val_ty(llptrptr).element_type();
911-
Store(bcx, C_null(llptrty), llptrptr)
911+
Store(bcx, C_null(llptrty), llptrptr);
912912
}
913913
}
914914
}

src/librustc_trans/trans/base.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -760,9 +760,14 @@ pub fn load_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
760760
}
761761

762762
let ptr = to_arg_ty_ptr(cx, ptr, t);
763+
let align = type_of::align_of(cx.ccx(), t);
763764

764765
if type_is_immediate(cx.ccx(), t) && type_of::type_of(cx.ccx(), t).is_aggregate() {
765-
return Load(cx, ptr);
766+
let load = Load(cx, ptr);
767+
unsafe {
768+
llvm::LLVMSetAlignment(load, align);
769+
}
770+
return load;
766771
}
767772

768773
unsafe {
@@ -788,13 +793,20 @@ pub fn load_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
788793
Load(cx, ptr)
789794
};
790795

796+
unsafe {
797+
llvm::LLVMSetAlignment(val, align);
798+
}
799+
791800
from_arg_ty(cx, val, t)
792801
}
793802

794803
/// Helper for storing values in memory. Does the necessary conversion if the in-memory type
795804
/// differs from the type used for SSA values.
796805
pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t: Ty<'tcx>) {
797-
Store(cx, to_arg_ty(cx, v, t), to_arg_ty_ptr(cx, dst, t));
806+
let store = Store(cx, to_arg_ty(cx, v, t), to_arg_ty_ptr(cx, dst, t));
807+
unsafe {
808+
llvm::LLVMSetAlignment(store, type_of::align_of(cx.ccx(), t));
809+
}
798810
}
799811

800812
pub fn to_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef {

src/librustc_trans/trans/build.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -646,13 +646,13 @@ pub fn LoadNonNull(cx: Block, ptr: ValueRef) -> ValueRef {
646646
}
647647
}
648648

649-
pub fn Store(cx: Block, val: ValueRef, ptr: ValueRef) {
650-
if cx.unreachable.get() { return; }
649+
pub fn Store(cx: Block, val: ValueRef, ptr: ValueRef) -> ValueRef {
650+
if cx.unreachable.get() { return C_nil(cx.ccx()); }
651651
B(cx).store(val, ptr)
652652
}
653653

654-
pub fn VolatileStore(cx: Block, val: ValueRef, ptr: ValueRef) {
655-
if cx.unreachable.get() { return; }
654+
pub fn VolatileStore(cx: Block, val: ValueRef, ptr: ValueRef) -> ValueRef {
655+
if cx.unreachable.get() { return C_nil(cx.ccx()); }
656656
B(cx).volatile_store(val, ptr)
657657
}
658658

src/librustc_trans/trans/builder.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -509,18 +509,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
509509
value
510510
}
511511

512-
pub fn store(&self, val: ValueRef, ptr: ValueRef) {
512+
pub fn store(&self, val: ValueRef, ptr: ValueRef) -> ValueRef {
513513
debug!("Store {} -> {}",
514514
self.ccx.tn().val_to_string(val),
515515
self.ccx.tn().val_to_string(ptr));
516516
assert!(!self.llbuilder.is_null());
517517
self.count_insn("store");
518518
unsafe {
519-
llvm::LLVMBuildStore(self.llbuilder, val, ptr);
519+
llvm::LLVMBuildStore(self.llbuilder, val, ptr)
520520
}
521521
}
522522

523-
pub fn volatile_store(&self, val: ValueRef, ptr: ValueRef) {
523+
pub fn volatile_store(&self, val: ValueRef, ptr: ValueRef) -> ValueRef {
524524
debug!("Store {} -> {}",
525525
self.ccx.tn().val_to_string(val),
526526
self.ccx.tn().val_to_string(ptr));
@@ -529,6 +529,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
529529
unsafe {
530530
let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
531531
llvm::LLVMSetVolatile(insn, llvm::True);
532+
insn
532533
}
533534
}
534535

src/librustc_trans/trans/foreign.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,9 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
802802
// appropriately sized integer and we have to convert it
803803
let tmp = builder.bitcast(llforeign_arg,
804804
type_of::arg_type_of(ccx, rust_ty).ptr_to());
805-
builder.load(tmp)
805+
let load = builder.load(tmp);
806+
llvm::LLVMSetAlignment(load, type_of::align_of(ccx, rust_ty));
807+
load
806808
} else {
807809
builder.load(llforeign_arg)
808810
}

src/librustc_trans/trans/intrinsic.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -456,13 +456,20 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
456456
(_, "volatile_load") => {
457457
let tp_ty = *substs.types.get(FnSpace, 0);
458458
let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
459-
from_arg_ty(bcx, VolatileLoad(bcx, ptr), tp_ty)
459+
let load = VolatileLoad(bcx, ptr);
460+
unsafe {
461+
llvm::LLVMSetAlignment(load, type_of::align_of(ccx, tp_ty));
462+
}
463+
from_arg_ty(bcx, load, tp_ty)
460464
},
461465
(_, "volatile_store") => {
462466
let tp_ty = *substs.types.get(FnSpace, 0);
463467
let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
464468
let val = to_arg_ty(bcx, llargs[1], tp_ty);
465-
VolatileStore(bcx, val, ptr);
469+
let store = VolatileStore(bcx, val, ptr);
470+
unsafe {
471+
llvm::LLVMSetAlignment(store, type_of::align_of(ccx, tp_ty));
472+
}
466473
C_nil(ccx)
467474
},
468475

0 commit comments

Comments
 (0)