Skip to content

core: support odd-bit primitive integers, add Core.bitsizeof#61359

Open
fingolfin wants to merge 19 commits into
masterfrom
codex/int63-primitive-support
Open

core: support odd-bit primitive integers, add Core.bitsizeof#61359
fingolfin wants to merge 19 commits into
masterfrom
codex/int63-primitive-support

Conversation

@fingolfin

Copy link
Copy Markdown
Member

Allow declaring primitive integer types with non-byte logical widths while keeping their storage byte-rounded. Track the declared bit width in datatype layout metadata, use it in width-sensitive runtime and codegen paths, and add Core.bitsizeof for public introspection.

Update bitstring and the manual to reflect logical bit widths, and add coverage for UInt63 and Int63 declarations, conversions, and LLVM lowering.

Some non-goals for this initial step:

  • packed array storage
  • reinterpret/array layout changes
  • broader ABI guarantees for odd-bit primitive integers
  • actually defining UInt63 or similar types anywhere other than the test suite
  • adding full-blown arithmetics and interop for these these types (doing so seems to be opening a can of worms, while in my applications, I will mostly end up coercing or bitshifting between these types and "ordinary" Int64/UInt64 types anyway).

This pull request was written with the assistance of generative AI.

Co-authored-by: Codex codex@openai.com

Motivated by discussion on PR #61262.

Also constitutes partial progress on issue #45486 (but no attempts at bit packed arrays, or "arbitrary size" integers, just enabling odd size).

@JeffBezanson

Copy link
Copy Markdown
Member

Thanks for working on this, this would be a great feature.

@topolarity

Copy link
Copy Markdown
Member

Thanks for starting this initiative. Not sure how useful this is to you, but I went ahead and spun up a bot to explore an implementation for #61361 along with this change: 8a8a6ac

That commit also punts on the issue of bit-level padding in reinterpret, but the bot did try to implement intrinsics, etc. to avoid regressing e.g. UInt24 . I tried to keep the robot mostly on the rails and prod it for useful tests, but it's in major need of human hands / clean-up / comprehensive review still. Anyway I thought it might be a useful reference for you to compare against. I do think it found at least a few places to update that are missing from this PR as-is.

fingolfin and others added 6 commits March 20, 2026 21:27
Allow declaring primitive integer types with non-byte logical
widths while keeping their storage byte-rounded. Track the
declared bit width in datatype layout metadata, use it in
width-sensitive runtime and codegen paths, and add Core.bitsizeof
for public introspection.

Update bitstring and the manual to reflect logical bit widths, and
add coverage for UInt63 and Int63 declarations, conversions, and
LLVM lowering.

Co-authored-by: Codex <codex@openai.com>
Handle byte extraction in bitstring by logical bit width rather
than rounded storage size. Sub-byte primitives need zero-extension
to UInt8, while wider odd-bit primitives still truncate to their
low byte.

Add regression coverage for a 6-bit primitive to keep bitstring
working below one byte.

Co-authored-by: Codex <codex@openai.com>
Store odd-bit primitive width metadata in an explicit unused_bits
field instead of overloading the layout struct padding bits. This
keeps the layout description self-documenting while preserving the
same packed footprint.

Adjust the layout builder and runtime metadata accessors to use
the new field name, and update the corresponding runtime_internals
bitfield notes.

Co-authored-by: Codex <codex@openai.com>
Reject byte-oriented reinterpret helpers for non-byte-aligned
primitive types, fix APInt sign, zero-extension, and truncation
for sub-byte widths, and use storage width for ABI integer
rewrites. Extend the odd-width intrinsics and reinterpret tests.

Co-authored-by: Codex <codex@openai.com>
Rewrite the primitive type description to say that the declared
bit count is the logical width, while storage remains
byte-rounded. This keeps the manual aligned with odd-bit primitive
support and Core.bitsizeof.

Co-authored-by: Codex <codex@openai.com>
Add regressions for odd-width primitive equality and object
identity masking, integer-float conversion round trips, Ref and
field loads, and storage-metadata behavior. Extend reinterpret
coverage for odd-width primitive layout metadata as well.

Co-authored-by: Codex <codex@openai.com>
@fingolfin fingolfin force-pushed the codex/int63-primitive-support branch from e8cd519 to 553f547 Compare March 20, 2026 20:28
@fingolfin

