Skip to content

Commit b0e46f0

Browse files
committed
Auto merge of #39586 - arielb1:packed-values, r=eddyb
emit "align 1" metadata on loads/stores of packed structs According to the LLVM reference: > A value of 0 or an omitted align argument means that the operation has the ABI alignment for the target. So loads/stores of fields of packed structs need to have their align set to 1. Implement that by tracking the alignment of `LvalueRef`s. Fixes #39376. r? @eddyb
2 parents fd2f8a4 + d71988a commit b0e46f0

15 files changed

+388
-267
lines changed

src/librustc_trans/adt.rs

+16-9
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ use monomorphize;
5656
use type_::Type;
5757
use type_of;
5858

59+
use mir::lvalue::Alignment;
60+
5961
/// Given an enum, struct, closure, or tuple, extracts fields.
6062
/// Treats closures as a struct with one variant.
6163
/// `empty_if_no_variants` is a switch to deal with empty enums.
@@ -279,6 +281,7 @@ pub fn trans_get_discr<'a, 'tcx>(
279281
bcx: &Builder<'a, 'tcx>,
280282
t: Ty<'tcx>,
281283
scrutinee: ValueRef,
284+
alignment: Alignment,
282285
cast_to: Option<Type>,
283286
range_assert: bool
284287
) -> ValueRef {
@@ -292,11 +295,12 @@ pub fn trans_get_discr<'a, 'tcx>(
292295

293296
let val = match *l {
294297
layout::CEnum { discr, min, max, .. } => {
295-
load_discr(bcx, discr, scrutinee, min, max, range_assert)
298+
load_discr(bcx, discr, scrutinee, alignment, min, max, range_assert)
296299
}
297300
layout::General { discr, .. } => {
298301
let ptr = bcx.struct_gep(scrutinee, 0);
299-
load_discr(bcx, discr, ptr, 0, def.variants.len() as u64 - 1,
302+
load_discr(bcx, discr, ptr, alignment,
303+
0, def.variants.len() as u64 - 1,
300304
range_assert)
301305
}
302306
layout::Univariant { .. } | layout::UntaggedUnion { .. } => C_u8(bcx.ccx, 0),
@@ -305,10 +309,10 @@ pub fn trans_get_discr<'a, 'tcx>(
305309
let llptrty = type_of::sizing_type_of(bcx.ccx,
306310
monomorphize::field_ty(bcx.tcx(), substs,
307311
&def.variants[nndiscr as usize].fields[0]));
308-
bcx.icmp(cmp, bcx.load(scrutinee), C_null(llptrty))
312+
bcx.icmp(cmp, bcx.load(scrutinee, alignment.to_align()), C_null(llptrty))
309313
}
310314
layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
311-
struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee)
315+
struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee, alignment)
312316
},
313317
_ => bug!("{} is not an enum", t)
314318
};
@@ -322,17 +326,19 @@ fn struct_wrapped_nullable_bitdiscr(
322326
bcx: &Builder,
323327
nndiscr: u64,
324328
discrfield: &layout::FieldPath,
325-
scrutinee: ValueRef
329+
scrutinee: ValueRef,
330+
alignment: Alignment,
326331
) -> ValueRef {
327332
let llptrptr = bcx.gepi(scrutinee,
328333
&discrfield.iter().map(|f| *f as usize).collect::<Vec<_>>()[..]);
329-
let llptr = bcx.load(llptrptr);
334+
let llptr = bcx.load(llptrptr, alignment.to_align());
330335
let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
331336
bcx.icmp(cmp, llptr, C_null(val_ty(llptr)))
332337
}
333338

