Skip to content

Commit 09400e4

Browse files
authored
Switch LLVM codegen of Ptr{T} to an actual pointer type. (#53687)
This PR switches our code generation for `Ptr{T}` from `i64` to an actual LLVM pointer type (`ptr` when using opaque pointers, an untyped `i8*` otherwise). The main motivation is to simplify `llvmcall` usage (doing away with the `inttoptr`/`ptrtoint` conversions), and also make it possible to simply use `ccall` to call intrinsics with `Ptr`-valued arguments (where we currently always need `llvmcall` for converting to an actual pointer). Changing codegen like this is a breaking change for `llvmcall` users, but I've added backwards compatibility and a deprecation warning. Before: ```llvm julia> @code_llvm pointer([]) define i64 @julia_pointer_1542(ptr noundef nonnull align 8 dereferenceable(24) %"x::Array") #0 { top: ; ┌ @ pointer.jl:65 within `cconvert` %0 = load ptr, ptr %"x::Array", align 8 ; └ ; ┌ @ pointer.jl:90 within `unsafe_convert` ; │┌ @ pointer.jl:30 within `convert` %bitcast_coercion = ptrtoint ptr %0 to i64 ret i64 %bitcast_coercion ; └└ } ``` After: ```llvm julia> @code_llvm pointer([]) define ptr @julia_pointer_3880(ptr noundef nonnull align 8 dereferenceable(24) %"x::Array") #0 { top: ; ┌ @ pointer.jl:65 within `cconvert` %0 = load ptr, ptr %"x::Array", align 8 ; └ ; ┌ @ pointer.jl:90 within `unsafe_convert` ; │┌ @ pointer.jl:30 within `convert` ret ptr %0 ; └└ } ``` This also simplifies "real code", e.g., when `ccall` converts an Array to a pointer, resulting in some more optimization opportunities.
1 parent 8e8b533 commit 09400e4

File tree

12 files changed

+253
-97
lines changed

12 files changed

+253
-97
lines changed

NEWS.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ Language changes
2626
Compiler/Runtime improvements
2727
-----------------------------
2828

29+
- Generated LLVM IR now uses actual pointer types instead of passing pointers as integers.
30+
This affects `llvmcall`: Inline LLVM IR should be updated to use `i8*` or `ptr` instead of
31+
`i32` or `i64`, and remove unneeded `ptrtoint`/`inttoptr` conversions. For compatibility,
32+
IR with integer pointers is still supported, but generates a deprecation warning. ([#53687])
33+
2934
Command-line option changes
3035
---------------------------
3136

base/atomics.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -364,13 +364,13 @@ for typ in atomictypes
364364
irt = "$ilt, $ilt*"
365365
@eval getindex(x::Atomic{$typ}) =
366366
GC.@preserve x llvmcall($"""
367-
%ptr = inttoptr i$WORD_SIZE %0 to $lt*
367+
%ptr = bitcast i8* %0 to $lt*
368368
%rv = load atomic $rt %ptr acquire, align $(gc_alignment(typ))
369369
ret $lt %rv
370370
""", $typ, Tuple{Ptr{$typ}}, unsafe_convert(Ptr{$typ}, x))
371371
@eval setindex!(x::Atomic{$typ}, v::$typ) =
372372
GC.@preserve x llvmcall($"""
373-
%ptr = inttoptr i$WORD_SIZE %0 to $lt*
373+
%ptr = bitcast i8* %0 to $lt*
374374
store atomic $lt %1, $lt* %ptr release, align $(gc_alignment(typ))
375375
ret void
376376
""", Cvoid, Tuple{Ptr{$typ}, $typ}, unsafe_convert(Ptr{$typ}, x), v)
@@ -379,7 +379,7 @@ for typ in atomictypes
379379
if typ <: Integer
380380
@eval atomic_cas!(x::Atomic{$typ}, cmp::$typ, new::$typ) =
381381
GC.@preserve x llvmcall($"""
382-
%ptr = inttoptr i$WORD_SIZE %0 to $lt*
382+
%ptr = bitcast i8* %0 to $lt*
383383
%rs = cmpxchg $lt* %ptr, $lt %1, $lt %2 acq_rel acquire
384384
%rv = extractvalue { $lt, i1 } %rs, 0
385385
ret $lt %rv
@@ -388,7 +388,7 @@ for typ in atomictypes
388388
else
389389
@eval atomic_cas!(x::Atomic{$typ}, cmp::$typ, new::$typ) =
390390
GC.@preserve x llvmcall($"""
391-
%iptr = inttoptr i$WORD_SIZE %0 to $ilt*
391+
%iptr = bitcast i8* %0 to $ilt*
392392
%icmp = bitcast $lt %1 to $ilt
393393
%inew = bitcast $lt %2 to $ilt
394394
%irs = cmpxchg $ilt* %iptr, $ilt %icmp, $ilt %inew acq_rel acquire
@@ -411,15 +411,15 @@ for typ in atomictypes
411411
if typ <: Integer
412412
@eval $fn(x::Atomic{$typ}, v::$typ) =
413413
GC.@preserve x llvmcall($"""
414-
%ptr = inttoptr i$WORD_SIZE %0 to $lt*
414+
%ptr = bitcast i8* %0 to $lt*
415415
%rv = atomicrmw $rmw $lt* %ptr, $lt %1 acq_rel
416416
ret $lt %rv
417417
""", $typ, Tuple{Ptr{$typ}, $typ}, unsafe_convert(Ptr{$typ}, x), v)
418418
else
419419
rmwop === :xchg || continue
420420
@eval $fn(x::Atomic{$typ}, v::$typ) =
421421
GC.@preserve x llvmcall($"""
422-
%iptr = inttoptr i$WORD_SIZE %0 to $ilt*
422+
%iptr = bitcast i8* %0 to $ilt*
423423
%ival = bitcast $lt %1 to $ilt
424424
%irv = atomicrmw $rmw $ilt* %iptr, $ilt %ival acq_rel
425425
%rv = bitcast $ilt %irv to $lt

base/compiler/tfuncs.jl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,6 @@ add_tfunc(sdiv_int, 2, 2, math_tfunc, 20)
184184
add_tfunc(udiv_int, 2, 2, math_tfunc, 20)
185185
add_tfunc(srem_int, 2, 2, math_tfunc, 20)
186186
add_tfunc(urem_int, 2, 2, math_tfunc, 20)
187-
add_tfunc(add_ptr, 2, 2, math_tfunc, 1)
188-
add_tfunc(sub_ptr, 2, 2, math_tfunc, 1)
189187
add_tfunc(neg_float, 1, 1, math_tfunc, 1)
190188
add_tfunc(add_float, 2, 2, math_tfunc, 2)
191189
add_tfunc(sub_float, 2, 2, math_tfunc, 2)
@@ -662,6 +660,9 @@ function pointer_eltype(@nospecialize(ptr))
662660
return Any
663661
end
664662

663+
@nospecs function pointerarith_tfunc(𝕃::AbstractLattice, ptr, offset)
664+
return ptr
665+
end
665666
@nospecs function pointerref_tfunc(𝕃::AbstractLattice, a, i, align)
666667
return pointer_eltype(a)
667668
end
@@ -705,6 +706,8 @@ end
705706
end
706707
return ccall(:jl_apply_cmpswap_type, Any, (Any,), T) where T
707708
end
709+
add_tfunc(add_ptr, 2, 2, pointerarith_tfunc, 1)
710+
add_tfunc(sub_ptr, 2, 2, pointerarith_tfunc, 1)
708711
add_tfunc(pointerref, 3, 3, pointerref_tfunc, 4)
709712
add_tfunc(pointerset, 4, 4, pointerset_tfunc, 5)
710713
add_tfunc(atomic_fence, 1, 1, atomic_fence_tfunc, 4)

base/pointer.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,8 @@ isless(x::Ptr{T}, y::Ptr{T}) where {T} = x < y
313313
<(x::Ptr, y::Ptr) = UInt(x) < UInt(y)
314314
-(x::Ptr, y::Ptr) = UInt(x) - UInt(y)
315315

316-
+(x::Ptr, y::Integer) = oftype(x, add_ptr(UInt(x), (y % UInt) % UInt))
317-
-(x::Ptr, y::Integer) = oftype(x, sub_ptr(UInt(x), (y % UInt) % UInt))
316+
+(x::Ptr, y::Integer) = add_ptr(x, (y % UInt) % UInt)
317+
-(x::Ptr, y::Integer) = sub_ptr(x, (y % UInt) % UInt)
318318
+(x::Integer, y::Ptr) = y + x
319319

320320
unsigned(x::Ptr) = UInt(x)

base/task.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,7 @@ const _state_index = findfirst(==(:_state), fieldnames(Task))
154154
@eval function load_state_acquire(t)
155155
# TODO: Replace this by proper atomic operations when available
156156
@GC.preserve t llvmcall($("""
157-
%ptr = inttoptr i$(Sys.WORD_SIZE) %0 to i8*
158-
%rv = load atomic i8, i8* %ptr acquire, align 8
157+
%rv = load atomic i8, i8* %0 acquire, align 8
159158
ret i8 %rv
160159
"""), UInt8, Tuple{Ptr{UInt8}},
161160
Ptr{UInt8}(pointer_from_objref(t) + fieldoffset(Task, _state_index)))

0 commit comments

Comments
 (0)