Copy link
Copy Markdown
Member Author

@topolarity we (Codex and me) substantially revised this, also based on some of the things you did in your PR.

Perhaps triage can make a decision on issue #61361 so I know whether to take that into account or not...

@fingolfin

Copy link
Copy Markdown
Member Author

BTW there is at least one genuine test failure, I just did not yet have time to look into it:

Error in testset intrinsics:
Error During Test at /cache/build/tester-amdci4-15/julialang/julia-master/julia-553f547e5a/share/julia/test/testdefs.jl:25
  Got exception outside of a @test
  LoadError: MethodError: no method matching Main.Test60Main_intrinsics.Int63(::Int32)
  The type `Main.Test60Main_intrinsics.Int63` exists, but no method is defined for this combination of argument types when trying to construct it.
  Closest candidates are:
    (::Type{T})(::T) where T<:Number
     @ Core boot.jl:1087
    Main.Test60Main_intrinsics.Int63(::Int64)
     @ Main.Test60Main_intrinsics /cache/build/tester-amdci4-15/julialang/julia-master/julia-553f547e5a/share/julia/test/intrinsics.jl:200
    (::Type{<:Integer})(::Sockets.IPAddr)
     @ Sockets /cache/build/tester-amdci4-15/julialang/julia-master/julia-553f547e5a/share/julia/stdlib/v1.14/Sockets/src/IPAddr.jl:11
    ...

@topolarity

topolarity commented Apr 3, 2026

Copy link
Copy Markdown
Member

Perhaps triage can make a decision on issue #61361 so I know whether to take that into account or not...

I think it might be possible to proceed without the triage decision, at least for a while. If we can make progress making the codebase consistent about allocation vs. storage vs. register (bit) size then accepting #61361 is a small change to make allocation size == storage size but most of codegen, intrinsics, etc. shouldn't be affected too badly.

I do think it might be useful to create an "action list" of areas that need non-byte-multiple integer support and to tackle them piece-by-piece. Specifically this piece:

adding full-blown arithmetics and interop for these these types (doing so seems to be opening a can of worms, while in my applications, I will mostly end up coercing or bitshifting between these types and "ordinary" Int64/UInt64 types anyway).

doesn't seem that far out-of-reach to me TBH (not that you have to / should worry about it in this PR).

I think the LLVM support should "just work" as long as we add the "cast storage integer type to / from register integer type" on the boundary with memory from 8a8a6ac, and I'd be happy to do an "odd-bit" follow-up to #61399 for this. The improved test coverage from that PR should be a help too.

@Keno

Keno commented Jul 4, 2026

Copy link
Copy Markdown
Member

Can we move this forward? What is missing?

fingolfin and others added 2 commits July 9, 2026 16:04
Port odd-width APInt conflict resolution to APInt.c.

Keep datatype unused_bits alongside master layout updates.

Co-authored-by: Codex <codex@openai.com>
Allow the local Int63 test constructor to accept signed integers through Int64 so default Int32 literals on 32-bit runners exercise the same truncation path.

Co-authored-by: Codex <codex@openai.com>
Comment thread src/abi_win32.cpp
if (!dt->layout->nfields && !dt->layout->npointers)
return NULL;
return Type::getIntNTy(ctx, jl_datatype_nbits(dt));
return Type::getIntNTy(ctx, jl_datatype_size(dt) * 8);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For ABIs we need byte store, so here we move away from jl_datatype_nbits

@fingolfin

Copy link
Copy Markdown
Member Author

I've just resolve the merge conflicts. Had to adapt to the APInt-C.cpp -> APInt.c migration.

I've asked Codex to summarize what it thinks of the state of this PR -- sorry, I don't mean to be rude by doing this, but I wasn't sure based on the previous comments what might be expected or not, so I thought I'd ask it ... here is what it wrote after I pointed it at the discussion here:

Locally I verified:

  • make -j4
  • JULIA_TEST_FAILFAST=1 ./julia --startup-file=no test/runtests.jl intrinsics apint
  • JULIA_TEST_FAILFAST=1 ./julia --startup-file=no test/runtests.jl intfuncs reinterpretarray core

