-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support isbits Union array elements and struct fields #22441
Conversation
5bd23b1
to
8f010bb
Compare
Could use a review from @vtjnash. |
Unfortunately for him, I commandeered his day yesterday to help me w/ the latest commit I pushed 😄 |
dbc36f1
to
97d5d44
Compare
Ok, an update here:
Otherwise, I do think this code is at a place to be reviewed by @vtjnash & @yuyichao at least in case there's something egregious going on. |
src/datatype.c
Outdated
|
||
JL_DLLEXPORT int jl_islayout_inline(jl_value_t *eltype, size_t *fsz, size_t *al) | ||
{ | ||
unsigned countbits = union_isbits(eltype, fsz, al); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indent's off here
src/datatype.c
Outdated
} | ||
if (jl_layout_isbits(ty)) { | ||
size_t sz = jl_datatype_size(ty); | ||
size_t al = ((jl_datatype_t*)ty)->layout->alignment; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use jl_datatype_align
for this
src/datatype.c
Outdated
size_t al = ((jl_datatype_t*)ty)->layout->alignment; | ||
if (*nbytes < sz) | ||
*nbytes = sz; | ||
if (*align < al) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC in a bitsunion array we can store elements that are eitherA
or B
?
I would think that the alignment needs to be a multiple of the alignment of A
and B
.
As an example, if A
has alignment 8 and B
as alignment 12
the alignment would need to be 24
(Joint alignment needs to be divisible by the individual alignments.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As it has been pointed out to me alignment 12 shouldn't exist (and me encountering that is probably a bug). Nevertheless, we should make sure that the new alignment is compatible with both.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, alignments must be powers of N (usually 2), otherwise N * alignment wouldn't be aligned to the alignment. Hence picking the larger alignment is always sufficient.
Added a "Closes #17073" to the top comment. |
e677731
to
af19042
Compare
Alrighty, another round of updates here. The new commits address the comments that were posted, general code cleanup, code comments and documentation, and getting tests passing (all Base tests pass for me locally). Apart from ensuring CI is happy, the remaining known issues that I'm aware of are two bugs that I suspect may be related to still-needed inference changes? Case 1: v = Vector{Union{Int8, Void}}(10)
v[1] = 10 this currently segfaults on an assert on the TIndex. I don't quite understand how we're getting past the call to convert in the Base.setindex! method setindex!(A::Array{T}, x, i1::Int) where {T} = arrayset(A, convert(T,x)::T, i1) Julia 0.6 appropriately fails with the error of Case 2: julia> mutable struct UnionField
x::Union{Int8, Void}
end
julia> x = UnionField(nothing)
UnionField(nothing)
julia> x.x = Int8(1)
1
julia> x
UnionField(0) Again, my efforts of trying to step through codegen were pretty futile and I had a hard time figuring out why exactly things weren't getting set correctly. I'll probably try to dig into this error again, but any tips again would be most appreciated. |
85223f9
to
6f52a44
Compare
Value *ptindex = ctx.builder.CreateGEP(T_int8, emit_bitcast(ctx, addr, T_pint8), ConstantInt::get(T_size, fsz - 1)); | ||
ctx.builder.CreateStore(tindex, ptindex); | ||
// copy data | ||
if (!rhs.isghost) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if this is the most idiomatic way to check for a singleton type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems OK. We should probably try to clean up codegen, since ghost actually probably refers to being an immutable singleton, and is probably inconsistent as to whether it refers to mutable singletons also.
src/codegen.cpp
Outdated
if (jl_is_uniontype(ety)) { | ||
Value *nbytes = ConstantInt::get(T_size, elsz); | ||
Value *data = emit_arrayptr(ctx, ary, args[1]); | ||
if (!(rhs.typ == jl_bottom_type)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if this is the right kind of check here; the issue is when you have something like
v = Vector{Union{Int8, Void}}(10);
v[1] = Int64(10)
this should result in a convert
error, but it passes thru codegen with rhs
being jl_bottom_type
, which ends up throwing an error in compute_tindex_unboxed
(since Bottom type doesn't match one of the Union types).
Alright, this now passes all tests locally and I've fixed all known bugs that I'm aware of. Let's see what CI says. |
6fd2ff5
to
c02f3e6
Compare
Progress! 2 green checks on travis (linux & osx 64-bit), and just pushed a fix for 32-bit. I'm not sure what happened on appveyor 64-bit, has anyone seen that error before? |
gc issue, missing root maybe?
|
Removed the "WIP" from the PR title and updated to reflect struct field type support. There have been intermittent travis/appveyor failures that are fairly cryptic, some seem unrelated to changes here while others do seem related. I'll keep trying to track down failures, but at this point, those w/ more knowledge might see obvious issues by just reviewing the code. |
9b3a4ed
to
fcc891e
Compare
Uh....what's w/ the windows failure? Did I change to a unsupported printf format code for windows or something? |
|
src/array.c
Outdated
@@ -586,6 +616,10 @@ static int NOINLINE array_resize_buffer(jl_array_t *a, size_t newlen) | |||
nbytes++; | |||
oldnbytes++; | |||
} | |||
if (!a->flags.ptrarray && jl_is_uniontype(jl_tparam0(jl_typeof(a)))) { | |||
nbytes += oldlen; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+= newlen
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
unlike codegen, only bitstypes (!isptr) fields are permitted in the union and the offset count starts from 0 instead of 1 but otherwise the tindex counter is compatible
f9766a6
to
88341b9
Compare
Value *selidx = ctx.builder.CreateMul(emit_arraylen_prim(ctx, ary), nbytes); | ||
selidx = ctx.builder.CreateAdd(selidx, idx); | ||
Value *ptindex = ctx.builder.CreateGEP(T_int8, data, selidx); | ||
Value *tindex = ctx.builder.CreateNUWAdd(ConstantInt::get(T_int8, 1), tbaa_decorate(tbaa_arrayselbyte, ctx.builder.CreateLoad(T_int8, ptindex))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vtjnash, added the tbaa_arrayselbyte
tbaa.
All that green feels super good. |
@nanosoldier |
Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @ararslan |
None of the benchmark results look like anything to worry about; after checking things out locally, it seems like these are just some of the noisiest benchmarks we have. |
I'm actually not surprised w/ the benchmarks, since I doubt many of them involve Unions at all. What we really need are some isbits-Union benchmarks; I have some lying around, but I'll try to clean them up and post some local results and plan on adding some to BaseBenchmarks. |
Tangentially, It would be cool to have some non-micro benchmarks where unions are a natural way of solving the problem, and make the code significantly simpler. |
I think the only one I was concerned with was the allocations. Any idea what those came from? |
Hmmm.....I've spent a few hours now digging thru performance/benchmarking and nothing seems really out of the ordinary. The Anybody else have any ideas on benchmarking or concerns with merging? |
I'll give this till the morning (12 hours or so) for any last reviewers |
should have been squashed if the intermediate commits don't all work |
"all work"; does that mean each commit should pass all tests? just compile? I tried to keep each of the commits pretty logically separated between union field support, array support, then tests, etc. |
pass tests ideally, depends what future bisectors are looking for. |
ok, cool. FWIW, I believe tests should have passed for all commits, except maybe after jameson's first, but I also didn't want to clobber his commit w/ the fix. |
Note this is based on the
jn/union-bits-layout
branch.This is an initial attempt to fix some of the issues reported here.
This successfully compiles, but I'm still feeling my way around
/src
code and figuring out if my code paths are even getting hit. The idea here is that when we allocate aUnion{T, S}
array whereT
andS
are both isbits, we compute the "element size" for the array usingjl_union_isbits
, allocate the buffer for that, then add on an extra "selector" byte for each element after the data buffer. The "selector" bytes indicate which Union element is actually stored in a data buffer element.If anyone can provide more pointers to what else needs to be updated, or simple ways to ensure I'm actually hitting codepaths, I'd appreciate it. I feel like a bit of a bull in a china shop here 😄 .
Closes #17073