334339
/// Helper for cases where the discriminant is simply loaded.
335-
fn load_discr(bcx: &Builder, ity: layout::Integer, ptr: ValueRef, min: u64, max: u64,
340+
fn load_discr(bcx: &Builder, ity: layout::Integer, ptr: ValueRef,
341+
alignment: Alignment, min: u64, max: u64,
336342
range_assert: bool)
337343
-> ValueRef {
338344
let llty = Type::from_integer(bcx.ccx, ity);
@@ -348,11 +354,12 @@ fn load_discr(bcx: &Builder, ity: layout::Integer, ptr: ValueRef, min: u64, max:
348354
// rejected by the LLVM verifier (it would mean either an
349355
// empty set, which is impossible, or the entire range of the
350356
// type, which is pointless).
351-
bcx.load(ptr)
357+
bcx.load(ptr, alignment.to_align())
352358
} else {
353359
// llvm::ConstantRange can deal with ranges that wrap around,
354360
// so an overflow on (max + 1) is fine.
355-
bcx.load_range_assert(ptr, min, max.wrapping_add(1), /* signed: */ True)
361+
bcx.load_range_assert(ptr, min, max.wrapping_add(1), /* signed: */ True,
362+
alignment.to_align())
356363
}
357364
}
358365

src/librustc_trans/asm.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ use builder::Builder;
2020
use rustc::hir;
2121
use rustc::ty::Ty;
2222

23+
use mir::lvalue::Alignment;
24+
2325
use std::ffi::CString;
2426
use syntax::ast::AsmDialect;
2527
use libc::{c_uint, c_char};
@@ -38,7 +40,7 @@ pub fn trans_inline_asm<'a, 'tcx>(
3840
let mut indirect_outputs = vec![];
3941
for (i, (out, &(val, ty))) in ia.outputs.iter().zip(&outputs).enumerate() {
4042
let val = if out.is_rw || out.is_indirect {
41-
Some(base::load_ty(bcx, val, ty))
43+
Some(base::load_ty(bcx, val, Alignment::Packed, ty))
4244
} else {
4345
None
4446
};

src/librustc_trans/base.rs

+41-36
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ use rustc::hir;
9090
use rustc::ty::layout::{self, Layout};
9191
use syntax::ast;
9292

93+
use mir::lvalue::Alignment;
94+
9395
pub struct StatRecorder<'a, 'tcx: 'a> {
9496
ccx: &'a CrateContext<'a, 'tcx>,
9597
name: Option<String>,
@@ -250,25 +252,25 @@ pub fn unsize_thin_ptr<'a, 'tcx>(
250252
/// Coerce `src`, which is a reference to a value of type `src_ty`,
251253
/// to a value of type `dst_ty` and store the result in `dst`
252254
pub fn coerce_unsized_into<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
253-
src: ValueRef,
254-
src_ty: Ty<'tcx>,
255-
dst: ValueRef,
256-
dst_ty: Ty<'tcx>) {
255+
src: &LvalueRef<'tcx>,
256+
dst: &LvalueRef<'tcx>) {
257+
let src_ty = src.ty.to_ty(bcx.tcx());
258+
let dst_ty = dst.ty.to_ty(bcx.tcx());
257259
let coerce_ptr = || {
258260
let (base, info) = if common::type_is_fat_ptr(bcx.ccx, src_ty) {
259261
// fat-ptr to fat-ptr unsize preserves the vtable
260262
// i.e. &'a fmt::Debug+Send => &'a fmt::Debug
261263
// So we need to pointercast the base to ensure
262264
// the types match up.
263-
let (base, info) = load_fat_ptr(bcx, src, src_ty);
265+
let (base, info) = load_fat_ptr(bcx, src.llval, src.alignment, src_ty);
264266
let llcast_ty = type_of::fat_ptr_base_ty(bcx.ccx, dst_ty);
265267
let base = bcx.pointercast(base, llcast_ty);
266268
(base, info)
267269
} else {
268-
let base = load_ty(bcx, src, src_ty);
270+
let base = load_ty(bcx, src.llval, src.alignment, src_ty);
269271
unsize_thin_ptr(bcx, base, src_ty, dst_ty)
270272
};
271-
store_fat_ptr(bcx, base, info, dst, dst_ty);
273+
store_fat_ptr(bcx, base, info, dst.llval, dst.alignment, dst_ty);
272274
};
273275
match (&src_ty.sty, &dst_ty.sty) {
274276
(&ty::TyRef(..), &ty::TyRef(..)) |
@@ -290,21 +292,22 @@ pub fn coerce_unsized_into<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
290292
monomorphize::field_ty(bcx.tcx(), substs_b, f)
291293
});
292294

293-
let src = LvalueRef::new_sized_ty(src, src_ty);
294-
let dst = LvalueRef::new_sized_ty(dst, dst_ty);
295-
296295
let iter = src_fields.zip(dst_fields).enumerate();
297296
for (i, (src_fty, dst_fty)) in iter {
298297
if type_is_zero_size(bcx.ccx, dst_fty) {
299298
continue;
300299
}
301300

302-
let src_f = src.trans_field_ptr(bcx, i);
303-
let dst_f = dst.trans_field_ptr(bcx, i);
301+
let (src_f, src_f_align) = src.trans_field_ptr(bcx, i);
302+
let (dst_f, dst_f_align) = dst.trans_field_ptr(bcx, i);
304303
if src_fty == dst_fty {
305304
memcpy_ty(bcx, dst_f, src_f, src_fty, None);
306305
} else {
307-
coerce_unsized_into(bcx, src_f, src_fty, dst_f, dst_fty);
306+
coerce_unsized_into(
307+
bcx,
308+
&LvalueRef::new_sized_ty(src_f, src_fty, src_f_align),
309+
&LvalueRef::new_sized_ty(dst_f, dst_fty, dst_f_align)
310+
);
308311
}
309312
}
310313
}
@@ -399,7 +402,8 @@ pub fn call_assume<'a, 'tcx>(b: &Builder<'a, 'tcx>, val: ValueRef) {
399402
/// Helper for loading values from memory. Does the necessary conversion if the in-memory type
400403
/// differs from the type used for SSA values. Also handles various special cases where the type
401404
/// gives us better information about what we are loading.
402-
pub fn load_ty<'a, 'tcx>(b: &Builder<'a, 'tcx>, ptr: ValueRef, t: Ty<'tcx>) -> ValueRef {
405+
pub fn load_ty<'a, 'tcx>(b: &Builder<'a, 'tcx>, ptr: ValueRef,
406+
alignment: Alignment, t: Ty<'tcx>) -> ValueRef {
403407
let ccx = b.ccx;
404408
if type_is_zero_size(ccx, t) {
405409
return C_undef(type_of::type_of(ccx, t));
@@ -419,54 +423,57 @@ pub fn load_ty<'a, 'tcx>(b: &Builder<'a, 'tcx>, ptr: ValueRef, t: Ty<'tcx>) -> V
419423
}
420424

421425
if t.is_bool() {
422-
b.trunc(b.load_range_assert(ptr, 0, 2, llvm::False), Type::i1(ccx))
426+
b.trunc(b.load_range_assert(ptr, 0, 2, llvm::False, alignment.to_align()),
427+
Type::i1(ccx))
423428
} else if t.is_char() {
424429
// a char is a Unicode codepoint, and so takes values from 0
425430
// to 0x10FFFF inclusive only.
426-
b.load_range_assert(ptr, 0, 0x10FFFF + 1, llvm::False)
431+
b.load_range_assert(ptr, 0, 0x10FFFF + 1, llvm::False, alignment.to_align())
427432
} else if (t.is_region_ptr() || t.is_box()) && !common::type_is_fat_ptr(ccx, t) {
428-
b.load_nonnull(ptr)
433+
b.load_nonnull(ptr, alignment.to_align())
429434
} else {
430-
b.load(ptr)
435+
b.load(ptr, alignment.to_align())
431436
}
432437
}
433438

434439
/// Helper for storing values in memory. Does the necessary conversion if the in-memory type
435440
/// differs from the type used for SSA values.
436-
pub fn store_ty<'a, 'tcx>(cx: &Builder<'a, 'tcx>, v: ValueRef, dst: ValueRef, t: Ty<'tcx>) {
441+
pub fn store_ty<'a, 'tcx>(cx: &Builder<'a, 'tcx>, v: ValueRef, dst: ValueRef,
442+
dst_align: Alignment, t: Ty<'tcx>) {
437443
debug!("store_ty: {:?} : {:?} <- {:?}", Value(dst), t, Value(v));
438444

439445
if common::type_is_fat_ptr(cx.ccx, t) {
440446
let lladdr = cx.extract_value(v, abi::FAT_PTR_ADDR);
441447
let llextra = cx.extract_value(v, abi::FAT_PTR_EXTRA);
442-
store_fat_ptr(cx, lladdr, llextra, dst, t);
448+
store_fat_ptr(cx, lladdr, llextra, dst, dst_align, t);
443449
} else {
444-
cx.store(from_immediate(cx, v), dst, None);
450+
cx.store(from_immediate(cx, v), dst, dst_align.to_align());
445451
}
446452
}
447453

448454
pub fn store_fat_ptr<'a, 'tcx>(cx: &Builder<'a, 'tcx>,
449455
data: ValueRef,
450456
extra: ValueRef,
451457
dst: ValueRef,
458+
dst_align: Alignment,
452459
_ty: Ty<'tcx>) {
453460
// FIXME: emit metadata
454-
cx.store(data, get_dataptr(cx, dst), None);
455-
cx.store(extra, get_meta(cx, dst), None);
461+
cx.store(data, get_dataptr(cx, dst), dst_align.to_align());
462+
cx.store(extra, get_meta(cx, dst), dst_align.to_align());
456463
}
457464

458465
pub fn load_fat_ptr<'a, 'tcx>(
459-
b: &Builder<'a, 'tcx>, src: ValueRef, t: Ty<'tcx>
466+
b: &Builder<'a, 'tcx>, src: ValueRef, alignment: Alignment, t: Ty<'tcx>
460467
) -> (ValueRef, ValueRef) {
461468
let ptr = get_dataptr(b, src);
462469
let ptr = if t.is_region_ptr() || t.is_box() {
463-
b.load_nonnull(ptr)
470+
b.load_nonnull(ptr, alignment.to_align())
464471
} else {
465-
b.load(ptr)
472+
b.load(ptr, alignment.to_align())
466473
};
467474

468475
// FIXME: emit metadata on `meta`.
469-
let meta = b.load(get_meta(b, src));
476+
let meta = b.load(get_meta(b, src), alignment.to_align());
470477

471478
(ptr, meta)
472479
}
@@ -633,7 +640,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
633640
bcx.alloca(fn_ty.ret.memory_ty(ccx), "sret_slot")
634641
};
635642
// Can return unsized value
636-
let mut dest_val = LvalueRef::new_sized_ty(dest, sig.output());
643+
let mut dest_val = LvalueRef::new_sized_ty(dest, sig.output(), Alignment::AbiAligned);
637644
dest_val.ty = LvalueTy::Downcast {
638645
adt_def: sig.output().ty_adt_def().unwrap(),
639646
substs: substs,
@@ -642,7 +649,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
642649
let mut llarg_idx = fn_ty.ret.is_indirect() as usize;
643650
let mut arg_idx = 0;
644651
for (i, arg_ty) in sig.inputs().iter().enumerate() {
645-
let lldestptr = dest_val.trans_field_ptr(&bcx, i);
652+
let (lldestptr, _) = dest_val.trans_field_ptr(&bcx, i);
646653
let arg = &fn_ty.args[arg_idx];
647654
arg_idx += 1;
648655
if common::type_is_fat_ptr(bcx.ccx, arg_ty) {
@@ -662,14 +669,12 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
662669
}
663670

664671
if let Some(cast_ty) = fn_ty.ret.cast {
665-
let load = bcx.load(bcx.pointercast(dest, cast_ty.ptr_to()));
666-
let llalign = llalign_of_min(ccx, fn_ty.ret.ty);
667-
unsafe {
668-
llvm::LLVMSetAlignment(load, llalign);
669-
}
670-
bcx.ret(load)
672+
bcx.ret(bcx.load(
673+
bcx.pointercast(dest, cast_ty.ptr_to()),
674+
Some(llalign_of_min(ccx, fn_ty.ret.ty))
675+
));
671676
} else {
672-
bcx.ret(bcx.load(dest))
677+
bcx.ret(bcx.load(dest, None))
673678
}
674679
} else {
675680
bcx.ret_void();

src/librustc_trans/builder.rs

+12-13
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@ use machine::llalign_of_pref;
1919
use type_::Type;
2020
use value::Value;
2121
use libc::{c_uint, c_char};
22-
use rustc::ty::{Ty, TyCtxt, TypeFoldable};
22+
use rustc::ty::TyCtxt;
2323
use rustc::session::Session;
24-
use type_of;
2524

2625
use std::borrow::Cow;
2726
use std::ffi::CString;
@@ -486,11 +485,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
486485
builder.dynamic_alloca(ty, name)
487486
}
488487

489-
pub fn alloca_ty(&self, ty: Ty<'tcx>, name: &str) -> ValueRef {
490-
assert!(!ty.has_param_types());
491-
self.alloca(type_of::type_of(self.ccx, ty), name)
492-
}
493-
494488
pub fn dynamic_alloca(&self, ty: Type, name: &str) -> ValueRef {
495489
self.count_insn("alloca");
496490
unsafe {
@@ -511,10 +505,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
511505
}
512506
}
513507

514-
pub fn load(&self, ptr: ValueRef) -> ValueRef {
508+
pub fn load(&self, ptr: ValueRef, align: Option<u32>) -> ValueRef {
515509
self.count_insn("load");
516510
unsafe {
517-
llvm::LLVMBuildLoad(self.llbuilder, ptr, noname())
511+
let load = llvm::LLVMBuildLoad(self.llbuilder, ptr, noname());
512+
if let Some(align) = align {
513+
llvm::LLVMSetAlignment(load, align as c_uint);
514+
}
515+
load
518516
}
519517
}
520518

@@ -539,8 +537,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
539537

540538

541539
pub fn load_range_assert(&self, ptr: ValueRef, lo: u64,
542-
hi: u64, signed: llvm::Bool) -> ValueRef {
543-
let value = self.load(ptr);
540+
hi: u64, signed: llvm::Bool,
541+
align: Option<u32>) -> ValueRef {
542+
let value = self.load(ptr, align);
544543

545544
unsafe {
546545
let t = llvm::LLVMGetElementType(llvm::LLVMTypeOf(ptr));
@@ -558,8 +557,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
558557
value
559558
}
560559

561-
pub fn load_nonnull(&self, ptr: ValueRef) -> ValueRef {
562-
let value = self.load(ptr);
560+
pub fn load_nonnull(&self, ptr: ValueRef, align: Option<u32>) -> ValueRef {
561+
let value = self.load(ptr, align);
563562
unsafe {
564563
llvm::LLVMSetMetadata(value, llvm::MD_nonnull as c_uint,
565564
llvm::LLVMMDNodeInContext(self.ccx.llcx(), ptr::null(), 0));

0 commit comments

Comments
 (0)