The earlier Int63(::Int32) intrinsics failure is no longer reproducing on the current branch.

I don’t see inline review comments currently. The remaining question I’m
aware of is whether to include the broader #61361 storage/alignment
change here. My current view is that it should remain a follow-up:
this PR keeps existing byte-rounded storage behavior and focuses on
logical odd-bit primitive widths plus Core.bitsizeof.

Anyway: there was also a failure on 32bit systems that I hope is fixed now.

Of course I (with Codex/ChatGPT) can do more work on this, but right now, I am indeed not quite sure else is expected / necessary? I mean: of course more work is needed, but would it perhaps make sense to get this (or perhaps just parts?) in sooner rather than later to avoid further conflicts caused by code drift, and then we can do follow-up PRs, e.g. to change the storage behavior?

@Keno

Keno commented Jul 9, 2026

Copy link
Copy Markdown
Member

I'm happy with incremental progress, especially for new features, so once CI goes through, I'm happy to get it merged. I'll also take another review pass.

Mask the partial storage byte when zero-extending odd-bit APInt
values, and make reinterpret padding checks inspect isbits union
members so odd-width primitives cannot bypass the guard.

Add focused coverage for runtime odd-width zero extension and
reinterpret rejection through an isbits union field.

Co-authored-by: Codex <codex@openai.com>
@fingolfin

Copy link
Copy Markdown
Member Author

It would definitely be good if others checked this -- while I tried my best to discuss all changes with Codex, we may very well have missed something.

Comment thread base/essentials.jl
@topolarity topolarity self-requested a review July 9, 2026 21:59
fingolfin and others added 2 commits July 10, 2026 00:24
Resolve the bitstring conflict by preserving odd-bit
primitive extraction while adopting master wrapping
arithmetic.

Co-authored-by: Codex <codex@openai.com>
@fingolfin

Copy link
Copy Markdown
Member Author

Another merge conflict popped up, should be resolved now.

fingolfin and others added 2 commits July 10, 2026 13:15
Use declared primitive bit widths when modeling bitcast and integer conversion exceptions, so invalid casts remain observable and valid odd-width conversions are recognized.

Co-authored-by: Codex <codex@openai.com>
Share size transfer logic with Core.sizeof and register bitsizeof for constant folding, return inference, and builtin effect analysis.

Co-authored-by: Codex <codex@openai.com>
@fingolfin

Copy link
Copy Markdown
Member Author

Realized there are some more issues with this. But now need to attend some talks. Will update PR later tonight

@fingolfin fingolfin marked this pull request as draft July 10, 2026 11:36
Pad the leading partial byte to its logical hexadecimal width so low-valued 5-, 6-, and 7-bit primitives keep a stable representation.

Co-authored-by: Codex <codex@openai.com>
@fingolfin fingolfin marked this pull request as ready for review July 11, 2026 08:02
@fingolfin

Copy link
Copy Markdown
Member Author

OK pushed three more commits.

@fingolfin

Copy link
Copy Markdown
Member Author

One fixed a somewhat serious issue where intrinsic_exct in the compiler still compared primitive types based on their sizeof value, not bitsizeof. That could lead to the compiler eliding a check it shouldn't have.

Another commit improves support in the compiler for bitsizeof to match that for sizeof, so that e.g. bitsizeof can be const folded, correctly type inferred etc.

@fingolfin fingolfin changed the title core: support odd-bit primitive integers core: support odd-bit primitive integers, add Core.bitsizeof Jul 11, 2026
Make the expected values explicitly Int64 so identity
comparisons do not depend on the host-sized Int literal
type.

CI: https://buildkite.com/julialang/julia-pr/builds/333#019f5038-9b13-473b-9287-582d1b7113b4

Co-authored-by: Codex <codex@openai.com>
@fingolfin fingolfin force-pushed the codex/int63-primitive-support branch from 0682913 to 4d43c94 Compare July 12, 2026 08:41
@fingolfin

Copy link
Copy Markdown
Member Author

I've once again resolved merge conflicts.

The repeating build failure on x86_64-apple-darwin seems to be unrelated to this PR (see discussion on Slack)

@Keno

Keno commented Jul 15, 2026

Copy link
Copy Markdown
Member

Yeah, the Darwin builders have been having trouble, fine to ignore for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants