Skip to content

Commit 8daa329

Browse files
authored
Merge pull request #332 from maleadt/tb/reland
Reland ConstantArray changes
2 parents 80ddc5f + 08b55a8 commit 8daa329

File tree

9 files changed

+144
-27
lines changed

9 files changed

+144
-27
lines changed

Manifest.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ version = "1.4.1"
3434

3535
[[LLVMExtra_jll]]
3636
deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl", "TOML"]
37-
git-tree-sha1 = "070e4b5b65827f82c16ae0916376cb47377aa1b5"
37+
git-tree-sha1 = "e46e3a40daddcbe851f86db0ec4a4a3d4badf800"
3838
uuid = "dad2f222-ce93-54a1-a47d-0025e8a3acab"
39-
version = "0.0.18+0"
39+
version = "0.0.19+0"
4040

4141
[[LazyArtifacts]]
4242
deps = ["Artifacts", "Pkg"]

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "LLVM"
22
uuid = "929cbde3-209d-540e-8aea-75f648917ca0"
3-
version = "4.17.1"
3+
version = "5.0.0"
44

55
[deps]
66
CEnum = "fa961155-64e5-5f13-b03f-caf6b980ea82"
@@ -11,5 +11,5 @@ Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
1111

1212
[compat]
1313
CEnum = "0.2, 0.3, 0.4"
14-
LLVMExtra_jll = "=0.0.18"
14+
LLVMExtra_jll = "=0.0.19"
1515
julia = "1.6"

