Skip to content

Commit 268ac24

Browse files
committed
alignment: subtly change meaning of datatype_align (#34473)
Rather than meaning the actual alignment of the object, this now means the preferred alignment of the object. The actual alignment of any object is the minimum of this preferred alignment and the alignment supported by the runtime allocator. This aligns us with how LLVM treats alignment, and is probably reasonably sensible anyways. Also tries to audit our existing uses of CreateLoad/CreateStore for correctness, and upgrade some to include pointer-types. fixes #32414
1 parent 9464069 commit 268ac24

10 files changed

+81
-72
lines changed

base/reflection.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,8 @@ struct DataTypeLayout
319319
nfields::UInt32
320320
npointers::UInt32
321321
firstptr::Int32
322-
alignment::UInt32
323-
# alignment : 9;
322+
alignment::UInt16
323+
flags::UInt16
324324
# haspadding : 1;
325325
# fielddesc_type : 2;
326326
end
@@ -335,7 +335,7 @@ function datatype_alignment(dt::DataType)
335335
@_pure_meta
336336
dt.layout == C_NULL && throw(UndefRefError())
337337
alignment = unsafe_load(convert(Ptr{DataTypeLayout}, dt.layout)).alignment
338-
return Int(alignment & 0x1FF)
338+
return Int(alignment)
339339
end
340340

341341
# amount of total space taken by T when stored in a container
@@ -368,8 +368,8 @@ Can be called on any `isconcretetype`.
368368
function datatype_haspadding(dt::DataType)
369369
@_pure_meta
370370
dt.layout == C_NULL && throw(UndefRefError())
371-
alignment = unsafe_load(convert(Ptr{DataTypeLayout}, dt.layout)).alignment
372-
return (alignment >> 9) & 1 == 1
371+
flags = unsafe_load(convert(Ptr{DataTypeLayout}, dt.layout)).flags
372+
return flags & 1 == 1
373373
end
374374

375375
"""
@@ -397,8 +397,8 @@ See also [`fieldoffset`](@ref).
397397
function datatype_fielddesc_type(dt::DataType)
398398
@_pure_meta
399399
dt.layout == C_NULL && throw(UndefRefError())
400-
alignment = unsafe_load(convert(Ptr{DataTypeLayout}, dt.layout)).alignment
401-
return (alignment >> 10) & 3
400+
flags = unsafe_load(convert(Ptr{DataTypeLayout}, dt.layout)).flags
401+
return (flags >> 1) & 3
402402
end
403403

404404
"""

src/array.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ JL_DLLEXPORT jl_array_t *jl_ptr_to_array_1d(jl_value_t *atype, void *data,
318318
else {
319319
align = elsz = sizeof(void*);
320320
}
321-
if (((uintptr_t)data) & (align - 1))
321+
if (((uintptr_t)data) & ((align > JL_HEAP_ALIGNMENT ? JL_HEAP_ALIGNMENT : align) - 1))
322322
jl_exceptionf(jl_argumenterror_type,
323323
"unsafe_wrap: pointer %p is not properly aligned to %u bytes", data, align);
324324

@@ -385,7 +385,7 @@ JL_DLLEXPORT jl_array_t *jl_ptr_to_array(jl_value_t *atype, void *data,
385385
else {
386386
align = elsz = sizeof(void*);
387387
}
388-
if (((uintptr_t)data) & (align - 1))
388+
if (((uintptr_t)data) & ((align > JL_HEAP_ALIGNMENT ? JL_HEAP_ALIGNMENT : align) - 1))
389389
jl_exceptionf(jl_argumenterror_type,
390390
"unsafe_wrap: pointer %p is not properly aligned to %u bytes", data, align);
391391

src/ccall.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ static Value *llvm_type_rewrite(
418418
from = emit_static_alloca(ctx, from_type);
419419
to = emit_bitcast(ctx, from, target_type->getPointerTo());
420420
}
421+
// XXX: deal with possible alignment issues
421422
ctx.builder.CreateStore(v, from);
422423
return ctx.builder.CreateLoad(to);
423424
}
@@ -514,7 +515,7 @@ static Value *julia_to_native(
514515
tbaa_decorate(jvinfo.tbaa, ctx.builder.CreateStore(emit_unbox(ctx, to, jvinfo, jlto), slot));
515516
}
516517
else {
517-
emit_memcpy(ctx, slot, jvinfo.tbaa, jvinfo, jl_datatype_size(jlto), jl_datatype_align(jlto));
518+
emit_memcpy(ctx, slot, jvinfo.tbaa, jvinfo, jl_datatype_size(jlto), julia_alignment(jlto));
518519
}
519520
return slot;
520521
}
@@ -1945,7 +1946,7 @@ jl_cgval_t function_sig_t::emit_a_ccall(
19451946
assert(rtsz > 0);
19461947
Value *strct = emit_allocobj(ctx, rtsz, runtime_bt);
19471948
MDNode *tbaa = jl_is_mutable(rt) ? tbaa_mutab : tbaa_immut;
1948-
int boxalign = jl_datatype_align(rt);
1949+
int boxalign = julia_alignment(rt);
19491950
// copy the data from the return value to the new struct
19501951
const DataLayout &DL = jl_data_layout;
19511952
auto resultTy = result->getType();

src/cgutils.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,8 @@ static unsigned julia_alignment(jl_value_t *jt)
386386
}
387387
assert(jl_is_datatype(jt) && ((jl_datatype_t*)jt)->layout);
388388
unsigned alignment = jl_datatype_align(jt);
389-
assert(alignment <= JL_HEAP_ALIGNMENT);
390-
assert(JL_HEAP_ALIGNMENT % alignment == 0);
389+
if (alignment > JL_HEAP_ALIGNMENT)
390+
return JL_HEAP_ALIGNMENT;
391391
return alignment;
392392
}
393393

@@ -594,7 +594,7 @@ static unsigned jl_field_align(jl_datatype_t *dt, size_t i)
594594
unsigned al = jl_field_offset(dt, i);
595595
al |= 16;
596596
al &= -al;
597-
return std::min(al, jl_datatype_align(dt));
597+
return std::min({al, (unsigned)jl_datatype_align(dt), (unsigned)JL_HEAP_ALIGNMENT});
598598
}
599599

600600
static Type *julia_struct_to_llvm(jl_value_t *jt, jl_unionall_t *ua, bool *isboxed, bool llvmcall)
@@ -636,7 +636,6 @@ static Type *julia_struct_to_llvm(jl_value_t *jt, jl_unionall_t *ua, bool *isbox
636636
if (jst->layout) {
637637
assert(isptr == jl_field_isptr(jst, i));
638638
assert((isptr ? sizeof(void*) : fsz + jl_is_uniontype(ty)) == jl_field_size(jst, i));
639-
assert(al <= jl_field_align(jst, i));
640639
}
641640
Type *lty;
642641
if (isptr) {
@@ -647,8 +646,15 @@ static Type *julia_struct_to_llvm(jl_value_t *jt, jl_unionall_t *ua, bool *isbox
647646
lty = T_int8;
648647
}
649648
else if (jl_is_uniontype(ty)) {
650-
// pick an Integer type size such that alignment will be correct
651-
// and always end with an Int8 (selector byte)
649+
// pick an Integer type size such that alignment will generally be correct,
650+
// and always end with an Int8 (selector byte).
651+
// We may need to insert padding first to get to the right offset
652+
if (al > MAX_ALIGN) {
653+
Type *AlignmentType = ArrayType::get(VectorType::get(T_int8, al), 0);
654+
latypes.push_back(AlignmentType);
655+
al = MAX_ALIGN;
656+
}
657+
assert(al <= jl_field_align(jst, i));
652658
Type *AlignmentType = IntegerType::get(jl_LLVMContext, 8 * al);
653659
unsigned NumATy = fsz / al;
654660
unsigned remainder = fsz % al;
@@ -1212,7 +1218,7 @@ static Value *emit_isconcrete(jl_codectx_t &ctx, Value *typ)
12121218
{
12131219
Value *isconcrete;
12141220
isconcrete = ctx.builder.CreateConstInBoundsGEP1_32(T_int8, emit_bitcast(ctx, decay_derived(typ), T_pint8), offsetof(jl_datatype_t, isconcretetype));
1215-
isconcrete = ctx.builder.CreateLoad(isconcrete, tbaa_const);
1221+
isconcrete = ctx.builder.CreateLoad(T_int8, isconcrete, tbaa_const);
12161222
isconcrete = ctx.builder.CreateTrunc(isconcrete, T_int1);
12171223
return isconcrete;
12181224
}
@@ -1336,7 +1342,7 @@ static jl_cgval_t typed_load(jl_codectx_t &ctx, Value *ptr, Value *idx_0based, j
13361342
//}
13371343
//else {
13381344
load = ctx.builder.CreateAlignedLoad(data,
1339-
isboxed || alignment ? alignment : julia_alignment(jltype),
1345+
isboxed || alignment ? alignment : julia_alignment(jltype),
13401346
false);
13411347
if (aliasscope)
13421348
load->setMetadata("alias.scope", aliasscope);
@@ -2434,7 +2440,8 @@ static Value *boxed(jl_codectx_t &ctx, const jl_cgval_t &vinfo)
24342440
static void emit_unionmove(jl_codectx_t &ctx, Value *dest, MDNode *tbaa_dst, const jl_cgval_t &src, Value *skip, bool isVolatile=false)
24352441
{
24362442
if (AllocaInst *ai = dyn_cast<AllocaInst>(dest))
2437-
ctx.builder.CreateStore(UndefValue::get(ai->getAllocatedType()), ai);
2443+
// TODO: make this a lifetime_end & dereferencable annotation?
2444+
ctx.builder.CreateAlignedStore(UndefValue::get(ai->getAllocatedType()), ai, ai->getAlignment());
24382445
if (jl_is_concrete_type(src.typ) || src.constant) {
24392446
jl_value_t *typ = src.constant ? jl_typeof(src.constant) : src.typ;
24402447
Type *store_ty = julia_type_to_llvm(typ);
@@ -2694,7 +2701,7 @@ static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t narg
26942701
if (jl_field_isptr(sty, i)) {
26952702
fval = boxed(ctx, fval_info);
26962703
if (!init_as_value)
2697-
tbaa_decorate(tbaa_stack, ctx.builder.CreateStore(fval, dest));
2704+
tbaa_decorate(tbaa_stack, ctx.builder.CreateAlignedStore(fval, dest, jl_field_align(sty, i)));
26982705
}
26992706
else if (jl_is_uniontype(jtype)) {
27002707
// compute tindex from rhs

0 commit comments

Comments
 (0)