deps/LLVMExtra/include/LLVMExtra.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,5 +162,8 @@ void LLVMReplaceMDNodeOperandWith(LLVMMetadataRef MD, unsigned I, LLVMMetadataRe
162162
LLVMBool LLVMContextSupportsTypedPointers(LLVMContextRef C);
163163
#endif
164164

165+
// constant data
166+
LLVMValueRef LLVMConstDataArray(LLVMTypeRef ElementTy, const void *Data, unsigned NumElements);
167+
165168
LLVM_C_EXTERN_C_END
166169
#endif

deps/LLVMExtra/lib/llvm-api.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,3 +556,8 @@ LLVMBool LLVMContextSupportsTypedPointers(LLVMContextRef C) {
556556
return unwrap(C)->supportsTypedPointers();
557557
}
558558
#endif
559+
560+
LLVMValueRef LLVMConstDataArray(LLVMTypeRef ElementTy, const void *Data, unsigned NumElements) {
561+
StringRef S((const char *)Data, NumElements * unwrap(ElementTy)->getPrimitiveSizeInBits() / 8);
562+
return wrap(ConstantDataArray::getRaw(S, NumElements, unwrap(ElementTy)));
563+
}

lib/libLLVM_extra.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,3 +416,7 @@ function LLVMContextSupportsTypedPointers(Ctx)
416416
ccall((:LLVMContextSupportsTypedPointers, libLLVMExtra), LLVMBool, (LLVMContextRef,), Ctx)
417417
end
418418
end
419+
420+
function LLVMConstDataArray(ElementTy, Data, NumElements)
421+
ccall((:LLVMConstDataArray, libLLVMExtra), LLVMValueRef, (LLVMTypeRef, Ptr{Cvoid}, Cuint), ElementTy, Data, NumElements)
422+
end

src/core/module.jl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,3 +267,30 @@ function Base.setindex!(iter::ModuleFlagDict, val::Metadata,
267267
(name, behavior)::Tuple{String, API.LLVMModuleFlagBehavior})
268268
API.LLVMAddModuleFlag(iter.mod, behavior, name, length(name), val)
269269
end
270+
271+
272+
## sdk version
273+
274+
export sdk_version, sdk_version!
275+
276+
function sdk_version!(mod::Module, version::VersionNumber)
277+
entries = Int32[version.major]
278+
if version.minor != 0 || version.patch != 0
279+
push!(entries, version.minor)
280+
if version.patch != 0
281+
push!(entries, version.patch)
282+
end
283+
# cannot represent prerelease or build metadata
284+
end
285+
md = Metadata(ConstantDataArray(entries; ctx=context(mod)))
286+
287+
flags(mod)["SDK Version", LLVM.API.LLVMModuleFlagBehaviorWarning] = md
288+
end
289+
290+
function sdk_version(mod::Module)
291+
haskey(flags(mod), "SDK Version") || return nothing
292+
md = flags(mod)["SDK Version"]
293+
c = Value(md; ctx=context(mod))
294+
entries = collect(c)
295+
VersionNumber(map(val->convert(Int, val), entries)...)
296+
end

src/core/type.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ function ArrayType(eltyp::LLVMType, count)
163163
return ArrayType(API.LLVMArrayType(eltyp, count))
164164
end
165165

166-
Base.length(arrtyp::ArrayType) = API.LLVMGetArrayLength(arrtyp)
166+
Base.length(arrtyp::ArrayType) = Int(API.LLVMGetArrayLength(arrtyp))
167167

168168
Base.isempty(@nospecialize(T::ArrayType)) = length(T) == 0 || isempty(eltype(T))
169169

src/core/value/constant.jl

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -112,17 +112,67 @@ Base.convert(::Type{T}, val::ConstantFP) where {T<:AbstractFloat} =
112112
convert(T, API.LLVMConstRealGetDouble(val, Ref{API.LLVMBool}()))
113113

114114

115-
# sequential
115+
# sequential data
116116

117117
export ConstantDataSequential, ConstantDataArray, ConstantDataVector
118118

119119
abstract type ConstantDataSequential <: Constant end
120120

121+
# ConstantData can only contain primitive types (1/2/4/8 byte integers, float/half),
122+
# as opposed to ConstantAggregate which can contain arbitrary LLVM values.
123+
#
124+
# however, LLVM seems to use both array types interchangeably, e.g., constructing
125+
# a ConstArray through LLVMConstArray may return a ConstantDataArray (presumably as an
126+
# optimization, when the data can be represented as densely packed primitive values).
127+
# because of that, ConstantDataArray and ConstantArray need to behave the same way,
128+
# concretely, indexing a ConstantDataArray has to return LLVM constant values...
129+
#
130+
# XXX: maybe we should just not expose ConstantDataArray then?
131+
# one advantage of keeping them separate is that creating a ConstantDataArray
132+
# is much cheaper (we should also be able to iterate much more efficiently,
133+
# but cannot support that as explained above).
134+
135+
# array interface
136+
Base.eltype(cda::ConstantDataSequential) = llvmeltype(cda)
137+
Base.length(cda::ConstantDataSequential) = length(llvmtype(cda))
138+
Base.size(cda::ConstantDataSequential) = (length(cda),)
139+
function Base.getindex(cda::ConstantDataSequential, idx::Integer)
140+
@boundscheck 1 <= idx <= length(cda) || throw(BoundsError(cda, idx))
141+
Value(API.LLVMGetElementAsConstant(cda, idx-1))
142+
end
143+
function Base.collect(cda::ConstantDataSequential)
144+
constants = Array{Value}(undef, length(cda))
145+
for i in 1:length(cda)
146+
@inbounds constants[i] = cda[i]
147+
end
148+
return constants
149+
end
150+
121151
@checked struct ConstantDataArray <: ConstantDataSequential
122152
ref::API.LLVMValueRef
123153
end
124154
register(ConstantDataArray, API.LLVMConstantDataArrayValueKind)
125155

156+
function ConstantDataArray(typ::LLVMType, data::Array{T}) where {T <: Union{Integer, AbstractFloat}}
157+
# TODO: can we look up the primitive size of the LLVM type?
158+
# use that to assert it matches the Julia element type.
159+
return ConstantDataArray(API.LLVMConstDataArray(typ, data, length(data)))
160+
end
161+
162+
# shorthands with arrays of plain Julia data
163+
# FIXME: duplicates the ConstantInt/ConstantFP conversion rules
164+
# XXX: X[X(...)] instead of X.(...) because of empty-container inference
165+
ConstantDataArray(data::AbstractVector{T}; ctx::Context) where {T<:Integer} =
166+
ConstantDataArray(IntType(sizeof(T)*8; ctx), data)
167+
ConstantDataArray(data::AbstractVector{Core.Bool}; ctx::Context) =
168+
ConstantDataArray(Int1Type(ctx), data)
169+
ConstantDataArray(data::AbstractVector{Float16}; ctx::Context) =
170+
ConstantDataArray(HalfType(ctx), data)
171+
ConstantDataArray(data::AbstractVector{Float32}; ctx::Context) =
172+
ConstantDataArray(FloatType(ctx), data)
173+
ConstantDataArray(data::AbstractVector{Float64}; ctx::Context) =
174+
ConstantDataArray(DoubleType(ctx), data)
175+
126176
@checked struct ConstantDataVector <: ConstantDataSequential
127177
ref::API.LLVMValueRef
128178
end
@@ -162,16 +212,14 @@ export ConstantArray
162212
ref::API.LLVMValueRef
163213
end
164214
register(ConstantArray, API.LLVMConstantArrayValueKind)
165-
register(ConstantArray, API.LLVMConstantDataArrayValueKind)
166-
167-
ConstantArrayOrAggregateZero(value) = Value(value)::Union{ConstantArray,ConstantAggregateZero}
168215

169216
# generic constructor taking an array of constants
170217
function ConstantArray(typ::LLVMType, data::AbstractArray{T,N}=T[]) where {T<:Constant,N}
171218
@assert all(x->x==typ, llvmtype.(data))
172219

173220
if N == 1
174-
return ConstantArrayOrAggregateZero(API.LLVMConstArray(typ, Array(data), length(data)))
221+
# XXX: this can return a ConstDataArray (presumably as an optimization?)
222+
return Value(API.LLVMConstArray(typ, Array(data), length(data)))
175223
end
176224

177225
ca_vec = map(x->ConstantArray(typ, x), eachslice(data, dims=1))
@@ -183,15 +231,15 @@ end
183231
# shorthands with arrays of plain Julia data
184232
# FIXME: duplicates the ConstantInt/ConstantFP conversion rules
185233
# XXX: X[X(...)] instead of X.(...) because of empty-container inference
186-
ConstantArray(data::AbstractArray{T,N}; ctx::Context) where {T<:Integer,N} =
234+
ConstantArray(data::AbstractArray{T}; ctx::Context) where {T<:Integer} =
187235
ConstantArray(IntType(sizeof(T)*8; ctx), ConstantInt[ConstantInt(x; ctx) for x in data])
188-
ConstantArray(data::AbstractArray{Core.Bool,N}; ctx::Context) where {N} =
236+
ConstantArray(data::AbstractArray{Core.Bool}; ctx::Context) =
189237
ConstantArray(Int1Type(ctx), ConstantInt[ConstantInt(x; ctx) for x in data])
190-
ConstantArray(data::AbstractArray{Float16,N}; ctx::Context) where {N} =
238+
ConstantArray(data::AbstractArray{Float16}; ctx::Context) =
191239
ConstantArray(HalfType(ctx), ConstantFP[ConstantFP(x; ctx) for x in data])
192-
ConstantArray(data::AbstractArray{Float32,N}; ctx::Context) where {N} =
240+
ConstantArray(data::AbstractArray{Float32}; ctx::Context) =
193241
ConstantArray(FloatType(ctx), ConstantFP[ConstantFP(x; ctx) for x in data])
194-
ConstantArray(data::AbstractArray{Float64,N}; ctx::Context) where {N} =
242+
ConstantArray(data::AbstractArray{Float64}; ctx::Context) =
195243
ConstantArray(DoubleType(ctx), ConstantFP[ConstantFP(x; ctx) for x in data])
196244

197245
# convert back to known array types
@@ -226,7 +274,9 @@ function Base.getindex(ca::ConstantArray, idx::Integer...)
226274
I = CartesianIndices(size(ca))[idx...]
227275
for i in Tuple(I)
228276
if isempty(operands(ca))
229-
ca = LLVM.Value(API.LLVMGetElementAsConstant(ca, i-1))
277+
# XXX: is this valid? LLVMGetElementAsConstant is meant to be used with
278+
# Constant*Data*Arrays, not ConstantArrays
279+
ca = Value(API.LLVMGetElementAsConstant(ca, i-1))
230280
else
231281
ca = (Base.@_propagate_inbounds_meta; operands(ca)[i])
232282
end

test/core.jl

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -419,29 +419,23 @@ end
419419
end
420420

421421

422-
@testset "array constants" begin
422+
@testset "array aggregate constants" begin
423423

424424
# from Julia values
425425
let
426-
vec = Int32[1,2,3,4]
426+
vec = Int128[1,2,3,4]
427427
ca = ConstantArray(vec; ctx)
428+
@test ca isa ConstantArray
428429
@test size(vec) == size(ca)
429430
@test length(vec) == length(ca)
430431
@test ca[1] == ConstantInt(vec[1]; ctx)
431432
@test collect(ca) == ConstantInt.(vec; ctx)
432433
end
433-
let
434-
vec = Float32[1.1f0,2.2f0,3.3f0,4.4f0]
435-
ca = ConstantArray(vec; ctx)
436-
@test size(vec) == size(ca)
437-
@test length(vec) == length(ca)
438-
@test ca[1] == ConstantFP(vec[1]; ctx)
439-
@test collect(ca) == ConstantFP.(vec; ctx)
440-
end
441434
let
442435
# tests for ConstantAggregateZero, constructed indirectly.
443436
# should behave similarly to ConstantArray since it can get returned there.
444437
ca = ConstantArray(Int[]; ctx)
438+
@test ca isa ConstantAggregateZero
445439
@test size(ca) == (0,)
446440
@test length(ca) == 0
447441
@test isempty(collect(ca))
@@ -458,7 +452,7 @@ end
458452

459453
end
460454

461-
@testset "struct constants" begin
455+
@testset "struct aggregate constants" begin
462456

463457
# from Julia values
464458
let
@@ -513,6 +507,36 @@ end
513507
end
514508

515509
end
510+
511+
512+
@testset "array data constants" begin
513+
514+
let
515+
vec = Int32[1,2,3,4]
516+
eltyp = LLVM.Int32Type(ctx)
517+
cda = ConstantDataArray(eltyp, vec)
518+
@test cda isa ConstantDataArray
519+
@test llvmtype(cda) == LLVM.ArrayType(eltyp, 4)
520+
@test collect(cda) == ConstantInt.(vec; ctx)
521+
end
522+
523+
# from Julia values
524+
for T in [Int8, Int16, Int32, Int64]
525+
vec = T[1,2,3,4]
526+
cda = ConstantDataArray(vec; ctx)
527+
@test cda isa ConstantDataArray
528+
@test size(vec) == size(cda)
529+
@test collect(cda) == ConstantInt.(vec; ctx)
530+
end
531+
for T in [Float32, Float64]
532+
vec = T[1,2,3,4]
533+
cda = ConstantDataArray(vec; ctx)
534+
@test cda isa ConstantDataArray
535+
@test size(vec) == size(cda)
536+
@test collect(cda) == ConstantFP.(vec; ctx)
537+
end
538+
539+
end
516540
end
517541

518542
# constant expressions
@@ -991,6 +1015,10 @@ end
9911015

9921016
@test mod_flags["foobar"] == md
9931017
@test_throws KeyError mod_flags["foobaz"]
1018+
1019+
@test sdk_version(mod) === nothing
1020+
sdk_version!(mod, v"1.2.3")
1021+
@test sdk_version(mod) == v"1.2.3"
9941022
end
9951023

9961024
# metadata iteration

0 commit comments

Comments
 (0)